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]>
