Added: 
uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/test/java/org/apache/uima/ducc/cli/test/TestCommandLine.java
URL: 
http://svn.apache.org/viewvc/uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/test/java/org/apache/uima/ducc/cli/test/TestCommandLine.java?rev=1634635&view=auto
==============================================================================
--- 
uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/test/java/org/apache/uima/ducc/cli/test/TestCommandLine.java
 (added)
+++ 
uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/test/java/org/apache/uima/ducc/cli/test/TestCommandLine.java
 Mon Oct 27 18:21:39 2014
@@ -0,0 +1,831 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+*/
+package org.apache.uima.ducc.cli.test;
+
+import org.apache.uima.ducc.cli.CommandLine;
+import org.apache.uima.ducc.cli.IUiOption;
+
+public class TestCommandLine
+    extends ATestDriver
+{
+    int NTESTS = 8;
+
+    enum OptionSet1
+        implements IUiOption
+    {
+        Administrators {                // to test multiargs
+            public String  pname()       { return "administrators"; } 
+            public boolean multiargs()   { return true; }
+            public String  argname()     { return "list of ids"; } 
+            public String  description() { return "Blank-delimited list of 
userids allowed to manage this service."; } 
+            public String  example()     { return "bob mary jimbo"; }
+            public String  label()       { return name(); }
+        },
+
+        Autostart   { 
+            public String  pname()       { return "autostart"; } 
+            public boolean noargs()      { return true; }
+            public String  description() { return "If True, start the service 
when DUCC starts."; } 
+            public String  example()     { return null; }
+            public String  label()       { return name(); }
+        },
+
+        Debug {                     // to test optional args
+            public String  pname()       { return "debug"; }
+            public String  argname()     { return "true|false"; }
+            public boolean optargs()     { return true; }
+            public String  deflt()       { return "true"; }
+            public String  description() { return "Enable CLI Debugging 
messages."; }
+            public String  example()     { return null; }
+            public String  label()       { return null; }
+        },            
+
+        Description {                     // to test longer quoted strings
+            public String  pname()       { return "description"; }
+            public String  argname()     { return "string"; }
+            public String  description() { return "Test description of the 
argument."; }
+        },            
+
+        DriverJvmArgs {                     // to test - in value
+            public String  pname()       { return "driver_jvm_args"; }
+            public String  argname()     { return "String with jvm arguments"; 
}
+            public String  description() { return "Args passed to the driver 
jvm."; }
+        },            
+
+        ProcessJvmArgs {                   // to test -- in value
+            public String  pname()       { return "process_jvm_args"; }
+            public String  argname()     { return "String with jvm arguments"; 
}
+            public String  description() { return "Args passed to JP jvm."; }
+        },            
+
+        Help {                      // to test no args
+            public String  pname()       { return "help"; }
+            public String  argname()     { return null; }
+            public boolean noargs()      { return true; }
+            public String  description() { return "Print this help message.  
It actually an astonishing long and uninformative description in order to test 
the justify part of the help formatter.  Just read Kipling's Ballad of East and 
West for the first time in years. Have you ever kippled? Ask the gefilte 
fish."; }
+            public String  example()     { return null; }
+            public String  label()       { return null; }
+        },            
+
+        SchedulingClass { 
+            public String pname()       { return "scheduling_class"; }
+            public String argname()     { return "scheduling class name"; }
+            public String description() { return "The class to run the job 
in."; }
+            public String example()     { return "normal"; }
+            public String label()       { return "SchedulingClass"; }
+        },            
+
+        Specification { 
+            public String pname()       { return "specification"; }
+            public String sname()       { return "f"; }
+            public boolean required()   { return true; }
+            public String argname()     { return "file"; }
+            public String description() { return "Properties file comprising 
the specification, where the keys are names of parameters. Individual 
parameters take precedence over those specified in properties file, if any."; }
+            public String example()     { return null; }
+            public String label()       { return name(); }
+        },
+
+        WaitForCompletion { 
+            public String pname()       { return "wait_for_completion"; }
+            public String argname()     { return null; }
+            public boolean noargs()     { return true; }
+            public String description() { return "Do not exit until job is 
completed."; }
+            public String example()     { return null; }
+            public String label()       { return name(); }
+        },            
+
+
+        WorkingDirectory { 
+            public String pname()       { return "working_directory"; }
+            public String argname()     { return "path"; }
+            public String description() { return "The working directory set in 
each process. Default to current directory."; }
+            public String example()     { return null; }
+            public String deflt()       { return "."; }
+            public String label()       { return "WorkingDirectory"; }
+        },            
+
+        ;
+
+        public String argname()    { return null; }
+        public boolean multiargs() { return false; } // the option can have >1 
arg
+        public boolean required()  { return false; } // this option is required
+        public String  deflt()     { return null; }  // default, or ""
+        public String  label()     { return null; }  // Parameter name for 
label in web form
+        public String  sname()     { return null; }  // short name of option
+        public boolean optargs()   { return false; } // is the argument 
optional?
+        public boolean noargs()    { return false; }
+        public String example()    { return null; }
+
+        public String makeDesc()
+        {
+            if ( example() == null ) return description();
+            return description() + "\nexample: " + example();
+        }
+    };
+
+    // deliberately conflicting
+    enum OptionSet2
+        implements IUiOption
+    {
+        Administrators {
+            public String pname()       { return "administrators"; } 
+            public boolean multiargs()  { return true; }
+            public boolean noargs()     { return true; }
+            public String argname()     { return "list of ids"; } 
+            public String description() { return "Blank-delimited list of 
userids allowed to manage this service."; } 
+            public String example()     { return "bob mary jimbo"; }
+            public String label()       { return name(); }
+        },
+        ;
+
+        public String argname()    { return null; }
+        public boolean multiargs() { return false; } // the option can have >1 
arg
+        public boolean required()  { return false; } // this option is required
+        public String  deflt()     { return null; }  // default, or ""
+        public String  label()     { return null; }  // Parameter name for 
label in web form
+        public String  sname()     { return null; }  // short name of option
+        public boolean optargs()   { return false; } // is the argument 
optional?
+        public boolean noargs()    { return false; }
+
+        public String makeDesc()
+        {
+            if ( example() == null ) return description();
+            return description() + "\nexample: " + example();
+        }
+
+    }
+
+    // deliberately conflicting
+    enum OptionSet3
+        implements IUiOption
+    {
+        Administrators {
+            public String pname()       { return "administrators"; } 
+            public boolean optargs()    { return true; }
+            public boolean noargs()     { return true; }
+            public String argname()     { return "list of ids"; } 
+            public String description() { return "Blank-delimited list of 
userids allowed to manage this service."; } 
+            public String example()     { return "bob mary jimbo"; }
+            public String label()       { return name(); }
+        },
+
+        ;
+
+        public String argname()    { return null; }
+        public boolean multiargs() { return false; } // the option can have >1 
arg
+        public boolean required()  { return false; } // this option is required
+        public String  deflt()     { return null; }  // default, or ""
+        public String  label()     { return null; }  // Parameter name for 
label in web form
+        public String  sname()     { return null; }  // short name of option
+        public boolean optargs()   { return false; } // is the argument 
optional?
+        public boolean noargs()    { return false; }
+
+        public String makeDesc()
+        {
+            if ( example() == null ) return description();
+            return description() + "\nexample: " + example();
+        }
+
+    }
+
+    // optargs, but no default specified
+    enum OptionSet4
+        implements IUiOption
+    {
+        Administrators {
+            public String pname()       { return "administrators"; } 
+            public boolean optargs()    { return true; }
+            public String argname()     { return "list of ids"; } 
+            public String description() { return "Blank-delimited list of 
userids allowed to manage this service."; } 
+            public String example()     { return "bob mary jimbo"; }
+            public String label()       { return name(); }
+        },
+
+        ;
+
+        public String argname()    { return null; }
+        public boolean multiargs() { return false; } // the option can have >1 
arg
+        public boolean required()  { return false; } // this option is required
+        public String  deflt()     { return null; }  // default, or ""
+        public String  label()     { return null; }  // Parameter name for 
label in web form
+        public String  sname()     { return null; }  // short name of option
+        public boolean optargs()   { return false; } // is the argument 
optional?
+        public boolean noargs()    { return false; }
+
+        public String makeDesc()
+        {
+            if ( example() == null ) return description();
+            return description() + "\nexample: " + example();
+        }
+
+    }
+
+    // multiargs and optargs
+    enum OptionSet5
+        implements IUiOption
+    {
+        Administrators {
+            public String pname()       { return "administrators"; } 
+            public boolean multiargs()  { return true; }
+            public boolean optargs()    { return true; }
+            public String deflt()       { return "bob"; }
+            public String argname()     { return "list of ids"; } 
+            public String description() { return "Blank-delimited list of 
userids allowed to manage this service."; } 
+            public String example()     { return "bob mary jimbo"; }
+            public String label()       { return name(); }
+        },
+
+        ;
+
+        public String argname()    { return null; }
+        public boolean multiargs() { return false; } // the option can have >1 
arg
+        public boolean required()  { return false; } // this option is required
+        public String  deflt()     { return null; }  // default, or ""
+        public String  label()     { return null; }  // Parameter name for 
label in web form
+        public String  sname()     { return null; }  // short name of option
+        public boolean optargs()   { return false; } // is the argument 
optional?
+        public boolean noargs()    { return false; }
+
+        public String makeDesc()
+        {
+            if ( example() == null ) return description();
+            return description() + "\nexample: " + example();
+        }
+
+    }
+
+    // For mixed option-set testing
+    enum OptionSet6
+        implements IUiOption
+    {
+        Specification { 
+            public String pname()       { return "specification"; }
+            public String sname()       { return "f"; }
+            public boolean required()   { return true; }
+            public String argname()     { return "file"; }
+            public String description() { return "Properties file comprising 
the specification, where the keys are names of parameters. Individual 
parameters take precedence over those specified in properties file, if any."; }
+            public String example()     { return null; }
+            public String label()       { return name(); }
+        },
+        ;
+
+        public String argname()    { return null; }
+        public boolean multiargs() { return false; } // the option can have >1 
arg
+        public boolean required()  { return false; } // this option is required
+        public String  deflt()     { return null; }  // default, or ""
+        public String  label()     { return null; }  // Parameter name for 
label in web form
+        public String  sname()     { return null; }  // short name of option
+        public boolean optargs()   { return false; } // is the argument 
optional?
+        public boolean noargs()    { return false; }
+
+        public String makeDesc()
+        {
+            if ( example() == null ) return description();
+            return description() + "\nexample: " + example();
+        }
+
+    }
+
+    // For mixed option-set testing
+    enum OptionSet7
+        implements IUiOption
+    {
+        WorkingDirectory { 
+            public String pname()       { return "working_directory"; }
+            public String argname()     { return "path"; }
+            public String description() { return "The working directory set in 
each process. Default to current directory."; }
+            public String example()     { return null; }
+            public String deflt()       { return "."; }
+            public String label()       { return "WorkingDirectory"; }
+        },            
+        ;
+
+        public String argname()    { return null; }
+        public boolean multiargs() { return false; } // the option can have >1 
arg
+        public boolean required()  { return false; } // this option is required
+        public String  deflt()     { return null; }  // default, or ""
+        public String  label()     { return null; }  // Parameter name for 
label in web form
+        public String  sname()     { return null; }  // short name of option
+        public boolean optargs()   { return false; } // is the argument 
optional?
+        public boolean noargs()    { return false; }
+
+        public String makeDesc()
+        {
+            if ( example() == null ) return description();
+            return description() + "\nexample: " + example();
+        }
+
+    }
+
+
+    //
+    // establish the tests and the order of execution
+    //
+    public String[] testsToRun()
+    {
+
+        return new String[] {
+            "Sanity",
+            "BasicParse",
+            "OptionalArguments",
+            "IncompleteOptionSet",
+            "MixedOptions",
+            "MissingArguments",
+            "MultipleOptionSets",
+            "HelpGeneration",
+            "MultiTokenValue",
+        };
+    }
+
+    public void testSanity(String tid)
+    {
+        //
+        // Test parser's sanity checker
+        //
+        String[] args = {
+            "--administrators",
+        };
+        IUiOption[] opts = {
+            OptionSet2.Administrators
+        };
+
+        CommandLine cl = new CommandLine(args, opts);
+        String testid = tid + ": multiargs=T noargs=T";
+        try {
+            cl.parse();
+            fail(testid, "Parse succeeded but should have failed.");
+        } catch ( Exception e ) {
+            success(testid, "Parse failed as expected", e.getMessage());
+        }        
+        
+
+        opts[0] = OptionSet3.Administrators;        
+        cl = new CommandLine(args, opts);
+        testid = tid + ": optargs=T noargs=T";
+        try {
+            cl.parse();
+            fail(testid, "Parse succeeded but should have failed.");
+        } catch ( Exception e ) {
+            success(testid, "Parse failed as expected", e.getMessage());
+        }        
+        
+        opts[0] = OptionSet4.Administrators;        
+        cl = new CommandLine(args, opts);
+        testid = tid + ": optargs=T, no default";
+        try {
+            cl.parse();
+            fail(testid, "Parse succeeded but should have failed."); 
+        } catch ( Exception e ) {
+            success(testid, "Parse failed as expected", e.getMessage());
+        }        
+        
+        opts[0] = OptionSet5.Administrators;        
+        cl = new CommandLine(args, opts);
+        testid = tid + ": optargs=T, multiargs=T, fetch deflt";
+        try {
+            cl.parse();
+            success(testid, "Parse succeeded.");
+            if ( cl.get(opts[0]).equals("bob")) {
+                success(testid, "Default of 'bob' correctly found.");
+            } else {
+                fail(testid, "Did not fetch default. Expeced 'bob', found", 
cl.get(opts[0]));
+            }
+        } catch ( Exception e ) {
+            fail(testid, "Parse failed", e.getMessage());
+        }        
+        
+        args = new String[] {
+            "--administrators", "mary",
+        };
+        cl = new CommandLine(args, opts);
+        testid = tid + ": optargs=T, multiargs=T, fetch value";
+        try {
+            cl.parse();
+            success(testid, "Parse succeeded.");
+            if ( cl.get(opts[0]).equals("mary")) {
+                success(testid, "Valu of 'mary' correctly found.");
+            } else {
+                fail(testid, "Did not fetch default. Expeced 'mary', found", 
cl.get(opts[0]));
+            }
+        } catch ( Exception e ) {
+            fail(testid, "Parse failed", e.getMessage());
+        }        
+        
+    }
+
+    public void testBasicParse(String testid)
+    {
+        //
+        // Simplest case, everything is paired, everything is provided
+        //
+        // Also shows proper termination for k,v option
+        //
+        String[] args = {
+            "--specification"    , "1.job",
+            "--scheduling_class" , "normal",
+            "--working_directory", "/home/bob",
+        };
+        IUiOption[] opts = {            // must be same order as args so we 
can verify values easiy
+            OptionSet1.Specification,
+            OptionSet1.SchedulingClass,
+            OptionSet1.WorkingDirectory,
+        };
+
+        CommandLine cl = new CommandLine(args, opts);
+
+        try {            
+            cl.parse();
+            success(testid, "Successful parse");
+            System.out.println("Command line: " + cl);    // tests toString()
+                
+            // in this test, must find everything and values must match
+            int i = 1;
+            for ( IUiOption o : opts ) {
+                if ( cl.contains(o) && args[i].equals(cl.get(o)) ) { 
+                    success(testid, "Found option " + o + " = " + cl.get(o));
+                } else {                        
+                    fail(testid, "Did not find " + o);
+                }
+                i += 2;
+            }
+        } catch (Exception e) {
+            fail(testid, "Parse failed.", e.getMessage());
+        }
+        
+    }
+
+    public void testOptionalArguments(String tid)
+    {
+        //
+        // Test optional and prohibited parameters
+        //
+        // debug takes optional parameter - default must exist
+        // wait_for_completion takes none - must fail if value is provided
+        //
+        String[] args = {
+            "--debug", "false",
+            "--wait_for_completion",
+        };
+        IUiOption[] opts = {
+            OptionSet1.Debug,
+            OptionSet1.WaitForCompletion,
+        };
+
+        CommandLine cl = new CommandLine(args, opts);
+        
+        String testid = tid + "1";
+        try {            
+            cl.parse();
+            success(testid, "Successful parse");
+            System.out.println("Command line: " + cl);    // tests toString()
+                
+            // in this test, must find everything
+            for ( IUiOption o : opts ) {
+                if ( cl.contains(o) ) {
+                    success(testid, "Found option " + o + " = " + cl.get(o));
+                } else {                        
+                    fail(testid, "Did not find " + o);
+                }
+            }
+            if ( !cl.get(OptionSet1.Debug).equals("false") ) {
+                fail(testid, "Value for Debug is wwong.  Expected 'false', 
found", cl.get(OptionSet1.Debug));
+            }
+        } catch (Exception e) {
+            fail(testid, "Parse failed.", e.getMessage());
+        }
+        
+        args = new String[] {
+            "--debug",
+            "--wait_for_completion", 
+        };
+        testid = tid + "2";
+        cl = new CommandLine(args, opts);
+
+        try {            
+            cl.parse();
+            success(testid, "Successful parse");
+            System.out.println("Command line: " + cl);    // tests toString()
+                
+            // in this test, must find everything.  default must be filled in 
for debug, nothing for wait_for_completion
+            for ( IUiOption o : opts ) {
+                if ( cl.contains(o) ) {
+                    success(testid, "Found option " + o + " = " + cl.get(o));
+                } else {                        
+                    fail(testid, "Did not find " + o);
+                }
+                if ( o.optargs() && !cl.get(o).equals(o.deflt()) ) {
+                    fail(testid, "Incorrect default for", o.pname(), 
"expected", o.deflt(), "found", cl.get(o));
+                }
+                if ( o.noargs() && (cl.get(o) != null) ) {
+                    fail(testid, "Found non-null value for", o.pname(), 
"expected null.");
+                }
+            }
+        } catch (Exception e) {
+            fail(testid, "Parse failed.", e.toString());
+        }
+        
+
+        args = new String[] {
+            "--debug",
+            "--wait_for_completion", "true"
+        };
+        cl = new CommandLine(args, opts);
+        testid = tid + "3";
+
+        try {            
+            cl.parse();
+            fail(testid, "Parse should have failed on 'wait_for_completion.");
+        } catch (Exception e) {
+            success(testid, "Parse failed as expected", e.getMessage());
+        }        
+
+    }
+
+    public void testIncompleteOptionSet(String testid)
+    {
+        //
+        // Spurious args - the option set is incomplete
+        //
+        String[] args = {
+            "--specification"    , "1.job",
+            "--scheduling_class" , "normal",
+            "--help",
+            "--working_directory", "/home/bob",
+            "--debug", "true",
+            "--autostart",
+        };
+        IUiOption[] opts = {
+            OptionSet1.Specification,
+            OptionSet1.SchedulingClass,
+            OptionSet1.WorkingDirectory,
+        };
+
+        CommandLine cl = new CommandLine(args, opts);
+
+        try {            
+            cl.parse();
+            fail(testid, "Incomplete option set should have failed.");
+        } catch (Exception e) {
+            success(testid, "Parse failed as expected:", e.getMessage());
+        }
+        
+    }
+
+    public void testMixedOptions(String testid)
+    {
+        //
+        // A bunch of options of mixed types.  Expected to succeed
+        //
+        String[] args = {
+            "--specification"    , "1.job",
+            "--scheduling_class" , "normal",
+            "--working_directory", "/home/bob",
+            "--debug", "false",
+            "--help",
+            "--autostart",
+        };
+        IUiOption[] opts = { 
+            OptionSet1.Specification,
+            OptionSet1.SchedulingClass,
+            OptionSet1.Help,
+            OptionSet1.WorkingDirectory,
+            OptionSet1.Debug,
+            OptionSet1.Autostart,
+        };
+
+        CommandLine cl = new CommandLine(args, opts);
+
+        try {            
+            cl.parse();
+            success(testid, "Incomplete option set");
+            System.out.println("Command line: " + cl);    // tests toString()
+                
+            String expected = null;
+            // in this test, must find everything
+            for ( IUiOption o : opts ) {
+                if ( cl.contains(o) ) {
+                     // insure correct stuff is parsed in
+                    switch ( (OptionSet1) o ) {
+                        case Specification:
+                            expected = "1.job";
+                            break;
+                        case SchedulingClass:
+                            expected = "normal";
+                            break;
+                        case Help:
+                            expected = null;
+                            break;
+                        case WorkingDirectory:
+                            expected = "/home/bob";
+                            break;
+                        case Debug:
+                            expected = "false";
+                            break;
+                        case Autostart:
+                            expected = null;
+                            break;
+                    }
+                    if ( expected == null && expected == cl.get(o) ) {
+                        success(testid, "Received expected null for", 
o.pname());
+                    } else if ( expected.equals(cl.get(o)) ) {
+                        success(testid, "Received expected", expected, "for", 
o.pname());
+                    } else {
+                        fail(testid, "Invalid parse, expected", expected, "and 
received", cl.get(o));
+                    }
+                } else {                        
+                    fail(testid, "Did not find " + o);
+                }
+            }
+        } catch (Exception e) {
+            fail(testid, "Parse failed.", e.getMessage());
+        }
+        
+    }
+
+
+    public void testMissingArguments(String testid)
+    {
+        // 
+        // Argument 'specification' is required but missing
+        //
+        String[] args = {
+            "--scheduling_class" , "normal",
+            "--help",
+            "--working_directory", "/home/bob",
+            "--debug", "true",
+            "--autostart",
+        };
+        IUiOption[] opts = {
+            OptionSet1.Help,
+            OptionSet1.Debug,
+            OptionSet1.Autostart,
+            OptionSet1.SchedulingClass,
+            OptionSet1.Specification,
+            OptionSet1.WorkingDirectory,
+        };
+
+        CommandLine cl = new CommandLine(args, opts);
+
+        try {            
+            cl.parse();
+            fail(testid, "Incomplete option set should have failed but 
didn't");
+
+        } catch (Exception e) {
+            success(testid, "Parse failed.", e.getMessage());
+        }
+        
+    }
+
+    public void testMultipleOptionSets(String testid)
+    {
+        // 
+        // Arguments from mixed option sets
+        //
+        String[] args = {
+            "--scheduling_class" , "normal",
+            "--help",
+            "--specification", "1.job",
+            "--working_directory", "/home/bob",
+            "--debug", "true",
+            "--autostart",
+        };
+
+        IUiOption[] opts = {
+            OptionSet1.Help,
+            OptionSet1.Debug,
+            OptionSet1.Autostart,
+            OptionSet1.SchedulingClass,
+            OptionSet6.Specification,
+            OptionSet7.WorkingDirectory,
+        };
+
+        CommandLine cl = new CommandLine(args, opts);
+
+        try {            
+            cl.parse();
+            success(testid, "Command line:", cl.toString());
+        } catch (Exception e) {
+            fail(testid, "Parse with multiple option sets failed.", 
e.getMessage());
+        }
+        
+    }
+
+    public void testHelpGeneration(String testid)
+    {
+        // 
+        // Auto-help generation.
+        // Unclear how to verify so as long as it doesn't crash we'll call it 
ok.
+        //
+        IUiOption[] opts = {
+            OptionSet1.Administrators,
+            OptionSet1.Autostart,
+            OptionSet1.Debug,
+            OptionSet1.Help,
+            OptionSet1.SchedulingClass,
+            OptionSet1.Specification,
+            OptionSet1.WaitForCompletion,
+            OptionSet1.WorkingDirectory,
+        };
+
+        CommandLine cl = new CommandLine(null, opts);
+
+        try {            
+            success(testid, "Help Generation:\n", 
cl.formatHelp(this.getClass().getName()));
+        } catch (Exception e) {
+            fail(testid, "Help generation.");
+        }
+        
+    }
+
+    public void testMultiTokenValue(String tid)
+    {
+        IUiOption[] opts = {
+            OptionSet1.Description,
+            OptionSet1.DriverJvmArgs,
+            OptionSet1.ProcessJvmArgs,
+            OptionSet1.WorkingDirectory,
+        };
+
+        // 
+        // arguments that start with - or --
+        //
+        String[] args;
+        String testid;
+        CommandLine cl;
+
+        args = new String[]{
+            "--description", "This is a multitoken description.",    // 
multitoken value
+        };
+        testid = tid + " basic";
+        cl = new CommandLine(args, opts);
+        try {            
+            cl.parse();
+            success(testid, "Command line:", cl.toString());
+        } catch (Exception e) {
+            fail(testid, "Multitoken description.", e.getMessage());
+        }
+ 
+        args = new String[]{
+            "--driver_jvm_args", "-Xmx",                 // one -
+        };
+        testid = tid + " Args with 1 -.";
+        cl = new CommandLine(args, opts);
+        try {            
+            cl.parse();
+            success(testid, "Command line:", cl.toString());
+        } catch (Exception e) {
+            fail(testid, "Parse args that start with - failed.", 
e.getMessage());
+        }
+ 
+        args = new String[] {
+            "--driver_jvm_args", "--Xmx",                // two --
+        };
+        testid = tid + " Args with 2 --.";
+        cl = new CommandLine(args, opts);
+        try {            
+            cl.parse();
+            success(testid, "Command line:", cl.toString());
+        } catch (Exception e) {
+            fail(testid, "Parse args that start with -- failed.", 
e.getMessage());
+        }
+ 
+        args = new String[] {
+            "--driver_jvm_args", "--description",        // it's a keyword, 
fail
+        };
+        testid = tid + " Args which are also keywords";
+        cl = new CommandLine(args, opts);
+        try {            
+            cl.parse();
+            fail(testid, "Parse arg that's valid keyword succeeded, should 
have failed.", cl.toString());
+        } catch (Exception e) {
+            success(testid, "Parse arg that's a keyword failed correctly", 
e.getMessage());
+        }
+        
+    }
+
+    public static void main(String[] args)
+    {
+        try {
+            TestCommandLine tester = new TestCommandLine();
+            tester.runTests();
+        } catch ( Exception e ) {
+            e.printStackTrace();
+        }
+    }
+}

Modified: 
uima/sandbox/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/utils/DuccPropertiesResolver.java
URL: 
http://svn.apache.org/viewvc/uima/sandbox/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/utils/DuccPropertiesResolver.java?rev=1634635&r1=1634634&r2=1634635&view=diff
==============================================================================
--- 
uima/sandbox/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/utils/DuccPropertiesResolver.java
 (original)
+++ 
uima/sandbox/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/utils/DuccPropertiesResolver.java
 Mon Oct 27 18:21:39 2014
@@ -27,12 +27,10 @@ import java.util.Properties;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.uima.ducc.common.IDuccEnv;
-import org.apache.uima.ducc.common.utils.id.DuccId;
 
 public class DuccPropertiesResolver {
        
-       private DuccLogger logger = 
DuccLogger.getLogger(DuccPropertiesResolver.class, null);
-       private DuccId duccId = null;
+       //private DuccId duccId = null;
        
        private AtomicBoolean loadedPrivate = new AtomicBoolean(false);
        
@@ -163,7 +161,7 @@ public class DuccPropertiesResolver {
     }
     
     private void init(Properties properties) {
-       String location = "init";
+       //String location = "init";
        String fileName = null;
         try {
                String componentProperties="ducc.deploy.configuration";
@@ -179,13 +177,13 @@ public class DuccPropertiesResolver {
         } 
         catch (FileNotFoundException e) {
                if(!e1.get()) {
-               logger.error(location, duccId, "File not found: "+fileName);
+               //logger.error(location, duccId, "File not found: "+fileName);
                e1.set(true);;
             }
         } 
         catch (IOException e) {
                if(!e2.get()) {
-               logger.debug(location, duccId, "Error reading file: "+fileName);
+               //logger.debug(location, duccId, "Error reading file: 
"+fileName);
                e2.set(true);;
             }
         }
@@ -201,7 +199,7 @@ public class DuccPropertiesResolver {
     }
     
     private Properties getPrivateProperties() {
-       String location = "getPrivateProperties";
+       //String location = "getPrivateProperties";
        Properties privateProperties = new Properties();
        String key = ducc_private_resources;
        String directory = getProperty(key);
@@ -214,29 +212,29 @@ public class DuccPropertiesResolver {
                 privateProperties.load(fis);
                 fis.close();
                 if(loadedPrivate.get()) {
-                       logger.debug(location, duccId, "Reloaded: "+fileName);
+                       //logger.debug(location, duccId, "Reloaded: "+fileName);
                 }
                 else {
-                       logger.debug(location, duccId, "Loaded: "+fileName);
+                       //logger.debug(location, duccId, "Loaded: "+fileName);
                 }
                 loadedPrivate.set(true);
             } 
             catch (FileNotFoundException e) {
                if(!e3.get()) {
-                       logger.debug(location, duccId, "File not found: 
"+fileName);
+                       //logger.debug(location, duccId, "File not found: 
"+fileName);
                        e3.set(true);;
                 }
             } 
                catch (IOException e) {
                        if(!e4.get()) {
-                       logger.debug(location, duccId, "Error reading file: 
"+fileName);
+                       //logger.debug(location, duccId, "Error reading file: 
"+fileName);
                        e4.set(true);;
                 }
             }
        }
        else {
                if(!e5.get()) {
-               logger.debug(location, duccId, "Key not found: "+key);
+               //logger.debug(location, duccId, "Key not found: "+key);
                e5.set(true);;
             }
        }

Modified: 
uima/sandbox/uima-ducc/trunk/uima-ducc-sm/src/main/java/org/apache/uima/ducc/sm/PingDriver.java
URL: 
http://svn.apache.org/viewvc/uima/sandbox/uima-ducc/trunk/uima-ducc-sm/src/main/java/org/apache/uima/ducc/sm/PingDriver.java?rev=1634635&r1=1634634&r2=1634635&view=diff
==============================================================================
--- 
uima/sandbox/uima-ducc/trunk/uima-ducc-sm/src/main/java/org/apache/uima/ducc/sm/PingDriver.java
 (original)
+++ 
uima/sandbox/uima-ducc/trunk/uima-ducc-sm/src/main/java/org/apache/uima/ducc/sm/PingDriver.java
 Mon Oct 27 18:21:39 2014
@@ -591,6 +591,10 @@ class PingDriver
                 cp = cp + ":" + dh + "/lib/uima-ducc/" + j;
                 continue;
             }
+            if ( j.contains("ducc-common") ) {
+                cp = cp + ":" + dh + "/lib/uima-ducc/" + j;
+                continue;
+            }
         }
 
         try {

Modified: 
uima/sandbox/uima-ducc/trunk/uima-ducc-sm/src/main/java/org/apache/uima/ducc/sm/ServiceHandler.java
URL: 
http://svn.apache.org/viewvc/uima/sandbox/uima-ducc/trunk/uima-ducc-sm/src/main/java/org/apache/uima/ducc/sm/ServiceHandler.java?rev=1634635&r1=1634634&r2=1634635&view=diff
==============================================================================
--- 
uima/sandbox/uima-ducc/trunk/uima-ducc-sm/src/main/java/org/apache/uima/ducc/sm/ServiceHandler.java
 (original)
+++ 
uima/sandbox/uima-ducc/trunk/uima-ducc-sm/src/main/java/org/apache/uima/ducc/sm/ServiceHandler.java
 Mon Oct 27 18:21:39 2014
@@ -1157,9 +1157,9 @@ public class ServiceHandler
                 case Modify:
                     // used by CLI only, won't even be passed in
                     continue;
-                case Activate:
+                //case Activate:
                     // TODO: I don't think this is ever used.  Maybe just drop 
it?
-                    continue;
+                    //continue;
             }
 
             String v = (String) mods.get(kk);

Modified: 
uima/sandbox/uima-ducc/trunk/uima-ducc-sm/src/main/java/org/apache/uima/ducc/sm/ServicePingMain.java
URL: 
http://svn.apache.org/viewvc/uima/sandbox/uima-ducc/trunk/uima-ducc-sm/src/main/java/org/apache/uima/ducc/sm/ServicePingMain.java?rev=1634635&r1=1634634&r2=1634635&view=diff
==============================================================================
--- 
uima/sandbox/uima-ducc/trunk/uima-ducc-sm/src/main/java/org/apache/uima/ducc/sm/ServicePingMain.java
 (original)
+++ 
uima/sandbox/uima-ducc/trunk/uima-ducc-sm/src/main/java/org/apache/uima/ducc/sm/ServicePingMain.java
 Mon Oct 27 18:21:39 2014
@@ -27,11 +27,12 @@ import java.io.StringReader;
 import java.io.StringWriter;
 import java.net.Socket;
 import java.net.UnknownHostException;
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.uima.ducc.cli.AServicePing;
+import org.apache.uima.ducc.cli.CommandLine;
+import org.apache.uima.ducc.cli.IUiOption;
 import org.apache.uima.ducc.cli.ServiceStatistics;
 import org.apache.uima.ducc.common.IServiceStatistics;
 import org.apache.uima.ducc.common.utils.DuccProperties;
@@ -56,34 +57,79 @@ public class ServicePingMain
     int error_max = 10;
     int error_count = 0;
 
-    DuccProperties clioptions = new DuccProperties();
-    static final String None = "None";
+    CommandLine command_line = null;
+
+    enum OptionSet
+        implements IUiOption
+    {
+        Class   { 
+            public String pname()       { return "class"; } 
+            public String argname()     { return "Java classname"; }
+            public boolean required()   { return true; }
+            public String description() { return "This is the name of the 
class implementing the pinger"; }
+            public String example()     { return "org.bob.PingClass"; }
+        },
+        Endpoint   { 
+            public String pname()       { return "endpoint"; } 
+            public String argname()     { return "string"; }
+            public boolean required()    { return true; }
+            public String description() { return "Thsi is the endpoint 
specified in teh registration."; }
+            public String example()     { return 
"UIMA-AS:MyUimaAsEndpoint:/tcp//broker1:1234"; }
+        },
+        Port   { 
+            public String pname()       { return "port"; } 
+            public String argname()     { return "integer"; }
+            public boolean required()   { return true; }
+            public String description() { return "This is the port the broker 
is listening on."; }
+            public String example()     { return "12345"; }
+            public String label()       { return name(); }
+        },
+        Arguments   { 
+            public String pname()       { return "arguments"; } 
+            public String argname()     { return "string"; }
+            public String description() { return "Argument string from pinger 
registration, if any."; }
+        },
+        Initprops   { 
+            public String pname()       { return "initprops"; } 
+            public String argname()     { return "string"; }
+            public String description() { return "Initialization properties, 
if any."; }
+        },
+        ;
+        public boolean multiargs() { return false; } // the option can have >1 
arg
+        public boolean required()  { return false; } // this option is required
+        public String  deflt()     { return null; }  // default, or ""
+        public String  label()     { return null; }  // Parameter name for 
label in web form
+        public String  sname()     { return null; }  // short name of option
+        public boolean optargs()   { return false; } // is the argument 
optional?
+        public boolean noargs()    { return false; }
+        public String  example()   { return null; }
+
+        public String makeDesc()
+        {
+            if ( example() == null ) return description();
+            return description() + "\nexample: " + example();
+        }
+    };
+
+    IUiOption[] options = {
+        OptionSet.Class,
+        OptionSet.Endpoint,
+        OptionSet.Port,
+        OptionSet.Arguments,
+        OptionSet.Initprops,
+    };
 
     public ServicePingMain()
     {
-       clioptions.put("--class", clioptions);
-       clioptions.put("--endpoint", clioptions);
-       clioptions.put("--port", clioptions);
-       clioptions.put("--arguments", None);
-       clioptions.put("--initprops", clioptions);
     }
 
-    static void usage()
+    public void usage()
     {
-
-        System.out.println("Usage:");
-        System.out.println("   java org.apache.uima.ducc.smnew.ServicePingMain 
<args>");
-        System.out.println("Where args are:");
-        System.out.println("   --class     classname       This is the class 
implementing the pinger.");
-        System.out.println("   --endpoint  ep              This is the 
endpoint specified in the registration.");
-        System.out.println("   --port      port            This is the listen 
port the SM is listening on.");
-        System.out.println("   --arguments classname       These are the 
arguments for the pinger, supplied in the registration.");
-        System.out.println("   --initprops props           These are 
initialization properties passed from SM, in serialized properties format.");
-        
+        
System.out.println(command_line.formatHelp(this.getClass().getName()));        
         System.exit(1);
     }
 
-    static void appendStackTrace(StringBuffer s, Throwable t)
+    void appendStackTrace(StringBuffer s, Throwable t)
     {
        s.append("\nAt:\n");
         StackTraceElement[] stacktrace = t.getStackTrace();
@@ -95,7 +141,7 @@ public class ServicePingMain
     }
     
     
-    public static void print(Object ... args)
+    public void print(Object ... args)
     {
        StringBuffer s = new StringBuffer();
         for ( Object a : args ) {
@@ -143,53 +189,53 @@ public class ServicePingMain
         }
     }
 
-    /**
-     * Simple argument parser for this class.  It is spawned only by SM so 
even though we do
-     * validity checking, we assume the args are correct and complete, and 
just crash hard if not as
-     * it's an internal error that should not occur.
-     */
-    void parseOptions(String[] args)
-    {
-        // First read them all in
-        if ( debug ) {
-            for ( int i = 0; i < args.length; i++ ) {
-                print("Args[" + i + "] = ", args[i]);
-            }
-        }
-
-        for ( int i = 0; i < args.length; ) {
-            if ( clioptions.containsKey(args[i]) ) {
-                Object o = clioptions.get(args[i]);
-                if ( (o != clioptions) && ( o != None ) ) {
-                    System.out.println("Duplicate argument, not allowed: " + 
args[i]);
-                    System.exit(1);
-                }
-                System.out.println("Put " + args[i] + ", " + args[i+1]);
-                clioptions.put(args[i], args[i+1]);
-                i += 2;
-            } else {
-                System.out.println("Invalid argument: " + args[i]);
-                System.exit(1);
-            }
-        }
-
-        // Now make sure they all exist
-        ArrayList<String> toRemove = new ArrayList<String>();
-        for ( Object o : clioptions.keySet()) {
-            String k = (String) o;
-            Object v = clioptions.get(k);
-            if ( v == clioptions ) {
-                System.out.println("Missing argument: " + k);
-                System.exit(1);
-            }
-            if ( v == None ) {             // optional arg, we want fetches to 
return null if it wasn't set 
-                toRemove.add(k);
-            }
-        }
-        for ( String k : toRemove ) {
-            clioptions.remove(k);
-        }
-    }
+    // /**
+    //  * Simple argument parser for this class.  It is spawned only by SM so 
even though we do
+    //  * validity checking, we assume the args are correct and complete, and 
just crash hard if not as
+    //  * it's an internal error that should not occur.
+    //  */
+    // void parseOptions(String[] args)
+    // {
+    //     // First read them all in
+    //     if ( debug ) {
+    //         for ( int i = 0; i < args.length; i++ ) {
+    //             print("Args[" + i + "] = ", args[i]);
+    //         }
+    //     }
+
+    //     for ( int i = 0; i < args.length; ) {
+    //         if ( clioptions.containsKey(args[i]) ) {
+    //             Object o = clioptions.get(args[i]);
+    //             if ( (o != clioptions) && ( o != None ) ) {
+    //                 System.out.println("Duplicate argument, not allowed: " 
+ args[i]);
+    //                 System.exit(1);
+    //             }
+    //             System.out.println("Put " + args[i] + ", " + args[i+1]);
+    //             clioptions.put(args[i], args[i+1]);
+    //             i += 2;
+    //         } else {
+    //             System.out.println("Invalid argument: " + args[i]);
+    //             System.exit(1);
+    //         }
+    //     }
+
+    //     // Now make sure they all exist
+    //     ArrayList<String> toRemove = new ArrayList<String>();
+    //     for ( Object o : clioptions.keySet()) {
+    //         String k = (String) o;
+    //         Object v = clioptions.get(k);
+    //         if ( v == clioptions ) {
+    //             System.out.println("Missing argument: " + k);
+    //             System.exit(1);
+    //         }
+    //         if ( v == None ) {             // optional arg, we want fetches 
to return null if it wasn't set 
+    //             toRemove.add(k);
+    //         }
+    //     }
+    //     for ( String k : toRemove ) {
+    //         clioptions.remove(k);
+    //     }
+    // }
 
     /**
      * Convert the initialization props into a map<string, object>
@@ -266,15 +312,15 @@ public class ServicePingMain
        protected int start(String[] args)
     {
 
-
+        command_line = new CommandLine(args, options);
+        command_line.parse();
         IServiceStatistics default_statistics = new ServiceStatistics(false, 
false, "<N/A>");
 
-        parseOptions(args);
-        String arguments = clioptions.getProperty("--arguments");
-        String pingClass = clioptions.getStringProperty("--class");
-        String endpoint  = clioptions.getStringProperty("--endpoint");
-        int port         = clioptions.getIntProperty   ("--port");
-        String initters  = clioptions.getStringProperty("--initprops");
+        String arguments = command_line.get   (OptionSet.Arguments);
+        String pingClass = command_line.get   (OptionSet.Class);
+        String endpoint  = command_line.get   (OptionSet.Endpoint);
+        int port         = command_line.getInt(OptionSet.Port);
+        String initters  = command_line.get   (OptionSet.Initprops);
         Map<String, Object> initprops = stringToProperties(initters);
 
         Socket sock = null;

Added: 
uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/dispatcher/ClassManager.java
URL: 
http://svn.apache.org/viewvc/uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/dispatcher/ClassManager.java?rev=1634635&view=auto
==============================================================================
--- 
uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/dispatcher/ClassManager.java
 (added)
+++ 
uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/dispatcher/ClassManager.java
 Mon Oct 27 18:21:39 2014
@@ -0,0 +1,439 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+*/
+package org.apache.uima.ducc.transport.dispatcher;
+
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ClassManager
+{
+    private boolean DEBUG = false;
+    private String DUCC_HOME = null;
+    private URL[] urls = null;
+    private ClassLoader classloader = null;
+
+    private String[] private_classpath;
+
+    public ClassManager(String[] cp)
+        throws Exception
+    {
+        DUCC_HOME = System.getProperty("DUCC_HOME");
+        if ( DUCC_HOME == null ) {
+            throw new IllegalStateException("Internal error: DUCC_HOME must be 
set as a system property.");
+        }
+
+        this.private_classpath = cp;
+        make_urls();
+        HttpClassLoader top = new HttpClassLoader(urls, 
ClassLoader.getSystemClassLoader().getParent());
+        classloader = new PrivateClassLoader(this.getClass().getClassLoader(), 
top);
+        Thread.currentThread().setContextClassLoader(classloader);
+        if ( DEBUG ) System.out.println("Context class loader set to " + 
classloader);
+    }
+
+    private void expand_wildcards(List<URL> in, String cp_entry)
+       throws Exception        
+    {
+       //
+       // We implement simple * wild-card
+       // - list the enclosing directory
+       // - get list of things matching PATH*
+       // - if thing is directory, add all its contents to the returned list 
of paths
+       // - if thing is file, add single entry to the list
+       // - if not found, throw, because it is an internal DUCC error to look 
for stuff that
+       //   can't exist
+       //
+       
+        // First, everything in cp MUST be inside DUCC_HOME
+        // TODO: Logic to get DUCC_HOME needs to be copied into this code in 
order to bypass
+        //       dependencies on other DUCC libraries in the public part of 
the CLI.
+
+        String path = DUCC_HOME + "/" + cp_entry;
+        if ( ! path.endsWith("*") ) {
+            File f = new File(path);
+            if ( ! f.exists() ) {
+                throw new IllegalStateException("Internal error: cannot find 
private classpath entry " + path);
+            }
+
+            if ( f.isFile() ) {
+                // System.out.println("FILE: Adding " + f + " to generated 
classpath.");
+                in.add(f.toURI().toURL());
+            } else  if ( f.isDirectory() ) {
+                if ( !path.endsWith("/") ) path = path + "/";
+                in.add(f.toURI().toURL());
+            }
+            return;
+        }
+
+        cp_entry = cp_entry.substring(0, cp_entry.length()-1);
+        int ndx = path.lastIndexOf("/");
+        String p = path.substring(0, ndx);
+        File parent = new File(p);
+        if ( parent.isDirectory() ) {
+            File[] contents = parent.listFiles();
+            for (File f : contents ) {
+                // System.out.println("Found file " + f);
+
+                // If it's a directory then skip it, these need explicit 
mention
+                // Otherwise try a 'startswith' match and if it matches, add 
to the returned list
+                
+                if ( f.isDirectory() ) continue;
+
+                if ( f.toString().contains(cp_entry)) {
+                    // System.out.println("Adding " + f + " to generated 
classpath.");
+                    in.add(f.toURI().toURL());
+                    continue;
+                } else {
+                       // System.out.println("Skipping cp entry " + cp_entry);
+                }
+            }
+        } else {
+            throw new Exception("Internal error: cannot find private classpath 
directory " + parent);
+        }
+        // System.exit(0);
+    }
+
+    private void make_urls()
+       throws Exception
+    {
+        
+        List<URL> urlList = new ArrayList<URL>();
+        
+        for ( String elem : private_classpath ) {
+            expand_wildcards(urlList, elem);
+        }
+        
+        urls = urlList.toArray(new URL[urlList.size()]);
+    }
+
+    private int level = 0;
+       private void listLoaders(ClassLoader cl)
+    {
+        // Debug only, it's only unused sometimes
+        System.out.println("Loader at level " + level + " is " + cl);
+        if ( cl.getParent() != null ) {
+            level++;
+            listLoaders(cl.getParent());
+        }
+    }
+
+    public Class<?> loadClass(String name)
+       throws MalformedURLException,
+       ClassNotFoundException    
+    {        
+        if ( DEBUG ) {
+            System.out.println("app_loader");
+            level = 0;
+            listLoaders(classloader);
+        }
+
+        // This should prevent the usual "default" classloader with the users 
gorp from sneaking in via
+        // classloaders in the stuff we bring in, such as log4j
+        Thread.currentThread().setContextClassLoader(classloader);
+
+        if ( DEBUG ) {            
+            System.out.println("app_loader is " + classloader);
+            System.out.println("My loader is " + getClass().getClassLoader());
+            System.out.println("System class loader is " + 
ClassLoader.getSystemClassLoader());
+            level = 0;
+            listLoaders(classloader);
+        }
+
+        // return app_loader.loadClass(name);
+        return Class.forName(name, true, classloader);
+    }
+
+
+    private boolean argumentsMatch(Class<?>[] cparms, Object[] args)
+    {
+        if ( cparms.length != args.length ) return false;
+
+        for ( int i = 0; i < cparms.length; i++ ) {
+               Class<?> cl = null;
+               if ( args[i] == null ) {
+                       cl = null;
+               } else {
+                cl = args[i].getClass();
+               }
+               
+               if ( !cparms[i].isPrimitive() && (cl == null) ) continue; // 
we'll assume everything we pass in now is assignable to null
+               
+            if ( !cparms[i].isAssignableFrom(cl) ) return false;
+
+            Class<?>[] declared = cl.getClasses();
+            for ( int j = 0; j < declared.length; j++ ) {
+                if ( DEBUG ) System.out.println("Check argument match cparms: 
" + cparms[i] + " with " + declared[j]);
+                if ( cparms[i].isAssignableFrom(declared[j]) ) return true;
+            }                                                
+        }
+        return true;
+    }
+
+
+    /**
+     * Constructor with arguments.
+     */
+       public Object construct(String name, Object[] args)
+       throws Exception
+    {
+        Class<?> cls = loadClass(name);
+
+        if ( DEBUG ) System.out.println("Context class loader: " + 
Thread.currentThread().getContextClassLoader());
+
+        Constructor<?> cons = null;
+        Constructor<?>[] allConstructors = cls.getConstructors();
+        for ( Constructor<?> c : allConstructors ) {
+            if ( DEBUG ) System.out.println("Constructor for " + name + " : " 
+ c);
+            Class<?>[] cparms = c.getParameterTypes();
+
+            if ( DEBUG ) {
+                for ( Class<?> cc : cparms ) {
+                    System.out.println("   takes parameter " + cc.getName() + 
" : from " + cc.getClassLoader());
+                }
+            }
+
+            if ( cparms.length != args.length ) {
+                if ( DEBUG ) System.out.println("Constructor " + c + " is not 
viable because argument length differs.");
+                continue;
+
+            }
+            if ( argumentsMatch(cparms, args) ) {
+                cons = c;
+                break;
+            }
+
+        }
+        if ( cons == null ) {
+            throw new ClassNotFoundException(name + " has no compatible 
arguments.");
+        } 
+        if ( DEBUG ) System.out.println("Use constructor " + cons);
+        
+        Object o = cons.newInstance(args);
+        return o;
+    }
+
+    /**
+     * No args constructor
+     */
+    public Object construct(String name)
+       throws Exception
+    {
+        Class<?> cls = loadClass(name);
+
+        if ( DEBUG ) System.out.println("Context class loader: " + 
Thread.currentThread().getContextClassLoader());
+        
+        return cls.newInstance();
+    }
+
+    public Object invoke(Object obj, String meth) 
+        throws Exception
+    {
+        return invoke(obj, meth, null);
+    }
+
+    public Object invoke(Object obj, String meth, Object[] args) 
+        throws Exception
+    {
+        Method m = null;
+        if ( args != null ) {
+            Method[] methods = obj.getClass().getMethods();
+            for ( Method mm : methods ) {
+                if ( !mm.getName().equals(meth) ) continue;
+
+                Class<?>[] cparms = mm.getParameterTypes();
+                if ( argumentsMatch(cparms, args ) ) {
+                       m = mm;
+                       break;
+                }
+            }
+
+            if ( m == null ) throw new NoSuchMethodException(meth);
+            // Class<?>[] cl_args= new Class[args.length];
+            // for ( int i = 0; i < args.length; i++ ) {
+            //     cl_args[i] = args[i].getClass();
+            // } 
+            // m = obj.getClass().getMethod(meth, cl_args);
+        } else {
+            m = obj.getClass().getMethod(meth);
+        }
+
+        Object ret = m.invoke(obj, args);
+        return ret;
+    }
+
+    public Object invokex(Object obj, String meth, Object[] args) 
+        throws Exception
+    {
+        Method m;
+        if ( args != null ) {
+            Class<?>[] cl_args= new Class[args.length];
+            for ( int i = 0; i < args.length; i++ ) {
+                cl_args[i] = args[i].getClass();
+            } 
+            m = obj.getClass().getMethod(meth, cl_args);
+        } else {
+            m = obj.getClass().getMethod(meth);
+        }
+
+        Object ret = m.invoke(obj, args);
+        return ret;
+    }
+
+    void invokeStatic(String cls, String meth, Object[] args)
+        throws Exception
+    {
+        Class<?> cl = loadClass(cls);
+        Class<?>[] cl_args= new Class[args.length];
+        for ( int i = 0; i < args.length; i++ ) {
+            cl_args[i] = args[i].getClass();
+        } 
+        Method m = cl.getMethod(meth, cl_args);
+        m.invoke(null, args);
+    }
+
+
+    class HttpClassLoader
+        extends URLClassLoader
+    {
+
+        ClassLoader parent;
+        HttpClassLoader(URL[] urls, ClassLoader parent)
+        {
+            super(urls, parent);
+            this.parent = parent;
+
+            //for ( URL u : urls ) {
+            //    System.out.println("XStreamClassLoader initializes from " + 
u);
+            // }
+        }
+
+        public Class<?> findClass(final String clname)
+            throws ClassNotFoundException
+        {
+            if ( DEBUG ) System.out.println("--------- HttpClassLoader -- 
Finding class " + clname + " from " + this.getClass() + " " + clname);
+            Class<?> ret = super.findClass(clname);
+            if ( ret == null ) {
+                if ( DEBUG ) {
+                    System.out.println("                                       
   Not found");
+                }
+            } else {
+                if ( DEBUG ) {
+                    System.out.println("                                       
   " + ret.getProtectionDomain().getCodeSource().getLocation());
+                    System.out.println("                                       
   " + ret.getClassLoader());
+                }
+            }
+            return ret;
+        }
+
+    }
+
+    class PrivateClassLoader
+        extends ClassLoader
+    {
+        ClassLoader parent;
+        HttpClassLoader grand_parent;
+        /**
+         * This creates a private class loader that loads only the things
+         * the we publicly expose to the user of the CLI/API.
+         *
+         * The parent loads should be the primal class loader, the parent
+         * of getSystemClassLoader(), which gives access to the base Java
+         * classes.
+         *
+         * There are some interfaces that exist in both the 'public' and
+         * the 'private' cli.  These guys must be loaded by the same
+         * loader regardless of whether public or private classes
+         * implement them, in order to get assignment compatibility.
+         *
+         * So this loader checks, if one of the 'shared' classes is being
+         * loaded, and if so, it loads them off the user's classpath,
+         * i.e. the also_parent loader, i.e. the public classpath, instead
+         * of from the private classpath, to insure assignemnt
+         * compatibility.
+         *
+         */
+        PrivateClassLoader(ClassLoader parent, HttpClassLoader grand_parent)
+        {
+            super(parent);
+            this.parent = parent;
+            this.grand_parent = grand_parent;
+        }
+
+
+        public Class<?> loadClass(String clname)
+               throws ClassNotFoundException
+        {
+            if ( DEBUG ) System.out.println("---- A ------- load class " + 
clname + " from " + this);
+            Class<?> ret =  super.loadClass(clname);
+            if ( DEBUG ) {
+                System.out.println("---- A ------- load class " + clname + " 
returns " + ret );
+                try { 
+                    throw new Exception("Stack trace:");
+                } catch ( Throwable e ) {
+                    e.printStackTrace();
+                    System.out.println("--- A 
-----------------------------------------------------------------------------");
+                }
+            }
+            return ret;
+        }
+
+        public Class<?> loadClass(String clname, boolean resolve)
+               throws ClassNotFoundException
+        {
+
+            if ( DEBUG ) System.out.println("---- B ------- load class " + 
clname + " from " + this);
+            Class<?> ret =  super.loadClass(clname, resolve);
+            if ( DEBUG ) {
+                System.out.println("---- B ------ load class " + clname + " 
returns " + ret);
+                try { 
+                    throw new Exception("Stack trace:");
+                } catch ( Throwable e ) {
+                    e.printStackTrace();
+                    System.out.println("---- B 
-----------------------------------------------------------------------------");
+                }
+            }
+            return ret;
+        }
+
+
+        public Class<?> findClass(final String clname)
+            throws ClassNotFoundException
+        {
+            if ( DEBUG ) System.out.println("*********** find class ********** 
" + clname);
+            // we want all the interfaces from "common" except UIOptions and 
IDuccMonitor which aren't well-placed
+            // for this exercise so we need a special case for them
+            Class<?> ret = grand_parent.findClass(clname);
+            if ( ret == null ) {
+                if ( DEBUG ) {
+                    System.out.println("*********** Looking in " + parent + " 
for " + clname);
+                }
+                return super.findClass(clname);
+            } else {
+                return ret;
+            }
+        }
+
+    }
+
+}

Modified: 
uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/dispatcher/DuccEventHttpDispatcher.java
URL: 
http://svn.apache.org/viewvc/uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/dispatcher/DuccEventHttpDispatcher.java?rev=1634635&r1=1634634&r2=1634635&view=diff
==============================================================================
--- 
uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/dispatcher/DuccEventHttpDispatcher.java
 (original)
+++ 
uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/dispatcher/DuccEventHttpDispatcher.java
 Mon Oct 27 18:21:39 2014
@@ -15,22 +15,26 @@
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
-*/
+ */
 package org.apache.uima.ducc.transport.dispatcher;
 
+
 import java.io.BufferedInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
 
-import org.apache.commons.httpclient.HttpClient;
-import org.apache.commons.httpclient.HttpVersion;
-import org.apache.commons.httpclient.methods.PostMethod;
-import org.apache.commons.httpclient.methods.RequestEntity;
-import org.apache.commons.httpclient.methods.StringRequestEntity;
 import org.apache.uima.ducc.common.exception.DuccRuntimeException;
-import org.apache.uima.ducc.common.utils.XStreamUtils;
 import org.apache.uima.ducc.transport.event.DuccEvent;
 import org.apache.uima.ducc.transport.event.SubmitJobDuccEvent;
 import org.apache.uima.ducc.transport.event.SubmitJobReplyDuccEvent;
-
+/**
+ * Implementation of the HTTP based dispatcher. Uses commons HTTPClient for 
+ * messaging. The body of each message is converted to a String (xml format).
+ * Default socket timeout is 30 minutes.
+ * 
+ */
 /**
  * Implementation of the HTTP based dispatcher. Uses commons HTTPClient for 
  * messaging. The body of each message is converted to a String (xml format).
@@ -38,80 +42,180 @@ import org.apache.uima.ducc.transport.ev
  * 
  */
 public class DuccEventHttpDispatcher {
-  private PostMethod method;
-  private HttpClient httpclient;
-  static int socketTimeout = 0;  // no timeout
-  static {
-    try {
-      String st;
-      if ( (st = System.getProperty("ducc.cli.httpclient.sotimeout") ) != null 
) {
-        socketTimeout = Integer.parseInt(st);
-      }
-    } catch( Exception e) {
-      
-    }
-  }
-  public DuccEventHttpDispatcher( String targetEndpoint ) throws Exception {
-    this(targetEndpoint, socketTimeout); 
-  }
-  
-  public DuccEventHttpDispatcher( String targetEndpoint, int timeout ) throws 
Exception {
-    httpclient = new HttpClient();
-    method = new PostMethod(targetEndpoint);
-    httpclient.getParams().setParameter("http.protocol.version", 
HttpVersion.HTTP_1_1);
-    httpclient.getParams().setParameter("http.socket.timeout", timeout);
-    httpclient.getParams().setParameter("http.protocol.content-charset", 
"UTF-8");
-  }
+    
+    private ClassManager classManager = null;
+    private String targetEndpoint;
+
+    String[] classpath = {
+        "lib/apache-camel/xstream*",
+        "lib/google-gson/gson*",
+    };        
 
-    public DuccEvent dispatchAndWaitForDuccReply(DuccEvent duccEvent) 
+    int socketTimeout = 0;  // no timeout
+
+    public DuccEventHttpDispatcher( String targetEndpoint ) 
+        throws Exception 
+    {
+        this(targetEndpoint, -1);
+    }
+    
+    public DuccEventHttpDispatcher( String targetEndpoint, int timeout ) 
+        throws Exception 
+    {
+        this.targetEndpoint = targetEndpoint;
+        // System.out.println("ENDPOINT: " + targetEndpoint);
+        if ( timeout == -1 ) {
+            String st = System.getProperty("ducc.cli.httpclient.sotimeout");
+            if (st != null ) {
+                socketTimeout = Integer.parseInt(st);
+            }
+        } else {
+            socketTimeout = timeout;
+        }
+
+        classManager = new ClassManager(classpath);
+    }
+
+    String toXml(Object ev)
+        throws Exception
+    {        
+        //  DomDriver dd = new DomDriver();
+
+        Object dd_obj = 
classManager.construct("com.thoughtworks.xstream.io.xml.DomDriver", new 
Object[] {null});
+
+        //    XStream xStream = new XStream(dd);
+        Object   xStream_obj = 
classManager.construct("com.thoughtworks.xstream.XStream", new Object[] 
{dd_obj});
+
+        //    return xStream.toXML(ev);
+        return (String) classManager.invoke(xStream_obj, "toXML", new Object[] 
{ev});
+    }
+
+    Object fromXml(String str)
+        throws Exception
+    {        
+        //  DomDriver dd = new DomDriver();
+        Object   dd_obj = 
classManager.construct("com.thoughtworks.xstream.io.xml.DomDriver", new 
Object[] {null});
+
+        //    XStream xStream = new XStream(dd);
+        Object   xStream_obj = 
classManager.construct("com.thoughtworks.xstream.XStream", new Object[] 
{dd_obj});
+
+        //    return xStream.fromXML(str);
+        return classManager.invoke(xStream_obj, "fromXML", new Object[] 
{str});        
+    }
+
+    public String dispatch(String outgoing, String content_type)
         throws Exception
     {
-        String serBody = XStreamUtils.marshall(duccEvent);
-        RequestEntity re = new StringRequestEntity(serBody,"application/xml", 
"UTF8");
-        method.setRequestEntity(re);
-        method.setRequestHeader("Content-Type", "text/xml");
-        httpclient.executeMethod(method);
-        
-        //System.out.println("Client Received Reply of 
type:"+method.getStatusLine().getStatusCode());
-        if ( method.getStatusLine().getStatusCode() == 200 ) {
-
-            //        Header[] headers = method.getResponseHeaders();
-            //        for ( Header h : headers ) {
-            //            System.out.println("Response: " + h.toString());
-            //        }
+ 
+        // String serBody = XStreamUtils.marshall(duccEvent);
+        // String serBody = toXml(duccEvent);
+
+        URL url = new URL(targetEndpoint);
+        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+        if ( outgoing != null ) {             // if not null, we POST.  GET is 
default.
+            //System.out.println(targetEndpoint + " using POST");
+            //System.out.println("-------------- POST body ---------------");
+            //System.out.println(outgoing);
+            //System.out.println("----- end ---- POST body ---------------");
+            conn.setRequestProperty("Content-Type", content_type);
+            conn.setDoOutput(true);           // post
+            // conn.setRequestProperty("Content-Type", "text/xml");
+            OutputStream postout = conn.getOutputStream();
+            postout.write(outgoing.getBytes());
+            postout.close();
+        } else {
+            // System.out.println(targetEndpoint + " using GET");
+        }
+
+        int status = conn.getResponseCode();          // this will fire the 
connection
+
+        if ( status == 200 ) {
+            // System.out.println("Response headers:");
+            //Map<String, List<String>> headers = conn.getHeaderFields();
+            //for ( String s : headers.keySet() ) {
+                //List<String> values = headers.get(s);
+                // System.out.print("    " + s + ": ");
+                // for ( String v : values ) System.out.print(v + " ");
+                // System.out.println("\n");
+
+                //if ( (s != null ) && s.equals("ContentType") ) { // nullkey! 
its the HTTP/1.1 200 OK header which is un-named
+                    
+                //}
+            //}
+
+            
+            InputStream content = conn.getInputStream();
             StringBuffer sb = new StringBuffer();
             byte[] slice = new byte[4096];
             int bytes_read = 0;
-            BufferedInputStream bis = new 
BufferedInputStream(method.getResponseBodyAsStream());
-            while ( (bytes_read = bis.read(slice, 0, slice.length)) != -1 ) {
+            BufferedInputStream bis = new BufferedInputStream(content);
+             while ( (bytes_read = bis.read(slice, 0, slice.length)) != -1 ) {
                 sb.append(new String(slice, 0, bytes_read));
             }
-            return (DuccEvent)XStreamUtils.unmarshall(sb.toString());
+            content.close();
+            
+            String response = sb.toString();
+            // System.out.println("Response: " + response);
+
+            return response;
         } else {
-            String body = method.getResponseBodyAsString();
-            throw new DuccRuntimeException("Ducc Unable to Process Request. 
Http Response Code:"+method.getStatusLine().getStatusCode()+". Ducc Service 
(OR) Returned Exception:",new Exception(body));
-        }
+            String body = conn.getResponseMessage();   // getContent tends to 
throw if status is an error status and there is no body
+            //System.out.println("BODY from failed HTTP request:");
+            //System.out.println("-------------- POST body ---------------");
+            //System.out.println(body);
+            //System.out.println("----- fail --- POST body ---------------");
+
+            throw new DuccRuntimeException("Ducc Unable to Process Request. 
Http Response Code: " + status + ". Ducc Service (OR) Returned Exception:",new 
Exception(body));
+        }        
     }
 
-  /**
-   * Must call this if done using this class
-   */
-  public void close() {
-    if ( method != null ) {
-      method.releaseConnection();
-    }
-  }
-  public static void main(String[] args) {
-    try {
-      DuccEventHttpDispatcher dispatcher = 
-              new 
DuccEventHttpDispatcher("http://"+args[0]+":19988/or",1000*4);
-      SubmitJobDuccEvent duccEvent = new SubmitJobDuccEvent(null, 1);
-      DuccEvent event = dispatcher.dispatchAndWaitForDuccReply(duccEvent);
-      if ( event instanceof SubmitJobReplyDuccEvent ) {
-        System.out.println("Client received SubmitJobReplyDuccEvent");
-      }
-    } catch( Exception e) {
-      e.printStackTrace();
+    public DuccEvent dispatchAndWaitForDuccReply(DuccEvent duccEvent) 
+        throws Exception
+    {
+        String serBody = toXml(duccEvent);
+        String response =  dispatch(serBody, "text/xml");
+        return (DuccEvent) fromXml(response);
+    }
+
+    Object fromJson(String str, Class<?> cl)
+        throws Exception
+    {        
+       //  DomDriver dd = new Gson
+        Object   gson_obj = classManager.construct("com.google.gson.Gson");
+
+        //    return xStream.fromXML(targetToUnmarshall);
+        return classManager.invoke(gson_obj, "fromJson", new Object[] {str, 
cl});        
+    }
+
+
+    public Object dispatchJson(Class<?> cl)
+       throws Exception
+    {
+        // no body, dispatch will use GET
+        String response = dispatch(null, "application/json");  // rfc4627 - 
json mime type
+        return fromJson(response, cl);
+    }
+
+    /**
+     * Must call this if done using this class
+     */
+    public void close() {
+        //if ( method != null ) {
+        // method.releaseConnection();
+        //}
+    }
+    public static void main(String[] args) {
+        try {
+            DuccEventHttpDispatcher dispatcher = 
+                new 
DuccEventHttpDispatcher("http://"+args[0]+":19988/or",1000*4);
+            SubmitJobDuccEvent duccEvent = new SubmitJobDuccEvent(null, 1);
+            DuccEvent event = 
dispatcher.dispatchAndWaitForDuccReply(duccEvent);
+            if ( event instanceof SubmitJobReplyDuccEvent ) {
+                System.out.println("Client received SubmitJobReplyDuccEvent");
+            }
+        } catch( Exception e) {
+            e.printStackTrace();
+        }
     }
-  }
+    
 }

Modified: 
uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/ServiceStartEvent.java
URL: 
http://svn.apache.org/viewvc/uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/ServiceStartEvent.java?rev=1634635&r1=1634634&r2=1634635&view=diff
==============================================================================
--- 
uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/ServiceStartEvent.java
 (original)
+++ 
uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/ServiceStartEvent.java
 Mon Oct 27 18:21:39 2014
@@ -25,7 +25,6 @@ public class ServiceStartEvent 
     private int friendly;
     private String epname;
     private int instances;
-    private boolean update;
 
        public ServiceStartEvent(String user, int friendly, String epname, 
byte[] auth_block, int cli_version)
     {
@@ -53,19 +52,8 @@ public class ServiceStartEvent 
         this.instances = instances;
     }
 
-    public boolean getUpdate()
-    {
-        return update;
-    }
-
-    public void setUpdate(boolean update)
-    {
-        this.update = update;
-    }
-
        public String toString() {
-               return "ServiceStartEvent [friendly=" + friendly + ", user=" + 
user + ", instances=" + instances  + ", update=" + update
-                               + "]";
+               return "ServiceStartEvent [friendly=" + friendly + ", user=" + 
user + ", instances=" + instances + "]";
        }
        
 }

Modified: 
uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/ServiceStopEvent.java
URL: 
http://svn.apache.org/viewvc/uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/ServiceStopEvent.java?rev=1634635&r1=1634634&r2=1634635&view=diff
==============================================================================
--- 
uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/ServiceStopEvent.java
 (original)
+++ 
uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/ServiceStopEvent.java
 Mon Oct 27 18:21:39 2014
@@ -26,7 +26,6 @@ public class ServiceStopEvent 
     private long friendly;
     private String epname;
     private int instances;
-    private boolean update;
 
        public ServiceStopEvent(String user, long friendly, String epname, 
byte[] auth_block, int cli_version)
     {
@@ -54,20 +53,9 @@ public class ServiceStopEvent 
         this.instances = instances;
     }
 
-    public boolean getUpdate()
-    {
-        return update;
-    }
-
-    public void setUpdate(boolean update)
-    {
-        this.update = update;
-    }
-
        @Override
        public String toString() {
-               return "ServiceStopEvent [friendly=" + friendly + ", user=" + 
user + ", instances=" + instances + ", update=" + update
-                               + "]";
+               return "ServiceStopEvent [friendly=" + friendly + ", user=" + 
user + ", instances=" + instances +  "]";
        }
        
 }


Reply via email to