halfdan
halfdan

Reputation: 34204

Complex Java Command Line Parameterization

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.

Example

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.

Tested Libraries

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

Answers (3)

Ingo
Ingo

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:

  • First, take the population and numberofruns from the end and check for validity.
  • Check if the remaining arguments are a multiple of 3 (assuming classname problem dimension can be repeated).
  • For each 3 tuple of arguments, resolve and load the class, check if it accepts the given problem, and check the dimension argument. A simple way to do this would be to just call the constructor or some initialization code of that class, like so:

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

geert3
geert3

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

BillRobertson42
BillRobertson42

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

Related Questions