Java Programs are often started form the command line with additonal arguments, like options (e.g. -f or -quiet) or filenames. For example in the call
java -cp PATH com.foo.Convert -q -f xml foo.txtthe "program" Convert has the arguments -q, -f, xml and foo.txt. Here -q and -f are (command line) options, xml is the value to -f and foo.txt is a non-option.
To parse and validate these arguments you need a command line parser. Writing such a parser can be an awful work, if you wanna do it right. Here are some things you have to consider:
Version | Changes |
0.1 | Initial version |
jcolipa-0.1/ doc/ examples/ src/ build.xml
<jcolipa> <usage>MyProgram, 1.0a: usage: MyProgram [options] file ...</usage> <options> <option name="-n" desc="Name of the server." varname="serverName" type="String" default='"localhost"' /> <option name="-q" desc="Quiet mode, no output is done." varname="quiet" type="Boolean" default="false" /> <option name="-l" desc="Length of the name." varname="lengthOfName" type="Integer" /> <option name="-I" desc="The interval" varname="interval" type="Float" /> <option name="-s" desc="List of servers." varname="serverList" type="de.thomasbaustert.jcolipa.MyList" /> </options> <!-- Error Message %o : option %v : value to option %t : type of option --> <errormessage> <unknownoption>The specified Option '%o' is unknown.</unknownoption> <missingvalue>The value to option '%o' is missing.</missingvalue> <valueofwrongtype>The value '%v' to option '%o' is not of type '%t'.</valueofwrongtype> <mandatorynotspecified>The mandatory option '%o' is not specified.</mandatorynotspecified> </errormessage> </jcolipa>Each option tag contains the following attributes:
Attribute | Description |
name | The name of the option; e.g. -q, -quiet, -file. |
desc | A short one line description for the usage. |
varname | The name of the variable containing the value to the option. For every value JColipa provides a getter method. For example "serverName" will result in a method "getServerName()". If the value is of type Boolean the method prefix will be "is", e.g. isQuiet(). |
type | The type of the value. Allowed types are Boolean, Double, Float, Integer, Long, Short, String. But also self defined types, which must be specified with the full qualified class name, e.g. de.thomasbaustert.jcolipa.MyList (see Extending). Every option of type Boolean must not have a value, e.g. "-q" and not "-q true". |
default | The default value. This attribute is optional. When specified, the option
is not mandatory, because there's a default value. If not specified, a value must be specified to
this option. Note! A String must be double quote, e.g. '"localhost"' and a self defined type cannot have a default value right now (results in compile error). |
The four error messages can be modified, if necessary. The pattern character %o, %v, %t can be used
to insert the option name, the value of the option or the type of the option.
Generating JColipa
After editing the XML file, run ant with the build.xml file and no target. It generates the file
JColipa.java in the java/ directory and runs the Java compiler. JColipa.java contains
a main method for tests, so run it with "java -cp build JColipa OPTIONS ...".
An output of the example may look like this (with no arguments, there will be a usage):
D:\projects\baw\clp>java -cp build JColipa -s a,b,c,d x -l 12 -I 42 y options: -n = {-n, value=Otto, default=Otto, type=String, hasValue=true, mandatory=false, found=false} -l = {-l, value=12, default=-, type=Integer, hasValue=true, mandatory=true, found=true} -I = {-I, value=42.0, default=-, type=Float, hasValue=true, mandatory=true, found=true} -s = {-s, value=[a, b, c, d], default=-, type=de.thomasbaustert.jcolipa.MyList, hasValue=true, mandatory=true, found=true} -q = {-q, value=false, default=false, type=Boolean, hasValue=false, mandatory=false, found=false} non options: [x, y]
... private JColipa clp = JColipa.getInstance(); ... private void connect() { ... // connect to clp.getServerName() ... // if !clp.isQuite() write debug ... } ... public static void main(String[] args) { if( args.length == 0 ) { System.out.println(JColipa.usage()); System.exit(1); } try { clp.parse(args); ... // your code here ... } catch(ParseException e) { System.err.println(e.getMessage()); //e.printStackTrace(System.err); } }As you can see, you get every value through its getter method provided by JColipa. If no argument is specified, print a usage.
static Object valueOf(String) [throws java.text.ParseException]ParseException is optinal but the only exception that is allowed. The type name in the XML file must be the full qualified classname.
For example, create a type MyList:
package de.thomasbaustert.jcolipa; import java.util.Vector; import java.util.StringTokenizer; /** * Example class to extends JColipa with an own type. * Validation (throwing ParseException) omitted. */ public class MyList extends Vector { // Parse a comma separated list of names, e.g. "a,b,c,d" and return MyList. public static Object valueOf(String s) { MyList ml = new MyList(); StringTokenizer st = new StringTokenizer(s,","); while( st.hasMoreTokens() ) { String item = st.nextToken(); ml.add(item.trim()); } return ml; } }Then specify an option with the full qualitfied class name in the XML file jcolipa.xml:
... <option name="-l" desc="Comma separated list of files." varname="serverList" type="de.thomasbaustert.jcolipa.MyList" /> ...After generating JColipa.java there will be a method of signature:
public MyList getServerList()and you get the list by calling
... JColipa clp = JColipa.getInstance(); MyList list = clp.getServerList(); ...where getServerList() has automatically a return value of type MyList. That's all.