The beauty of this approach is that it requres ZERO confiuration. All Option objects are created by reflection.
for example
public void main (String [] args ) {
MyClass me = new MyClass();
ReflectionCLI cli = new ReflectionCLI(me);
cli.applyCommandLine(args);
}
Is all it takes.
If there is a BeanInfo class additional properties are set.
argName is from the Display Name
description is from the Short Description.
I also override the meaning of "preferred" to set the Option to required.
I have included a simple JUnit test.
Please let me know what you think, and what else I need to do to get it accepted.
R,
Nick
Index: java/com/chalko/tools/batch/Batch.java =================================================================== RCS file: /cvsroot/chalktools/batch/src/java/com/chalko/tools/batch/Batch.java,v retrieving revision 1.19 diff -u -r1.19 Batch.java --- java/com/chalko/tools/batch/Batch.java 18 Jan 2003 08:46:42 -0000 1.19 +++ java/com/chalko/tools/batch/Batch.java 18 Jan 2003 09:29:22 -0000 @@ -22,8 +22,9 @@ import javax.mail.internet.MimeMultipart; import javax.mail.internet.MimePart; +import org.apache.commons.cli.ReflectionCLI; + import com.chalko.tools.batch.clp.BatchCLI; -import com.chalko.tools.batch.clp.ReflectionCLI; import com.chalko.tools.rt.BuildVersion; /** Index: java/com/chalko/tools/batch/clp/BatchCLI.java =================================================================== RCS file: /cvsroot/chalktools/batch/src/java/com/chalko/tools/batch/clp/BatchCLI.java,v retrieving revision 1.3 diff -u -r1.3 BatchCLI.java --- java/com/chalko/tools/batch/clp/BatchCLI.java 18 Jan 2003 09:14:37 -0000 1.3 +++ java/com/chalko/tools/batch/clp/BatchCLI.java 18 Jan 2003 09:29:22 -0000 @@ -2,6 +2,7 @@ import java.io.IOException; +import org.apache.commons.cli.*; import org.apache.commons.cli.ParseException; import com.chalko.tools.batch.Batchable; Index: java/com/chalko/tools/batch/clp/ReflectionCLI.java =================================================================== RCS file: java/com/chalko/tools/batch/clp/ReflectionCLI.java diff -N java/com/chalko/tools/batch/clp/ReflectionCLI.java --- java/com/chalko/tools/batch/clp/ReflectionCLI.java 18 Jan 2003 09:14:37 -0000 1.4 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,390 +0,0 @@ -package com.chalko.tools.batch.clp; -/* - * $Header: /cvsroot/chalktools/batch/src/java/com/chalko/tools/batch/clp/ReflectionCLI.java,v 1.4 2003/01/18 09:14:37 chalko Exp $ - */ - -import java.beans.BeanInfo; -import java.beans.IntrospectionException; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.HelpFormatter; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.OptionBuilder; -import org.apache.commons.cli.Options; -import org.apache.commons.cli.ParseException; -import org.apache.commons.cli.Parser; -import org.apache.commons.cli.PosixParser; - -/** - * - * Used to apply command line paramters, setting properties and options. - * - * @author Nick Chalko ([EMAIL PROTECTED]) - * @author $Author: chalko $ - * @version $Revision: 1.4 $ - */ -public class ReflectionCLI { - public final static String PROPERTY_FILE_OPTION_NAME = "prop"; - private final Properties prop = new Properties(); - private Object obj; - private final Parser parser; - - private final Map writeableFields = new HashMap(); - - private final Options options = new Options(); - - /** - * All propeties that are set as <emp>Preffered</emp> in the client classes beaninfo. - * - * @return List of PropertyDescriptor that where isExpert = true - */ - protected List getExpertPropertiesList() throws ParseException { - - List requiredPropetiesList = new ArrayList(writeableFields.size()); - - for (Iterator i = writeableFields.values().iterator(); i.hasNext();) { - PropertyDescriptor p = (PropertyDescriptor) i.next(); - if (p.isExpert()) { - requiredPropetiesList.add(p); - } - } - return requiredPropetiesList; - } - - /** - * All propeties that are set as <emp>expert</emp> - * in the client classes beaninfo. - * - * @return List of PropertyDescriptor that where isExpert = false. - */ - protected List getNonExpertPropertiesList() throws ParseException { - - List requiredPropetiesList = new ArrayList(writeableFields.size()); - - for (Iterator i = writeableFields.values().iterator(); i.hasNext();) { - PropertyDescriptor p = (PropertyDescriptor) i.next(); - if (!p.isExpert()) { - requiredPropetiesList.add(p); - } - } - return requiredPropetiesList; - } - - /** - * All propeties that are set as <emp>Preffered</emp> in the client classes beaninfo. - * - * @return List of PropertyDescriptor that where isPreferred = true. - */ - protected List getRequiredPropertiesList() throws ParseException { - - List requiredPropetiesList = new ArrayList(writeableFields.size()); - - for (Iterator i = writeableFields.values().iterator(); i.hasNext();) { - PropertyDescriptor p = (PropertyDescriptor) i.next(); - if (p.isPreferred()) { - requiredPropetiesList.add(p); - } - } - - return requiredPropetiesList; - } - - public boolean isAllRequiredPropertiesSet() throws ParseException { - try { - boolean result = true; - ; - for (Iterator i = getRequiredPropertiesList().iterator(); - i.hasNext(); - ) { - PropertyDescriptor pd = (PropertyDescriptor) i.next(); - Method readMethod = pd.getReadMethod(); - if (readMethod != null) { - - Object value = readMethod.invoke(obj, null); - if (value == null) { - result = false; - break; - } - - } - } - - return result; - } catch (IllegalAccessException e) { - throw new ParseException(e.getMessage()); - } catch (InvocationTargetException e) { - throw new ParseException(e.getMessage()); - } - - } - - /** - * Apply the proprties to the Object. Uses the java beans introspection to find writable properties. - * @param prop java.util.Properties the set of Properties to apply - */ - protected void apply(Properties prop) throws ParseException { - - Object args[] = new Object[1]; - for (Iterator i = writeableFields.values().iterator(); i.hasNext();) { - String newValue = null; - PropertyDescriptor p = (PropertyDescriptor) i.next(); - try { - Method writeMethod = p.getWriteMethod(); - String propertyName = p.getName(); - newValue = prop.getProperty(p.getName()); - if (newValue != null) { - args[0] = newValue; - // handle primitives. - Class clazz = p.getPropertyType(); - if (clazz.isPrimitive()) { - args[0] = primitiveValueOf(clazz, newValue); - } else { - args[0] = valueFromStringConstructor(clazz, newValue); - } - writeMethod.invoke(obj, args); - } - } catch (Exception e) { - throw new ParseException( - "Unable to set the value of " - + p.getName() - + " to " - + newValue - + " because " - + e); - } - } - - } - - private void initOptions() throws ParseException, java.io.IOException { - - // setup long options from writeable properties - - options.addOption( - OptionBuilder - .withArgName("file") - .hasArgs() - .withDescription("Property file") - .withLongOpt(PROPERTY_FILE_OPTION_NAME) - .create()); - - for (Iterator i = writeableFields.values().iterator(); i.hasNext();) { - - PropertyDescriptor pd = (PropertyDescriptor) i.next(); - Method writeMethod = pd.getWriteMethod(); - - if (writeMethod != null) { - options.addOption( - OptionBuilder - .hasArg() - .withDescription(pd.getShortDescription()) - .withArgName(pd.getDisplayName()) - .withLongOpt(pd.getName()) - .create()); - - } - - } - - return; - } - - /** - */ - private void initWriteablePropertiesList() throws ParseException { - writeableFields.clear(); - - try { - - BeanInfo bi = Introspector.getBeanInfo(obj.getClass()); - - addWritableFields(writeableFields, bi); - BeanInfo[] additionalBI = bi.getAdditionalBeanInfo(); - if (additionalBI != null) { - for (int i = 0; i < additionalBI.length; i++) { - BeanInfo beanInfo = additionalBI[i]; - addWritableFields(writeableFields, beanInfo); - - } - - } - - } catch (IntrospectionException e) { - - throw ( - new ParseException("Unable to apply Properties becuase " + e)); - - } - - } - - private void addWritableFields(Map writeableFields, BeanInfo bi) { - PropertyDescriptor pd[] = bi.getPropertyDescriptors(); - - Object args[] = new Object[1]; - - for (int i = 0; i < pd.length; i++) { - - String newValue = null; - - PropertyDescriptor p = pd[i]; - - Method writeMethod = p.getWriteMethod(); - - if (writeMethod != null) { - - writeableFields.put(p.getName(), p); - } - - } - } - - /** - * Loads a set of file into an existing Property set. - * Creation date: (7/25/00 4:52:19 PM) - * @return java.util.Properties - * @param fileNames java.lang.String[] - * @param prop java.util.Properties - */ - protected static Properties loadPropertyFile( - String fileName, - Properties prop) - throws java.io.IOException { - if (prop == null) { - prop = new Properties(); - } - java.io.File file = new java.io.File(fileName); - java.io.FileInputStream fis = new java.io.FileInputStream(file); - prop.load(fis); - return prop; - } - - /** - * Created CLI using Reflection to get the list of options. - */ - public ReflectionCLI(Object obj) throws ParseException, IOException { - super(); - parser = new PosixParser(); - this.obj = obj; - initWriteablePropertiesList(); - initOptions(); - } - - /** - * Reads the command line passed and applies it to the associated object. - * - * @param args java.lang.String[] - * @return argumentsLeft String[] - */ - public String[] applyCommandLine(String[] args) - throws java.io.IOException, ParseException { - - CommandLine cl = parser.parse(options, args); - - prop.clear(); - - int c; - Option[] optArray = cl.getOptions(); - for (int i = 0; i < optArray.length; i++) { - Option opt = optArray[i]; - String longOpt = opt.getLongOpt(); - if (longOpt.equals("prop")) { - String[] files = opt.getValues(); - for (int j = 0; j < files.length; j++) { - loadPropertyFile(files[j], prop); - } - - } else { - PropertyDescriptor pd = - (PropertyDescriptor) writeableFields.get(longOpt); - prop.put(pd.getName(), opt.getValue()); - - } - - } - apply(prop); - - return cl.getArgs(); - - } - - public void printUsage() { - HelpFormatter formatter = new HelpFormatter(); - formatter.printHelp(obj.getClass().getName(), options); - - } - - /** - * Insert the method's description here. - * Creation date: (5/29/2001 3:15:03 PM) - * @return java.lang.Object - * @param clazz java.lang.Class - * @param value java.lang.String - */ - protected static Object primitiveValueOf(Class clazz, String value) - throws java.text.ParseException { - Object obj = null; - if (clazz == boolean.class || clazz == Boolean.class) { - String tf = value.toLowerCase(); - if (tf.equals("true") || tf.equals("yes")) { - obj = Boolean.TRUE; - } else if (tf.equals("false") || tf.equals("no")) { - obj = Boolean.FALSE; - } else { - throw new java.text.ParseException( - "A boolean must be set to either true or false ", - 0); - } - } else if (clazz == int.class || clazz == Integer.class) { - obj = Integer.valueOf(value); - } else if (clazz == long.class || clazz == Long.class) { - obj = Long.valueOf(value); - } else if (clazz == float.class || clazz == Float.class) { - obj = Float.valueOf(value); - } else if (clazz == double.class || clazz == Double.class) { - obj = Double.valueOf(value); - } else if (clazz == byte.class || clazz == Byte.class) { - obj = Byte.valueOf(value); - } else if (clazz == char.class || clazz == Character.class) { - obj = new Character(value.charAt(0)); - } - return obj; - } - - /** - * Insert the method's description here. - * Creation date: (5/29/2001 3:15:03 PM) - * @return java.lang.Object - * @param clazz java.lang.Class - * @param value java.lang.String - */ - protected static Object valueFromStringConstructor( - Class clazz, - String value) { - Object obj = null; - if (clazz == String.class) { - obj = value; - } else { - try { - obj = - clazz.getConstructor( - new Class[] { String.class }).newInstance( - new Object[] { value }); - } catch (Exception e) { - // just return the null - } - } - return obj; - } -} Index: test/com/chalko/tools/batch/clp/Mirror.java =================================================================== RCS file: test/com/chalko/tools/batch/clp/Mirror.java diff -N test/com/chalko/tools/batch/clp/Mirror.java --- test/com/chalko/tools/batch/clp/Mirror.java 18 Jan 2003 09:14:33 -0000 1.2 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,77 +0,0 @@ -package com.chalko.tools.batch.clp; - -import java.io.File; - -/** - * A simple class to test reflection CLI. - * @author Nick Chalko ([EMAIL PROTECTED]) - * @author $Author: chalko $ - * @version $Revision: 1.2 $ - */ -public class Mirror { - - private File file; - private String name; - private boolean sleeping; - - /** - * Constructor for SimpleClass. - */ - public Mirror() { - super(); - } - - public static void main(String[] args) {} - /** - * Returns the file. - * @return File - */ - public File getFile() { - return file; - } - - - - /** - * Returns the name. - * @return String - */ - public String getName() { - return name; - } - - /** - * Sets the file. - * @param file The file to set - */ - public void setFile(File file) { - this.file = file; - } - - - - /** - * Sets the name. - * @param name The name to set - */ - public void setName(String name) { - this.name = name; - } - - /** - * Returns the sleeping. - * @return boolean - */ - public boolean isSleeping() { - return sleeping; - } - - /** - * Sets the sleeping. - * @param sleeping The sleeping to set - */ - public void setSleeping(boolean sleeping) { - this.sleeping = sleeping; - } - -} Index: test/com/chalko/tools/batch/clp/ReflectionCLITest.java =================================================================== RCS file: test/com/chalko/tools/batch/clp/ReflectionCLITest.java diff -N test/com/chalko/tools/batch/clp/ReflectionCLITest.java --- test/com/chalko/tools/batch/clp/ReflectionCLITest.java 18 Jan 2003 09:14:33 -0000 1.5 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,81 +0,0 @@ -package com.chalko.tools.batch.clp; - -import java.io.IOException; - -import junit.framework.TestCase; - -import org.apache.commons.cli.ParseException; - -/** - * - * @author Nick Chalko ([EMAIL PROTECTED]) - * @author $Author: chalko $ - * @version $Revision: 1.5 $ - */ -public class ReflectionCLITest extends TestCase { - private Mirror mirror; - private ReflectionCLI cli; - /** - * Constructor for ReflectionCLITest. - * @param testName - */ - public ReflectionCLITest(String testName) { - super(testName); - } - - /** - * @see TestCase#setUp() - */ - protected void setUp() throws Exception { - super.setUp(); - mirror = new Mirror(); - cli = new ReflectionCLI(mirror); - - } - - /** - * @see TestCase#tearDown() - */ - protected void tearDown() throws Exception { - super.tearDown(); - mirror = null; - cli = null; - } - - public void testNoArgs() throws ParseException, IOException { - cli.applyCommandLine(new String[] {}); - assertEquals("all required properties",true,cli.isAllRequiredPropertiesSet()); - cli.printUsage(); - - } - - public void testFile() throws ParseException, IOException { - cli.applyCommandLine(new String[] {"--file","foo.txt"}); - assertEquals("all required properties",true,cli.isAllRequiredPropertiesSet()); - cli.printUsage(); - assertNotNull("File was not set",mirror.getFile()); - assertEquals("File name","foo.txt",mirror.getFile().getName()); - - } - - public void testSleeping() throws ParseException, IOException { - cli.applyCommandLine(new String[] {"--sleeping","true"}); - assertEquals("all required properties",true,cli.isAllRequiredPropertiesSet()); - cli.printUsage(); - - assertEquals("sleeping",true,mirror.isSleeping()); - - } - - public void testProp() throws ParseException, IOException { - cli.applyCommandLine(new String[] {"--prop","src/test/com/chalko/tools/batch/clp/mirror.properties"}); - assertEquals("all required properties",true,cli.isAllRequiredPropertiesSet()); - cli.printUsage(); - - assertEquals("name","foobar",mirror.getName()); - - } - - - -} Index: test/com/chalko/tools/batch/clp/mirror.properties =================================================================== RCS file: test/com/chalko/tools/batch/clp/mirror.properties diff -N test/com/chalko/tools/batch/clp/mirror.properties --- test/com/chalko/tools/batch/clp/mirror.properties 18 Jan 2003 08:58:30 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,2 +0,0 @@ -# $Header: $ -name=foobar \ No newline at end of file
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>