CLI Breaks down command line processing into three distinct phases, the first of which is to create a model of the command line you wish to process. The second phase is arguably the most important as it involves processing the command line arguments of the application according to the model created. Finally the parsed command line is available to be queried by the application proper. The phases are discussed in more detail below.
In CLI2 a command line is modelled as a Group composed of many Options. There are a number different Option implementations available to be used including DefaultOption, Switch and Command which may all have an Argument and/or a Group of child options associated with them. An example of where this parental relationship could be used is where you need to allow for the following scenario where one option only makes sense within the context of another:
myapp --output path/to/file --xml
Typically this command line would be modelled as a DefaultOption
(--output
) with an Argument (to capture
path/to/file
) and a Group of children consisting of a
DefaultOption (--xml
) since the format only applies if the
output is specified
The various Option implementations provided need careful configuration and constructors take a complex set of arguments. To ease the construction of these options *Builder classes (e.g. DefaultOptionBuilder, GroupBuilder and ArgumentBuilder) have been supplied following the Builder Pattern which essentially involves using the DefaultOptionBuilder class to create instances of DefaultOption using descriptive method calls instead of anonymous arguments to a constructor. The following example demonstrates how the command line shown above could be modelled in code:
DefaultOptionBuilder oBuilder = new DefaultOptionBuilder(); ArgumentBuilder aBuilder = new ArgumentBuilder(); GroupBuilder gBuilder = new GroupBuilder(); DefaultOption xmlOption = oBuilder .withLongName("xml") .withDescription("Output using xml format") .create(); Argument pathArgument = aBuilder .withName("path") .withMinimum(1) .withMaximum(1) .create(); Group outputChildren = gBuilder .withOption(xmlOption) .create(); Option outputOption = oBuilder .withLongName("output") .withDescription("Outputs to a file") .withArgument(pathArgument) .withChildren(outputChildren) .create();
The Options section of the manual discuss these features in greater detail.
Once all the options have been composed into a Group modelling the complete option model then we are ready to parse a command line.
The Parser class can be used to parse an array of arguments against the
option model into a CommandLine. The parsing is driven by the
parse(String[])
method which delegates to the option model to do
the actual parsing, with each Option implementation providing its own parsing
logic. The parseAndHelp(String[])
method attempts to simplify
the use of the former method by automatically handling any --help
options and displaying error messages where appropriate.
The HelpFormatter class is designed to allow the option model to be described to the user in a manner typical of command line applications. The HelpFormatter is designed with flexibility in mind so it should be possible to control exactly which structures are described to the user and what level of detail to use.
Any errors that occur while parsing result in an OptionException being thrown
which attempt to provide a meaningful message describing the problem to the
user. Parser's parseAndHelp(String[])
method catches any
OptionException and uses the HelpFormatter to display to the user:
// configure the options Group options = ...; // configure a HelpFormatter HelpFormatter hf = new HelpFormatter(); // configure a parser Parser p = new Parser(); p.setGroup(options); p.setHelpFormatter(hf); p.setHelpTrigger("--help"); CommandLine cl = p.parseAndHelp(new String[]{}); // abort application if no CommandLine was parsed if(cl==null) { System.exit(-1); }
Assuming that OptionExceptions have been averted then the next step is to have the application query the resulting CommandLine instance.
The CommandLine interface provides lots of ways to look up information either
by Option instance or by a String representing any of the forms valid on the
command line. For example if an option is configured with multiple names
(e.g. -?
, -h
, --help
) then any of the
those strings can be used to look up the value irrespective of which form
appeared on the command line.
The hasOption()
family of methods can be used to simply test for
the presence of options, while the getValues()
family of methods
can be used to retrieve the values associated with Arguments. The status of
any Switch options can be detected through the use of getSwitch()
methods which will return a Boolean if set or null otherwise:
// if we have --output option if( cl.hasOption( "--output" ) ) { // grab the path String path = (String) cl.getValue( "--output" ); // grab the format boolean xml = cl.hasOption( "--xml" ); // configure the application's output configureOutput( path,xml ); }
To enable complex CommandLine configurations alternative implementations are provided that can wrap a Properties or Preferences instance as a CommandLine. These can then be combined with the DefaultingCommandLine and the parsed CommandLine to provide a variety of different defaulting and overriding scenarios.