Currently I am creating a java Project that will be used by many people to (in theory) create a product, each with their own set of configurations, in a straightforward, fast and with standardized mechanisms.
If I were using a GUI, it would be easier to handle the configurations in different files, however, because I am making it just an editable project, I see myself in the need of putting all the constants in a single class/file so as to centralize the area where the respective engineer configures the product he is creating. Thus I have the following Constants interface:
public interface Constants {
//ROUTE OF FOLDERS
String PATH_ACTUALIZ = "..\\actualiz\\";
String PATH_ENTRADAS = "..\\entries\\";
String PATH_SALIDAS = "..\\outputs\\";
String PATH_ENTRADAS_CARTAS = PATH_ENTRADAS + "CARTAS\\";
String PATH_ENTRADAS_ANEXOS = PATH_ENTRADAS + "ANEXOS\\";
String PATH_SALIDAS_PDF = PATH_SALIDAS + "PDF\\";
//ROUTE OF FILES
String PATH_FILE_SPOOL_CLIENTE = PATH_ENTRADAS + "spool.txt";
String PATH_FILE_SPOOL_ERRORES = PATH_SALIDAS + "Reporte_de_Errores.txt";
String PATH_FILE_BASE_EMAIL = PATH_SALIDAS + "BaseEmail_[OP].txt";
String PATH_FILE_DATA_VAR = PATH_SALIDAS + "DataVar_[OP].txt";
String PATH_FILE_BASE = PATH_SALIDAS + "Base.obj";
String NAME_FILE_LOG = "Log.txt";
//DESIGNER
String DESIGNER_DELIMITER = "\t"; //Other options "ยป", "|"
String DESIGNER_CANAL = "AA01";
//GUI INFORMATION
String NAME_RESPONSABLE = "JOHN DOE";
String TITULO_MENSAJE_ERROR = "Error when processing the data.";
String TITULO_MENSAJE_INFORMACION = "Processing data";
//HTML
String HTML = "123";
//SEGMENTS
HashMap<String, String> HMSEGMENTO = new HashMap<String, String>(); //Initialization missing.
}
The last line of which is a HashMap because the data involves several pairs of String to String, including one that is returned by default if the key provided isn't found, however I find myself at a standstill because there is no elegant/simple way add data to a Hashmap inside an Interface.
Other solutions I've looked into include the use of Java Properties, but I also wouldn't be able to add data to it in this interface.
So my larger question becomes if I'm even doing this right at all. Any sources or ideas on software development that would direct to the right path would be greatly appreciated.
Finally I understand my question is slightly broad. If there is a way to make it more specific, I would appreciate the help too.
Serious non-answer: don't do this.
Java invented Properties to exactly give you that: the ability to specify runtime configuration information in text files. And when you need multiple layers - that is also possible using property files (you could for example have a base property file that defines useful defaults, and then different people can provide their own property files that "override" those properties that they need to be changed).
And when you insist on using interfaces to "wrap" your constants (although exactly that is considered a bad practice) - please don't stuff everything into the same interface. Instead identify the different "categories" you need and have one file per category.
Your approach is determined to end up with monolithic spaghetti code.
Related
I want to use a single YAML file which contains several different objects - for different applications. I need to fetch one object to get an instance of MyClass1, ignoring the rest of docs for MyClass2, MyClass3, etc. Some sort of selective de-serializing: now this class, then that one... The structure of MyClass2, MyClass3 is totally unknown to the application working with MyClass1. The file is always a valid YAML, of course.
The YAML may be of any structure we need to implement such a multi-class container. The preferred parsing tool is snakeyaml.
Is it sensible? How can I ignore all but one object?
UPD: replaced all "document" with "object". I think we have to speak about the single YAML document containing several objects of different structure. More of it, the parser knows exactly only 1 structure and wants to ignore the rest.
UDP2: I think it is impossible with snakeyaml. We have to read all objects anyway - and select the needed one later. But maybe I'm wrong.
UPD2: sample config file
---
-
exportConfiguration781:
attachmentFieldName: "name"
baseSftpInboxPath: /home/user/somedir/
somebool: false
days: 9999
expected:
- ABC w/o quotes
- "Cat ABC"
- "Some string"
dateFormat: yyyy-MMdd-HHmm
user: someuser
-
anotherConfiguration:
k1: v1
k2:
- v21
- v22
This is definitely possible with SnakeYAML, albeit not trivial. Here's a general rundown what you need to do:
First, let's have a look what loading with SnakeYAML does. Here's the important part of the YAML class:
private Object loadFromReader(StreamReader sreader, Class<?> type) {
Composer composer = new Composer(new ParserImpl(sreader), resolver, loadingConfig);
constructor.setComposer(composer);
return constructor.getSingleData(type);
}
The composer parses YAML input into Nodes. To do that, it doesn't need any knowledge about the structure of your classes, since every node is either a ScalarNode, a SequenceNode or a MappingNode and they just represent the YAML structure.
The constructor takes a root node generated by the composer and generates native POJOs from it. So what you want to do is to throw away parts of the node graph before they reach the constructor.
The easiest way to do that is probably to derive from Composer and override two methods like this:
public class MyComposer extends Composer {
private final int objIndex;
public MyComposer(Parser parser, Resolver resolver, int objIndex) {
super(parser, resolver);
this.objIndex = objIndex;
}
public MyComposer(Parser parser, Resolver resolver, LoaderOptions loadingConfig, int objIndex) {
super(parser, resolver, loadingConfig);
this.objIndex = objIndex;
}
#Override
public Node getNode() {
return strip(super.getNode());
}
private Node strip(Node input) {
return ((SequenceNode)input).getValue().get(objIndex);
}
}
The strip implementation is just an example. In this case, I assumed your YAML looks like this (object content is arbitrary):
- {first: obj}
- {second: obj}
- {third: obj}
And you simply select the object you actually want to deserialize by its index in the sequence. But you can also have something more complex like a searching algorithm.
Now that you have your own composer, you can do
Constructor constructor = new Constructor();
// assuming we want to get the object at index 1 (i.e. second object)
Composer composer = new MyComposer(new ParserImpl(sreader), new Resolver(), 1);
constructor.setComposer(composer);
MyObject result = (MyObject)constructor.getSingleData(MyObject.class);
The answer of #flyx was very helpful for me, opening the way to workaround the library (in our case - snakeyaml) limitations by overriding some methods. Thanks a lot! It's quite possible there is a final solution in it - but not now. Besides, the simple solution below is robust and should be considered even if we'd found the complete library-intruding solution.
I've decided to solve the task by double distilling, sorry, processing the configuration file. Imagine the latter consisting of several parts and every part is marked by the unique token-delimiter. For the sake of keeping the YAML-likenes, it may be
---
#this is a unique key for the configuration A
<some YAML document>
---
#this is another key for the configuration B
<some YAML document
The first pass is pre-processing. For the given String fileString and String key (and DELIMITER = "\n---\n". for example) we select a substring with the key-defined configuration:
int begIndex;
do {
begIndex= fileString.indexOf(DELIMITER);
if (begIndex == -1) {
break;
}
if (fileString.startsWith(DELIMITER + key, begIndex)) {
fileString = fileString.substring(begIndex + DELIMITER.length() + key.length());
break;
}
// spoil alien delimiter and repeat search
fileString = fileString.replaceFirst(DELIMITER, " ");
} while (true);
int endIndex = fileString.indexOf(DELIMITER);
if (endIndex != -1) {
fileString = fileString.substring(0, endIndex);
}
Now we feed the fileString to the simple YAML parsing
ExportConfiguration configuration = new Yaml(new Constructor(ExportConfiguration.class))
.loadAs(fileString, ExportConfiguration.class);
This time we have a single document that must co-respond to the ExportConfiguration class.
Note 1: The structure and even the very content of the rest of configuration file plays absolutely no role. This was the main idea, to get independent configurations in a single file
Note 2: the rest of configurations may be JSON or XML or whatever. We have a method-preprocessor that returns a String configuration - and the next processor parses it properly.
I have a model which is in XML format as shown below and I need to parse the XML and check whether my XML has internal-flag flag set as true or not. In my other models, it might be possible, that internal-flag flag is set as false. And sometimes, it is also possible that this field won't be there so by default it will be false from my code.
<?xml version="1.0"?>
<ClientMetadata
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.google.com client.xsd"
xmlns="http://www.google.com">
<client id="200" version="13">
<name>hello world</name>
<description>hello hello</description>
<organization>TESTER</organization>
<author>david</author>
<internal-flag>true</internal-flag>
<clock>
<clock>
<for>
<init>val(tmp1) = 1</init>
<clock>
<eval><![CDATA[result("," + $convert(val(tmp1)))]]></eval>
</clock>
</for>
<for>
<incr>val(tmp1) -= 1</incr>
<clock>
<eval><![CDATA[result("," + $convert(val(tmp1)))]]></eval>
</clock>
</for>
</clock>
</clock>
</client>
</ClientMetadata>
I have a POJO in which I am storing my above model -
public class ModelMetadata {
private int modelId;
private String modelValue; // this string will have my above XML data as string
// setters and getters here
}
Now what is the best way to determine whether my model has internal-flag set as true or not?
// this list will have all my Models stored
List<ModelMetadata> metadata = getModelMetadata();
for (ModelMetadata model : metadata) {
// my model will be stored in below variable in XML format
String modelValue = model.getModelValue();
// now parse modelValue variable and extract `internal-flag` field property
}
Do I need to use XML parsing for this or is there any better way to do this?
Update:-
I have started using Stax and this is what I have tried so far but not sure how can I extract that field -
InputStream is = new ByteArrayInputStream(modelValue.getBytes());
XMLStreamReader r = XMLInputFactory.newInstance().createXMLStreamReader(is);
while(r.hasNext()) {
// now what should I do here?
}
There is an easy solution using XMLBeam (Disclosure: I'm affiliated with that project), just a few lines:
public class ReadBoolean {
public interface ClientMetaData {
#XBRead("//xbdefaultns:internal-flag")
boolean hasFlag();
}
public static void main(String[] args) throws IOException {
ClientMetaData clientMetaData = new XBProjector().io().url("res://xmlWithBoolean.xml").read(ClientMetaData.class);
System.out.println("Has flag:"+clientMetaData.hasFlag());
}
}
This program prints out
Has flag:true
for your XML.
You could also do some simple string parsing, but this will only work for small cases with proper XML and if there's only a single <internal-flag> element.
This is a simple solution to your problem without using any XML parsing utilities. Other solutions may be more robust or powerful.
Find the index of the string literal <internal-flag>. If it doesn't exist, return false.
Go forward "<internal-flag>".length (15) characters. Read up to the next </internal-flag>, which should be the string true or false.
Take that string, use Boolean.parseBoolean(String) to get a boolean value.
If you want me to help you out with the code just drop a comment!
If you are willing to consider adding Groovy to your mix (e.g. see the book Making Java Groovy) then using a Groovy XMLParser and associated classes will make this simple.
If you need to stick to Java, let me put in a shameless plug for my Xen library, which mimics a lot of the "Groovy way". The answer to your question would be:
Xen doc = new XenParser().parseText(YOUR_XML_STRING);
String internalFlag = doc.getText(".client.internal-flag");
boolean isSet = "true".equals(internalFlag);
If the XML comes from a File, Stream, or URI, that can be handled too.
Caveat emptor, (even though it is free) this is a fairly new library, written solely by a random person (me), and not thoroughly tested on all the crazy XML out there. If anybody knows of a similar, more "mainstream" library I'd be very interested in hearing about it.
I want to retrieve all data properties set for an individual of any class using owl api. The code i have used is
OWLNamedIndividual inputNoun = df.getOWLNamedIndividual(IRI.create(prefix + "Cow"));
for (OWLDataProperty prop: inputNoun.getDataPropertiesInSignature())
{
System.out.println("the properties for Cow are " + prop); //line 1
}
This code compiles with success but line 1 print nothing at all. What should be the correct syntax. Have thoroughly googled and couldnt find any thing worth it.
OWLNamedIndividual::getDataPropertiesInSignature() does not return the properties for which the individual has a filler, it returns the properties that appear in the object itself. For an individual this is usually empty. The method is on the OWLObject interface, which covers things like class and property expressions and ontologies, for which it has a more useful output.
If you want the data properties with an actual filler for an individual, use OWLOntology::getDataPropertyAssertionAxioms(OWLIndividual), like this:
OWLNamedIndividual input = ...
Set<OWLDataPropertyAssertionAxiom> properties=ontology.getDataPropertyAssertionAxioms(input);
for (OWLDataPropertyAssertionAxiom ax: properties) {
System.out.println(ax.getProperty());
}
This link: http://www.otc.edu/GEN/schedule/all_classes_fall.txt contains classes for my college, and I am trying to take all of this data and store it in a ClassInformationFall object I have created. Basically, the classes begin at the class title in the format like this : "ABR-100-101" and have class instructor, days it occurs, start/end time, etc.
I have written some regex to pick out the class title, and some of the easier things like start and ending time, but I have been struggling on trying to get the rest of it out. I was thinking about setting up some code where anytime another class title is encountered, it adds the following text to a new ClassInformationFall object, which I am storing in a list of that type. Even if I had that, though, I still haven't been able to successfully extract all of the data for all of the things that make up the class.
What would be the regex to pick this information out, or is regex even the way to go?
Thanks for any help, this has stumped me for awhile.
PS - I am developing the application using this in Java.
If the fields are always in the same order, you can just split each line by tabs and deal with the resulting array.
String line = bufferedReader.readLine();
while (line != null) {
String[] data = line.split("\\t+");
String name = data[0];
String credits = data[2];
String description = data[3];
String professor = data[11];
ClassInfo ci = new ClassInfo(name, credits, description, professor);
classInfoList.add(ci);
line = bufferedReader.readLine();
}
New to Java, and can't figure out what I hope to be a simple thing.
I keep "sections" in an array:
//Section.java
public static final String[] TOP = {
"Top News",
"http://www.mysite.com/RSS/myfeed.csp",
"top"
};
I'd like to do something like this:
Article a1 = new Article();
a1.["s_" + section[2]] = 1; //should resolve to a1.s_top = 1;
But it won't let me, as it doesn't know what "section" is. (I'm sure seasoned Java people will cringe at this attempt... but my searches have come up empty on how to do this)
Clarification:
My article mysqlite table has fields for the "section" of the article:
s_top
s_sports
...etc
When doing my import from an XML file, I'd like to set that field to a 1 if it's in that category. I could have switch statement:
//whatever the Java version of this is
switch(section[2]) {
case "top": a1.s_top = 1; break;
case "sports": a1.s_sports = 1; break;
//...
}
But I thought it'd be a lot easier to just write it as a single line:
a1["s_"+section[2]] = 1;
In Java, it's a pain to do what you want to do in the way that you're trying to do it.
If you don't want to use the switch/case statement, you could use reflection to pull up the member attribute you're trying to set:
Class articleClass = a1.getClass();
Field field = articleClass.getField("s_top");
field.set(a1, 1);
It'll work, but it may be slow and it's an atypical approach to this problem.
Alternately, you could store either a Map<String> or a Map<String,Boolean> inside of your Article class, and have a public function within Article called putSection(String section), and as you iterate, you would put the various section strings (or string/value mappings) into the map for each Article. So, instead of statically defining which sections may exist and giving each Article a yes or no, you'd allow the list of possible sections to be dynamic and based on your xml import.
Java variables are not "dynamic", unlink actionscript for exemple. You cannot call or assign a variable without knowing it at compile time (well, with reflection you could but it's far to complex)
So yes, the solution is to have a switch case (only possible on strings with java 1.7), or using an hashmap or equivalent
Or, if it's about importing XML, maybe you should take a look on JAXB
If you are trying to get an attribute from an object, you need to make sure that you have "getters" and "setters" in your object. You also have to make sure you define Section in your article class.
Something like:
class Article{
String section;
//constructor
public Article(){
};
//set section
public void setSection(Section section){
this.section = section;
}
//get section
public String getSection(){
return this.section;
}