Reputation: 34204
I am trying to find the best solution to make my Java application configurable over the command line. The issue I am facing is that I need to configure complex nested structures.
Consider the following structure (words starting with a capital are classes, indenting notates attributes)
The first thing I need to select from the command line is a class that implements InterfaceOptimizer
(e.g. java App -O SomeOptimizer
). The next thing to select would be the AbstractProblem
which by itself takes another parameter dimension
(e.g. java App -O SomeOptimizer -- -P ConcreteProblem
.
The issue here is that some parameters are parameters for a specific class and depend on what parameter was first given. ConcreteProblem might take different parameters than OtherProblem.
I tested args4j and commons-cli, but those both fail when trying to do what I need.
WEKA (a popular machine learning tool) seems to have implemented a solution for this problem, but it basically requires each class to implement it's own CLI parser (and they seem to have issues with consistency).
Is there any good solution (existing library?) to this problem? What would be the recommended pattern be to solve this?
Upvotes: 1
Views: 194
Reputation: 36329
I don't see how this CLI is very complex, unless I didn't understand fully. You want
java X classname problem dimension population numberruns
Now, even if the part
classname problem dimension
or just
problem dimension
can be repeated, it is quite easy:
classname problem dimension
can be repeated).Code (to be refined):
try {
IOptimizer io = (IOptimizer) Class.forName(args[n]).newInstance();
io.init(args[n+1], args[n+2]);
}
catch (ClassNotFoundException ...) { ... }
catch (ClassCastException ...) { ... }
catch (InvalidArgumentException ...) { ... }
Note that if some Problem needs more than one paramter, you can implment like so:
java X classname problem3 a,b,c population numbers
and then you can split the dimension parameter in the init() method.
Upvotes: 0
Reputation: 7321
Just an idea, but this looks a lot like deserializing an object graph to me. Java has built-in serialization/deserialization of object. E.g. to construct an object from an XML file:
FileInputStream is = new FileInputStream(new File("config.xml"));
XMLDecoder d = new XMLDecoder(is);
InterfaceOptimizer obj = (InterfaceOptimizer)d.readObject();
To get an initial config file (as a starting point that you could manually alter), you could create the object programmatically, then dump it to an XML file using this:
FileOutputStream os = new FileOutputStream(new File("config.xml"));
XMLEncoder e = new XMLEncoder(os);
e.writeObject(myOptimizerObject);
You would then have to pass only the config file on the command line.
Upvotes: 0
Reputation: 12883
I think you're probably going to have to just write the code that selects the right classes. After that, you can use reflection to put the values into the objects and/or validate that the command line options are appropriate. Annotations would help you out tremendously here, because you could use that to help drive the reflection engine, as well as for generating documentation e.g. command line help.
Upvotes: 1