You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by cw...@apache.org on 2013/01/02 20:07:54 UTC

svn commit: r1427911 [3/4] - in /uima/sandbox/uima-ducc/trunk/uima-ducc-cli: main/ main/java/ main/java/org/ main/java/org/apache/ main/java/org/apache/uima/ main/java/org/apache/uima/ducc/ main/java/org/apache/uima/ducc/api/ main/java/org/apache/uima/...

Added: uima/sandbox/uima-ducc/trunk/uima-ducc-cli/main/java/org/apache/uima/ducc/cli/DuccServiceApi.java
URL: http://svn.apache.org/viewvc/uima/sandbox/uima-ducc/trunk/uima-ducc-cli/main/java/org/apache/uima/ducc/cli/DuccServiceApi.java?rev=1427911&view=auto
==============================================================================
--- uima/sandbox/uima-ducc/trunk/uima-ducc-cli/main/java/org/apache/uima/ducc/cli/DuccServiceApi.java (added)
+++ uima/sandbox/uima-ducc/trunk/uima-ducc-cli/main/java/org/apache/uima/ducc/cli/DuccServiceApi.java Wed Jan  2 19:07:53 2013
@@ -0,0 +1,979 @@
+/*
+ * 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;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.Properties;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.OptionBuilder;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.PosixParser;
+import org.apache.uima.ducc.common.IDucc;
+import org.apache.uima.ducc.common.Pair;
+import org.apache.uima.ducc.common.utils.DuccProperties;
+import org.apache.uima.ducc.transport.dispatcher.DuccEventDispatcher;
+import org.apache.uima.ducc.transport.dispatcher.DuccEventHttpDispatcher;
+import org.apache.uima.ducc.transport.event.ServiceModifyEvent;
+import org.apache.uima.ducc.transport.event.ServiceQueryEvent;
+import org.apache.uima.ducc.transport.event.ServiceQueryReplyEvent;
+import org.apache.uima.ducc.transport.event.ServiceRegisterEvent;
+import org.apache.uima.ducc.transport.event.ServiceReplyEvent;
+import org.apache.uima.ducc.transport.event.ServiceStartEvent;
+import org.apache.uima.ducc.transport.event.ServiceStopEvent;
+import org.apache.uima.ducc.transport.event.ServiceUnregisterEvent;
+import org.apache.uima.ducc.transport.event.sm.IService;
+
+
+/**
+ * DUCC service API
+ */
+
+public class DuccServiceApi 
+    implements IService,
+               IServiceApi
+{
+
+    String ducc_home = null;
+     
+    DuccProperties ducc_properties = null;
+    Properties     jvmargs = null;     // -D vars from jvm args, as properties
+
+    //String broker = null;
+    //String jms_provider = "activemq";
+    //String endpoint_name = "ducc.sm.request.endpoint";
+    //String endpoint_type = "ducc.sm.request.endpoint.type";    
+    DuccEventHttpDispatcher dispatcher;
+    
+    String sm_port = "ducc.sm.http.port";
+    String sm_host = "ducc.sm.http.node";
+    String endpoint = null;
+
+    boolean debug = false;
+
+    CamelContext context = null;
+
+    static boolean init_done = false;
+
+    public DuccServiceApi()
+    {
+    }
+
+    static void usage(String msg)
+    {
+        if ( msg != null ) {
+            System.out.println(msg);
+        }
+        System.out.println("Usage:");
+        System.exit(0);
+    }
+
+	static void usage(Options options) 
+    {
+		HelpFormatter formatter = new HelpFormatter();
+		formatter.setWidth(DuccUiConstants.help_width);
+		formatter.printHelp(DuccServiceApi.class.getName(), options);
+	}
+
+	@SuppressWarnings("static-access")
+	private void addOptions(Options options) 
+    {
+        //
+        // Verbs here
+        //
+		options.addOption(OptionBuilder
+                          .withLongOpt    (ServiceVerb.Register.decode())
+                          .withDescription(ServiceVerb.Register.description())
+                          .withArgName    (ServiceVerb.Register.argname())
+                          .hasOptionalArg ()
+                          .create         ()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (ServiceVerb.Unregister.decode())
+                          .withDescription(ServiceVerb.Unregister.description())
+                          .withArgName    (ServiceVerb.Unregister.argname())
+                          .hasArg         (true)
+                          .create         ()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (ServiceVerb.Start.decode())
+                          .withDescription(ServiceVerb.Start.description())
+                          .withArgName    (ServiceVerb.Start.argname())
+                          .hasArg         (true)
+                          .create         ()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (ServiceVerb.Stop.decode())
+                          .withDescription(ServiceVerb.Stop.description())
+                          .withArgName    (ServiceVerb.Stop.argname())
+                          .hasArg         (true)
+                          .create         ()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (ServiceVerb.Modify.decode())
+                          .withDescription(ServiceVerb.Modify.description())
+                          .withArgName    (ServiceVerb.Modify.argname())
+                          .hasArg         (true)
+                          .create         ()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (ServiceVerb.Query.decode())
+                          .withDescription(ServiceVerb.Query.description())
+                          .hasOptionalArg()
+                          .create()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (ServiceVerb.Debug.decode())
+                          .withDescription(ServiceVerb.Debug.description())
+                          .hasArg         (false)
+                          .create         ()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (ServiceVerb.Help.decode())
+                          .withDescription(ServiceVerb.Help.description())
+                          .hasArg         (false)
+                          .create         ()
+                          );
+
+        //
+        // Options here
+        //
+		options.addOption(OptionBuilder
+                          .withLongOpt    (ServiceOptions.Autostart.decode())
+                          .withDescription(ServiceOptions.Autostart.description())
+                          .withArgName    (ServiceOptions.Autostart.argname())
+                          .withDescription("Change autostart setting for registered service.")
+                          .hasArg(true)
+                          .create()
+                          );
+
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (ServiceOptions.Instances.decode())
+                          .withDescription(ServiceOptions.Instances.description())
+                          .withArgName    (ServiceOptions.Instances.argname())
+                          .hasArg(true)
+                          .create()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (ServiceOptions.Activate.decode())
+                          .withDescription(ServiceOptions.Activate.description())
+                          .withArgName    (ServiceOptions.Activate.argname())
+                          .hasArg(false)
+                          .create()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (ServiceOptions.Update.decode())
+                          .withDescription(ServiceOptions.Update.description())
+                          .withArgName    (ServiceOptions.Update.argname())
+                          .hasArg(false)
+                          .create()
+                          );
+
+
+        //
+        // Services options that more correctly belong in properties file here
+        //
+        // description
+        // process_DD
+        // process_memory_size
+        // process_classpath
+        // process_jvm_args
+        // process_environment
+        // process_failures_limit
+        // scheduling_class
+        // working directory
+        // log_directory
+        // jvm
+        // service_dependency
+        // Other directives are not supported for registered services.
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (RegistrationOption.Description.decode()) 
+                          .withDescription(RegistrationOption.Description.description()) 
+                          .withArgName    (RegistrationOption.Description.argname())
+                          .hasArg(true)
+                          .create()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (RegistrationOption.ProcessDD.decode()) 
+                          .withDescription(RegistrationOption.ProcessDD.description()) 
+                          .withArgName    (RegistrationOption.ProcessDD.argname())
+                          .hasArg(true)
+                          .create()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (RegistrationOption.ProcessMemorySize.decode()) 
+                          .withDescription(RegistrationOption.ProcessMemorySize.description()) 
+                          .withArgName    (RegistrationOption.ProcessMemorySize.argname())
+                          .hasArg(true)
+                          .create()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (RegistrationOption.ProcessClasspath.decode()) 
+                          .withDescription(RegistrationOption.ProcessClasspath.description()) 
+                          .withArgName    (RegistrationOption.ProcessClasspath.argname())
+                          .hasArg(true)
+                          .create()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (RegistrationOption.ProcessJvmArgs.decode()) 
+                          .withDescription(RegistrationOption.ProcessJvmArgs.description()) 
+                          .withArgName    (RegistrationOption.ProcessJvmArgs.argname())
+                          .hasArg(true)
+                          .create()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (RegistrationOption.ProcessEnvironment.decode()) 
+                          .withDescription(RegistrationOption.ProcessEnvironment.description()) 
+                          .withArgName    (RegistrationOption.ProcessEnvironment.argname())
+                          .hasArg(true)
+                          .create()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (RegistrationOption.ProcessFailuresLimit.decode()) 
+                          .withDescription(RegistrationOption.ProcessFailuresLimit.description()) 
+                          .withArgName    (RegistrationOption.ProcessFailuresLimit.argname())
+                          .hasArg(true)
+                          .create()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (RegistrationOption.SchedulingClass.decode()) 
+                          .withDescription(RegistrationOption.SchedulingClass.description()) 
+                          .withArgName    (RegistrationOption.SchedulingClass.argname())
+                          .hasArg(true)
+                          .create()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (RegistrationOption.WorkingDirectory.decode()) 
+                          .withDescription(RegistrationOption.WorkingDirectory.description()) 
+                          .withArgName    (RegistrationOption.WorkingDirectory.argname())
+                          .hasArg(true)
+                          .create()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (RegistrationOption.LogDirectory.decode()) 
+                          .withDescription(RegistrationOption.LogDirectory.description()) 
+                          .withArgName    (RegistrationOption.LogDirectory.argname())
+                          .hasArg(true)
+                          .create()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (RegistrationOption.Jvm.decode()) 
+                          .withDescription(RegistrationOption.Jvm.description()) 
+                          .withArgName    (RegistrationOption.Jvm.argname())
+                          .hasArg(true)
+                          .create()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (RegistrationOption.ServiceDependency.decode()) 
+                          .withDescription(RegistrationOption.ServiceDependency.description()) 
+                          .withArgName    (RegistrationOption.ServiceDependency.argname())
+                          .hasArg(true)
+                          .create()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (RegistrationOption.ServiceLinger.decode()) 
+                          .withDescription(RegistrationOption.ServiceLinger.description()) 
+                          .withArgName    (RegistrationOption.ServiceLinger.argname())
+                          .hasArg(true)
+                          .create()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (RegistrationOption.ServiceCustomPing.decode()) 
+                          .withDescription(RegistrationOption.ServiceCustomPing.description()) 
+                          .withArgName    (RegistrationOption.ServiceCustomPing.argname())
+                          .hasArg(true)
+                          .create()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (RegistrationOption.ServiceCustomEndpoint.decode()) 
+                          .withDescription(RegistrationOption.ServiceCustomEndpoint.description()) 
+                          .withArgName    (RegistrationOption.ServiceCustomEndpoint.argname())
+                          .hasArg(true)
+                          .create()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (RegistrationOption.ServiceCustomClasspath.decode()) 
+                          .withDescription(RegistrationOption.ServiceCustomClasspath.description()) 
+                          .withArgName    (RegistrationOption.ServiceCustomClasspath.argname())
+                          .hasArg(true)
+                          .create()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (RegistrationOption.ServiceCustomJvmArgs.decode()) 
+                          .withDescription(RegistrationOption.ServiceCustomJvmArgs.description()) 
+                          .withArgName    (RegistrationOption.ServiceCustomJvmArgs.argname())
+                          .hasArg(true)
+                          .create()
+                          );
+    }
+
+    synchronized protected void init()
+    {
+
+        if ( init_done ) return;
+
+        ducc_home = System.getenv("DUCC_HOME");
+        if ( ducc_home == null ) {
+            usage("DUCC_HOME must be set.");
+        }
+
+        String propsfile = ducc_home + "/resources/ducc.properties";
+        try {
+            ducc_properties = new DuccProperties();
+            ducc_properties.load(propsfile);
+
+            String host = ducc_properties.getStringProperty(sm_host);
+            String port = ducc_properties.getStringProperty(sm_port);
+
+            if ( host == null ) {
+                throw new IllegalStateException(sm_host + " is not set in ducc.properties");
+            }
+        
+            if ( port == null ) {
+                throw new IllegalStateException(sm_port + " is not set in ducc.properties");
+            }
+            
+            String targetUrl = "http://"+ host + ":" + port + "/sm";
+            dispatcher = new DuccEventHttpDispatcher(targetUrl);
+
+//             String en = ducc_properties.getStringProperty(endpoint_name);
+//             String et = ducc_properties.getStringProperty(endpoint_type);
+//             endpoint = jms_provider
+//                 + ":" 
+//                 + et 
+//                 + ":"
+//                 + en;
+
+//             broker = ducc_properties.get("ducc.broker.protocol") 
+//                 + "://"
+//                 + ducc_properties.get("ducc.broker.hostname")
+//                 + ":"
+//                 + ducc_properties.get("ducc.broker.port");
+//             String decoration = ducc_properties.getStringProperty("ducc.broker.url.decoration");
+//             if ( decoration != null ) {
+//                 broker = broker
+//                     + "?"
+//                     + decoration;
+//             }
+        } catch ( Throwable t ) {
+            usage("Error loading configuration: " + t.getMessage());
+        }
+
+//        if ( debug ) {
+//            System.out.println("DUCC_HOME   :  " + ducc_home);
+//            System.out.println("SM Endpoint :  " + endpoint);
+//            System.out.println("Broker      :  " + broker);            
+//        }
+
+        init_done = true;
+    }
+
+    synchronized protected DuccEventDispatcher connect() throws Exception
+    {
+		context = new DefaultCamelContext();
+
+		//ActiveMQComponent amqc = ActiveMQComponent.activeMQComponent(broker);
+        //context.addComponent(jms_provider, amqc);
+        //context.start();
+        DuccEventDispatcher duccEventDispatcher = new DuccEventDispatcher(context, endpoint);
+        return duccEventDispatcher;
+    }
+
+    private Pair<Integer, String> getId(CommandLine cl, ServiceVerb verb)
+    {
+        String sid = cl.getOptionValue(verb.decode());
+        if ( sid == null ) {
+            throw new IllegalArgumentException("Missing id for --" + verb.decode() + ".");
+        }
+        
+        int id = -1;
+        try {
+            id = Integer.parseInt(sid);
+            return new Pair<Integer, String>(id, null);
+        } catch ( NumberFormatException e ) {
+            // nothing
+        }
+        if ( sid.startsWith(ServiceType.UimaAs.decode()) || sid.startsWith(ServiceType.Custom.decode()) ) {
+            return new Pair<Integer, String>(-1, sid);
+        }
+        throw new IllegalArgumentException("Invalid id; must be numeric or start with " + ServiceType.UimaAs.decode() + " or " + ServiceType.Custom.decode() + ".");
+    }
+
+    private int getInstances(CommandLine cl, String deflt)
+    {
+        String nstncs = cl.getOptionValue(ServiceOptions.Instances.decode(), deflt);
+        int instances = 0;
+        try {
+            instances = Integer.parseInt(nstncs);
+        } catch ( NumberFormatException e ) {
+            System.out.println ("--" + ServiceOptions.Instances.decode() + " " + nstncs + " is not numeric.");
+            doExit(1);
+        }
+        return instances;
+    }
+
+    private Trinary getAutostart(CommandLine cl)
+    {
+        String auto = cl.getOptionValue(ServiceOptions.Autostart.decode(), null);
+        if ( auto == null ) {
+            return Trinary.Unset;
+        }
+
+        Trinary answer = Trinary.encode(auto);
+
+        if ( answer == Trinary.Unset ) {
+            System.out.println("--" + ServiceOptions.Autostart.decode()  + " " + auto + " is not 'true' or 'false'");
+            doExit(1);
+        }
+
+        return answer;
+    }
+
+    private boolean getActivate(CommandLine cl)
+    {
+        return cl.hasOption(ServiceOptions.Activate.decode());
+    }
+
+    private boolean getUpdate(CommandLine cl)
+    {
+        return cl.hasOption(ServiceOptions.Update.decode());
+    }
+
+    private void overrideProperties(CommandLine cl, DuccProperties props, RegistrationOption opt)
+    {
+        String k = opt.decode();
+        String v = cl.getOptionValue(k, null);
+        if ( v == null ) return;
+        props.put(k, v);
+    }
+
+    private String getLinger(DuccProperties props)
+    {
+        String kw = RegistrationOption.ServiceLinger.decode();
+        String default_linger = ducc_properties.getStringProperty("ducc.sm.default.linger", "30");
+        String linger = props.getStringProperty(kw, default_linger);
+        long actual = 0;
+        try {             
+            actual = Long.parseLong(linger); // make sure it's an int
+        } catch ( NumberFormatException e ) {
+            throw new IllegalArgumentException(kw + " is not numeric: " + linger);
+        }
+        return Long.toString(actual);
+    }
+
+    synchronized protected DuccProperties getPropsFile(CommandLine cl)
+        throws Throwable
+    {
+        DuccProperties reply = new DuccProperties();
+
+        //
+        // First read the properties file if given in
+        //    ducc_services --register propsfile
+        String props = cl.getOptionValue(ServiceVerb.Register.decode());
+        if ( props != null ) {
+            reply.load(new FileInputStream(props));
+            if ( debug ) {
+                System.out.println("Service specification file:");
+                for ( Object key: reply.keySet() ) {
+                    System.out.println("    Key: " + "Value: " + reply.getStringProperty((String)key));
+                }
+            }            
+        }
+
+        // Must enforce this for registered services
+        reply.put("process_deployments_max", "1");     
+
+        // 
+        // Now pull in the override props.
+        //
+        overrideProperties(cl, reply, RegistrationOption.Description);
+        overrideProperties(cl, reply, RegistrationOption.ProcessDD);
+        overrideProperties(cl, reply, RegistrationOption.ProcessMemorySize);
+        overrideProperties(cl, reply, RegistrationOption.ProcessClasspath);
+        overrideProperties(cl, reply, RegistrationOption.ProcessJvmArgs);
+        overrideProperties(cl, reply, RegistrationOption.ProcessEnvironment);
+        overrideProperties(cl, reply, RegistrationOption.ProcessFailuresLimit);
+        overrideProperties(cl, reply, RegistrationOption.SchedulingClass);
+        overrideProperties(cl, reply, RegistrationOption.WorkingDirectory);
+        overrideProperties(cl, reply, RegistrationOption.LogDirectory);
+        overrideProperties(cl, reply, RegistrationOption.Jvm);
+        overrideProperties(cl, reply, RegistrationOption.ServiceDependency);
+        overrideProperties(cl, reply, RegistrationOption.ServiceLinger);
+        overrideProperties(cl, reply, RegistrationOption.ServiceCustomPing);
+        overrideProperties(cl, reply, RegistrationOption.ServiceCustomEndpoint);
+        overrideProperties(cl, reply, RegistrationOption.ServiceCustomClasspath);
+        overrideProperties(cl, reply, RegistrationOption.ServiceCustomJvmArgs);
+
+        //
+        // Now: let's resolve placeholders.
+        //
+        String jvmarg_string = reply.getProperty(RegistrationOption.ProcessJvmArgs.decode());
+        jvmargs = DuccUiUtilities.jvmArgsToProperties(jvmarg_string);
+        DuccUiUtilities.resolvePropertiesPlaceholders(reply, jvmargs);
+        return reply;
+    }
+
+    /**
+     * @param endpoint This is 'my' service endpoint
+     * @param props    This is the service properties file with the dependencies in it.
+     */
+    void resolve_service_dependencies(String endpoint, Properties props)
+    {
+        String deps = props.getProperty(RegistrationOption.ServiceDependency.decode());
+        deps = DuccUiUtilities.resolve_service_dependencies(endpoint, deps, jvmargs);
+        if ( deps != null ) {
+            props.setProperty(RegistrationOption.ServiceDependency.decode(), deps);
+        }
+    }
+
+    /**
+     * @param props Name of file in standard Java properies format with the service specification.
+     * @return 
+     */
+    public ServiceReplyEvent register(DuccProperties service_props, int instances)
+        throws Exception
+    {
+        //
+        // TODO: Crypto?
+        //
+
+        String k_wd = RegistrationOption.WorkingDirectory.decode();
+        String working_dir = service_props.getStringProperty(k_wd, System.getProperty("user.dir"));
+        service_props.setProperty(k_wd, working_dir);
+
+        // Employ default log directory if not specified
+        String k_ld = RegistrationOption.LogDirectory.decode();
+		String log_directory = service_props.getStringProperty(k_ld, System.getProperty("user.home") + IDucc.userLogsSubDirectory);
+        if( ! log_directory.startsWith(File.separator)) {
+            // relative log directory was specified - default to user's home + relative directory
+            // TODO: This logic comes from submit.  But is it right?  Log dir relative to $HOME instread of job's working dir?
+            if (log_directory.endsWith(File.separator)) {
+                log_directory = System.getProperty("user.home") + log_directory;
+            } else {
+                log_directory = System.getProperty("user.home") + File.separator + log_directory;
+            }
+		}
+
+        // Insure a linger time is set
+        String k_lin = RegistrationOption.ServiceLinger.decode();
+        String linger = getLinger(service_props);
+        service_props.setProperty(k_lin, linger);
+        
+		// tack on "services" to complete logging directory
+        // TODO: Again, from service submit - is it really correct to force "/services" into the path if the
+        //       user specifies the path?
+		// if(log_directory.endsWith(File.separator)) {
+// 			log_directory = log_directory+"services";
+// 		}
+// 		else {
+// 			log_directory = log_directory+File.separator+"services";
+// 		}
+		service_props.setProperty(k_ld, log_directory);
+
+        // establish my endpoint
+        String  endpoint = service_props.getStringProperty(RegistrationOption.ServiceCustomEndpoint.decode(), null);
+        if ( endpoint == null ) {               // not custom ...
+            //
+            // No endpoint, resolve from the DD.
+            //
+
+            //
+            // If claspath is not specified, pick it up from the submitter's environment
+            //            
+            String classpath = service_props.getStringProperty(RegistrationOption.ProcessClasspath.decode(), System.getProperty("java.class.path"));
+            service_props.setProperty(RegistrationOption.ProcessClasspath.decode(), classpath);
+
+            String dd = service_props.getStringProperty(RegistrationOption.ProcessDD.decode());
+            endpoint = DuccUiUtilities.getEndpoint(working_dir, dd, jvmargs);
+            if ( debug ) {
+                System.out.println("Service endpoint resolves to " + endpoint);
+            }
+        } else {
+            String k_scp = RegistrationOption.ServiceCustomClasspath.decode();
+            String classpath = service_props.getStringProperty(k_scp, System.getProperty("java.class.path"));
+            service_props.setProperty(k_scp, classpath);
+
+            if ( ! endpoint.startsWith(ServiceType.Custom.decode()) ) {
+                throw new IllegalArgumentException("Invalid custom endpoint: " + endpoint);
+            }
+            if ( service_props.getProperty(RegistrationOption.ServiceCustomPing.decode()) == null ) {
+                throw new IllegalArgumentException("Custom service is missing ping class name.");
+            }
+        }
+
+        // work out stuff I'm dependendent upon
+        resolve_service_dependencies(endpoint, service_props);
+
+        //
+        // Finally set up the the event object and ship it!
+        //
+        // DuccEventDispatcher dispatcher = connect();
+
+        ServiceRegisterEvent ev = new ServiceRegisterEvent(DuccUiUtilities.getUser(), instances, endpoint, service_props);
+        ServiceReplyEvent reply = null;
+
+        try {
+            reply = (ServiceReplyEvent) dispatcher.dispatchAndWaitForDuccReply(ev);
+        } catch (Exception e) {
+            // TODO: print a nice error.  For now, we spew the stack.
+            e.printStackTrace();
+        } finally {
+            dispatcher.close();
+        }
+
+//         try {
+//         	reply = (ServiceReplyEvent) dispatcher.dispatchAndWaitForDuccReply(ev);
+//         }
+//         finally {
+//         	context.stop();
+//         }
+
+        return reply;
+	}
+
+    /**
+     * @param id The full service id as returned by register
+     * @return 
+     */
+    public ServiceReplyEvent unregister(int intId, String strId)
+        throws Exception
+    {
+        ServiceUnregisterEvent ev = new ServiceUnregisterEvent(DuccUiUtilities.getUser(), intId, strId);
+        //DuccEventDispatcher dispatcher = connect();
+        ServiceReplyEvent reply = null;
+        
+        try {
+            reply = (ServiceReplyEvent) dispatcher.dispatchAndWaitForDuccReply(ev);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            dispatcher.close();
+        }
+
+//         try {
+//         	reply = (ServiceReplyEvent) dispatcher.dispatchAndWaitForDuccReply(ev);
+//         }
+//         finally {
+//         	context.stop();
+//         }
+
+        return reply;
+	}
+
+    /**
+     * @param props Name of file in standard Java properies format with the service specification.
+     * @return 
+     */
+    public ServiceReplyEvent start(int intId, String strId, int instances, boolean update)
+        throws Exception
+    {
+
+        ServiceStartEvent ev = new ServiceStartEvent(DuccUiUtilities.getUser(), intId, strId);
+        ev.setInstances(instances);
+        ev.setUpdate(update);
+        
+        ServiceReplyEvent reply = null;
+        try {
+            reply = (ServiceReplyEvent) dispatcher.dispatchAndWaitForDuccReply(ev);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            dispatcher.close();
+        }
+
+        return reply;
+    }
+
+
+    /**
+     * @param props Name of file in standard Java properies format with the service specification.
+     * @return 
+     */
+    public ServiceReplyEvent stop(int intId, String strId, int instances, boolean update)
+        throws Exception
+    {
+
+        ServiceStopEvent ev = new ServiceStopEvent(DuccUiUtilities.getUser(), intId, strId);
+        ev.setInstances(instances);
+        ev.setUpdate(update);
+        
+        ServiceReplyEvent reply = null;
+        try {
+            reply = (ServiceReplyEvent) dispatcher.dispatchAndWaitForDuccReply(ev);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            dispatcher.close();
+        }
+
+        return reply;
+    }
+
+    /**
+     * @param id The id of a registered service.
+     * @param instances The nubmer of instances of the service to start.
+     * @param autostart Update to autostart status of the registered service.
+     * @return 
+     */
+    public ServiceReplyEvent modify(int intId, String strId, int instances, Trinary autostart, boolean activate)
+        throws Exception
+    {
+
+        ServiceModifyEvent ev = new ServiceModifyEvent(DuccUiUtilities.getUser(), intId, strId);
+        ev.setInstances(instances);
+        ev.setAutostart(autostart);
+        ev.setActivate(activate);
+        
+        ServiceReplyEvent reply = null;
+        try {
+            reply = (ServiceReplyEvent) dispatcher.dispatchAndWaitForDuccReply(ev);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            dispatcher.close();
+        }
+
+        return reply;
+    }
+
+    /**
+     * @param props Name of file in standard Java properies format with the service specification.
+     * @return 
+     */
+    public ServiceQueryReplyEvent query(int intId, String strId)
+        throws Exception
+    {
+        ServiceQueryEvent ev = new ServiceQueryEvent(DuccUiUtilities.getUser(), intId, strId);
+        ServiceQueryReplyEvent reply = null;
+
+        try {
+            reply = (ServiceQueryReplyEvent) dispatcher.dispatchAndWaitForDuccReply(ev);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            dispatcher.close();
+        }
+
+        return reply;
+    }
+
+    synchronized ServiceVerb extract_verb(CommandLine cl)
+    {
+        boolean found_verb = false;
+        ServiceVerb verb = ServiceVerb.Unknown;
+        
+        for ( ServiceVerb v : ServiceVerb.values() ) {
+        	if ( cl.hasOption(v.decode()) ) {
+                if ( found_verb ) {
+                    usage("Duplicate option " + v + ": not allowd.");
+                } else {
+                    found_verb = true;
+                    verb = v;
+                }
+            }
+        }
+
+        return verb;
+    }
+
+    public void print_reply(ServiceVerb verb, ServiceReplyEvent ev)
+    {
+        String result = (ev.getReturnCode() == ServiceCode.OK) ? "succeeded" : "failed";
+        String reason = (ev.getReturnCode() == ServiceCode.OK) ? "" : ": " +ev.getMessage();
+        String action = "Service " + verb.decode();
+        String msg = (action + " " + result + " ID " + ((ev.getId() == null) ? "<none>" : ev.getId().toString()) + " endpoint " + ev.getEndpoint() + reason);
+        switch ( verb ) {
+           case Register:
+           case Unregister:
+           case Start:
+           case Stop:
+           case Modify:
+               System.out.println(msg);
+               break;
+           case Query:
+               System.out.println(ev.toString());
+               break;
+        }
+    }
+
+    public void run(String[] args)
+    	throws Throwable
+    {
+        Options options = new Options();
+        synchronized(this) {
+            addOptions(options);
+        }
+
+        CommandLineParser parser = new PosixParser();
+        CommandLine commandLine = null;
+		try {
+			commandLine = parser.parse(options, args);
+		} catch (ParseException e) {
+            usage("Cannot parse command line: " + e.getMessage());            
+		}
+
+        /*
+         * give help & exit when requested
+         */
+        if (commandLine.hasOption(ServiceVerb.Help.decode())) {
+        	usage(options);
+        }
+
+        if(commandLine.getOptions().length == 0) {
+            usage(options);
+        }
+
+        if (commandLine.hasOption(ServiceVerb.Debug.decode())) {
+            debug = true;
+        }
+        
+        DuccProperties props = null;
+        int instances = 0;
+        boolean activate = false;
+        boolean update = false;
+        Pair<Integer, String> id = null;
+        Trinary autostart;
+        try { 
+            ServiceVerb verb = extract_verb(commandLine);
+            ServiceReplyEvent reply = null;
+            switch ( verb ) {
+                case Register:                    
+                    props = getPropsFile(commandLine);
+                    instances = getInstances(commandLine, "1");
+                    reply = register(props, instances);                    
+                    break;
+                case Unregister:
+                    id = getId(commandLine, verb);
+                    reply = unregister(id.first(), id.second());
+                    break;
+                case Start:
+                    id = getId(commandLine, verb);
+                    instances = getInstances(commandLine, "0");
+                    update = getUpdate(commandLine);
+                    reply = start(id.first(), id.second(), instances, update);                    
+                    break;
+                case Stop:
+                    id = getId(commandLine, verb);
+                    instances = getInstances(commandLine, "0");
+                    update = getUpdate(commandLine);
+                    reply = stop(id.first(), id.second(), instances, update);
+                    break;
+                case Modify:
+                    id = getId(commandLine, verb);
+                    instances = getInstances(commandLine, "0");
+                    autostart = getAutostart(commandLine);
+                    activate  = getActivate(commandLine);
+                    reply = modify(id.first(), id.second(), instances, autostart, activate);
+                    break;
+                case Query:
+                    if (commandLine.getOptionValue(verb.decode()) == null ) {
+                        reply = query(-1, null);
+                    } else {
+                        id = getId(commandLine, verb);
+                        reply = query(id.first(), id.second());
+                    }
+                    break;
+                case Unknown:
+                    throw new IllegalArgumentException("Missing Service verb (--register --unregister --start --stop --query --modify)");
+            }
+            print_reply(verb, reply);
+        } catch ( Throwable t ) {
+        	t.printStackTrace();
+            System.out.println("Service command fails: " + t.getMessage());
+            doExit(1);
+        }
+    }
+
+    //
+    // single common exit point for CL invoction
+    //
+    protected void doExit(int rc)
+    {
+        System.exit(rc);
+    }
+
+    /**
+     * DuccServiceApi <options>
+     * Where options:
+     *    -r --register <properties>
+     *    -u --unregister <id>
+     *    -q --query <id>
+     *    --start <id>
+     *    --stop <id>
+     *    -m --modify <properties>
+     *    -f --fetch <id>
+     *
+     *  Properties file:
+     *  type = UIMA-AS | Custom
+     *  endpoint = <amq endoint>      # if UIMA-AS
+     *  broker   = <broker url>       # if UIMA-AS
+     *  user     = userid
+     *
+     *  Service is identified as:
+     *  type:endpoint:broker
+     *  e.g.  UIMA-AS@FixedSleepAE@tcp://bluej02
+     */
+	public static void main(String[] args) 
+    {
+
+		try {
+			DuccServiceApi api = new DuccServiceApi();
+            api.init();
+			api.run(args);
+            api.doExit(0);
+		} catch (Throwable e) {
+			e.printStackTrace();           // should not get this, hopefully have trapped everything
+            System.exit(1);
+		}
+	}
+	
+}

Propchange: uima/sandbox/uima-ducc/trunk/uima-ducc-cli/main/java/org/apache/uima/ducc/cli/DuccServiceApi.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: uima/sandbox/uima-ducc/trunk/uima-ducc-cli/main/java/org/apache/uima/ducc/cli/DuccServiceCancel.java
URL: http://svn.apache.org/viewvc/uima/sandbox/uima-ducc/trunk/uima-ducc-cli/main/java/org/apache/uima/ducc/cli/DuccServiceCancel.java?rev=1427911&view=auto
==============================================================================
--- uima/sandbox/uima-ducc/trunk/uima-ducc-cli/main/java/org/apache/uima/ducc/cli/DuccServiceCancel.java (added)
+++ uima/sandbox/uima-ducc/trunk/uima-ducc-cli/main/java/org/apache/uima/ducc/cli/DuccServiceCancel.java Wed Jan  2 19:07:53 2013
@@ -0,0 +1,220 @@
+/*
+ * 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;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+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.PosixParser;
+import org.apache.uima.ducc.api.DuccMessage;
+import org.apache.uima.ducc.api.IDuccMessageProcessor;
+import org.apache.uima.ducc.common.crypto.Crypto;
+import org.apache.uima.ducc.common.exception.DuccRuntimeException;
+import org.apache.uima.ducc.common.utils.DuccPropertiesResolver;
+import org.apache.uima.ducc.transport.dispatcher.DuccEventHttpDispatcher;
+import org.apache.uima.ducc.transport.event.CancelServiceDuccEvent;
+import org.apache.uima.ducc.transport.event.CancelServiceReplyDuccEvent;
+import org.apache.uima.ducc.transport.event.DuccEvent;
+import org.apache.uima.ducc.transport.event.cli.JobReplyProperties;
+import org.apache.uima.ducc.transport.event.cli.JobRequestProperties;
+import org.apache.uima.ducc.transport.event.cli.ServiceSpecificationProperties;
+
+
+/**
+ * Cancel a DUCC service
+ */
+
+public class DuccServiceCancel extends DuccUi {
+	
+	private IDuccMessageProcessor duccMessageProcessor = new DuccMessage();
+	
+	public DuccServiceCancel() {
+	}
+	
+	public DuccServiceCancel(IDuccMessageProcessor duccMessageProcessor) {
+		this.duccMessageProcessor = duccMessageProcessor;
+	}
+	
+	@SuppressWarnings("static-access")
+	private void addOptions(Options options) {
+		options.addOption(OptionBuilder
+				.withDescription(DuccUiConstants.desc_help).hasArg(false)
+				.withLongOpt(DuccUiConstants.name_help).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_job_id)
+				.withDescription(makeDesc(DuccUiConstants.desc_job_id,DuccUiConstants.exmp_job_id)).hasArg()
+				.withLongOpt(DuccUiConstants.name_job_id).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_service_broker)
+				.withDescription(makeDesc(DuccUiConstants.desc_service_broker,DuccUiConstants.exmp_service_broker)).hasArg()
+				.withLongOpt(DuccUiConstants.name_service_broker).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_service_endpoint)
+				.withDescription(makeDesc(DuccUiConstants.desc_service_endpoint,DuccUiConstants.exmp_service_endpoint)).hasArg()
+				.withLongOpt(DuccUiConstants.name_service_endpoint).create());
+	}
+	
+	protected int help(Options options) {
+		HelpFormatter formatter = new HelpFormatter();
+		formatter.setWidth(DuccUiConstants.help_width);
+		formatter.printHelp(DuccServiceCancel.class.getName(), options);
+		return 1;
+	}
+	
+	public int run(String[] args) throws Exception {
+		JobRequestProperties serviceRequestProperties = new JobRequestProperties();
+		/*
+		 * parser is not thread safe?
+		 */
+		synchronized(DuccUi.class) {	
+			Options options = new Options();
+			addOptions(options);
+			CommandLineParser parser = new PosixParser();
+			CommandLine commandLine = parser.parse(options, args);
+			/*
+			 * give help & exit when requested
+			 */
+			if (commandLine.hasOption(DuccUiConstants.name_help)) {
+				return help(options);
+			}
+			if(commandLine.getOptions().length == 0) {
+				return help(options);
+			}
+			/*
+			 * require DUCC_HOME 
+			 */
+			String ducc_home_key = "DUCC_HOME";
+			String ducc_home = System.getenv(ducc_home_key);
+			if(ducc_home == null) {
+				duccMessageProcessor.err("missing required environment variable: "+ducc_home_key);
+				return 1;
+			}
+			/*
+			 * detect duplicate options
+			 */
+			if (DuccUiUtilities.duplicate_options(duccMessageProcessor, commandLine)) {
+				return 1;
+			}
+			/*
+			 * marshal user
+			 */
+			String user = DuccUiUtilities.getUser();
+			serviceRequestProperties.setProperty(ServiceSpecificationProperties.key_user, user);
+			String property = DuccPropertiesResolver.getInstance().getProperty(DuccPropertiesResolver.ducc_signature_required);
+			if(property != null) {
+				String signatureRequiredProperty = property.trim().toLowerCase();
+				if(signatureRequiredProperty.equals("on")) {
+					Crypto crypto = new Crypto(System.getProperty("user.home"));
+					byte[] cypheredMessage = crypto.encrypt(user);
+					serviceRequestProperties.put(ServiceSpecificationProperties.key_signature, cypheredMessage);
+				}
+			}
+			/*
+			 * marshal command line options into properties
+			 */
+			Option[] optionList = commandLine.getOptions();
+			for (int i=0; i<optionList.length; i++) {
+				Option option = optionList[i];
+				String name = option.getLongOpt();
+				String value = option.getValue();
+				serviceRequestProperties.setProperty(name, value);
+			}
+		}
+		// trim
+		DuccUiUtilities.trimProperties(serviceRequestProperties);
+		/*
+		 * employ default broker/endpoint if not specified
+		 */
+		String broker = serviceRequestProperties.getProperty(JobRequestProperties.key_service_broker);
+		if(broker == null) {
+			broker = DuccUiUtilities.buildBrokerUrl();
+		}
+		String endpoint = serviceRequestProperties.getProperty(JobRequestProperties.key_service_endpoint);
+		if(endpoint == null) {
+			endpoint = DuccPropertiesResolver.getInstance().getProperty(DuccPropertiesResolver.ducc_jms_provider)
+				     + ":"
+				     + DuccPropertiesResolver.getInstance().getProperty(DuccPropertiesResolver.ducc_orchestrator_request_endpoint_type)
+				     + ":"
+				     + DuccPropertiesResolver.getInstance().getProperty(DuccPropertiesResolver.ducc_orchestrator_request_endpoint)
+				     ;
+		}
+		/*
+		 * send to JM & get reply
+		 */
+//		CamelContext context = new DefaultCamelContext();
+//		ActiveMQComponent amqc = ActiveMQComponent.activeMQComponent(broker);
+//		String jmsProvider = DuccPropertiesResolver.getInstance().getProperty(DuccPropertiesResolver.ducc_jms_provider);
+//        context.addComponent(jmsProvider, amqc);
+//        context.start();
+//        DuccEventDispatcher duccEventDispatcher;
+//        duccEventDispatcher = new DuccEventDispatcher(context,endpoint);
+        
+        String port = 
+                DuccPropertiesResolver.
+                  getInstance().
+                    getProperty(DuccPropertiesResolver.ducc_orchestrator_http_port);
+        if ( port == null ) {
+          throw new DuccRuntimeException("Unable to Submit a Job. Ducc Orchestrator HTTP Port Not Defined. Add ducc.orchestrator.http.port ducc.properties");
+        }
+        String orNode = 
+                DuccPropertiesResolver.
+                  getInstance().
+                    getProperty(DuccPropertiesResolver.ducc_orchestrator_node);
+        if ( orNode == null ) {
+          throw new DuccRuntimeException("Unable to Submit a Job. Ducc Orchestrator Node Not Defined. Add ducc.orchestrator.node to ducc.properties");
+        }
+        
+        String targetUrl = "http://"+orNode+":"+port+"/or";
+        DuccEventHttpDispatcher duccEventDispatcher = new DuccEventHttpDispatcher(targetUrl);        
+        CancelServiceDuccEvent CancelServiceDuccEvent = new CancelServiceDuccEvent();
+        CancelServiceDuccEvent.setProperties(serviceRequestProperties);
+        DuccEvent duccRequestEvent = CancelServiceDuccEvent;
+        DuccEvent duccReplyEvent = null;
+        CancelServiceReplyDuccEvent cancelServiceReplyDuccEvent = null;
+        try {
+        	duccReplyEvent = duccEventDispatcher.dispatchAndWaitForDuccReply(duccRequestEvent);
+        }
+        finally {
+          duccEventDispatcher.close();
+        	//context.stop();
+        }
+        /*
+         * process reply
+         */
+        cancelServiceReplyDuccEvent = (CancelServiceReplyDuccEvent) duccReplyEvent;
+        // TODO handle null & rejected possibilities here
+    	String jobId = cancelServiceReplyDuccEvent.getProperties().getProperty(JobReplyProperties.key_id);
+    	String msg = cancelServiceReplyDuccEvent.getProperties().getProperty(JobReplyProperties.key_message);
+    	duccMessageProcessor.out("Service"+" "+jobId+" "+msg);
+		return 0;
+	}
+	
+	public static void main(String[] args) {
+		try {
+			DuccServiceCancel duccServiceCancel = new DuccServiceCancel();
+			duccServiceCancel.run(args);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+	
+}

Propchange: uima/sandbox/uima-ducc/trunk/uima-ducc-cli/main/java/org/apache/uima/ducc/cli/DuccServiceCancel.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: uima/sandbox/uima-ducc/trunk/uima-ducc-cli/main/java/org/apache/uima/ducc/cli/DuccServiceSubmit.java
URL: http://svn.apache.org/viewvc/uima/sandbox/uima-ducc/trunk/uima-ducc-cli/main/java/org/apache/uima/ducc/cli/DuccServiceSubmit.java?rev=1427911&view=auto
==============================================================================
--- uima/sandbox/uima-ducc/trunk/uima-ducc-cli/main/java/org/apache/uima/ducc/cli/DuccServiceSubmit.java (added)
+++ uima/sandbox/uima-ducc/trunk/uima-ducc-cli/main/java/org/apache/uima/ducc/cli/DuccServiceSubmit.java Wed Jan  2 19:07:53 2013
@@ -0,0 +1,895 @@
+/*
+ * 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;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+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.PosixParser;
+import org.apache.uima.ducc.api.DuccMessage;
+import org.apache.uima.ducc.api.IDuccMessageProcessor;
+import org.apache.uima.ducc.cli.IServiceApi.RegistrationOption;
+import org.apache.uima.ducc.common.IDucc;
+import org.apache.uima.ducc.common.crypto.Crypto;
+import org.apache.uima.ducc.common.exception.DuccRuntimeException;
+import org.apache.uima.ducc.common.utils.DuccPropertiesResolver;
+import org.apache.uima.ducc.common.utils.IOHelper;
+import org.apache.uima.ducc.transport.dispatcher.DuccEventHttpDispatcher;
+import org.apache.uima.ducc.transport.event.DuccEvent;
+import org.apache.uima.ducc.transport.event.SubmitServiceDuccEvent;
+import org.apache.uima.ducc.transport.event.SubmitServiceReplyDuccEvent;
+import org.apache.uima.ducc.transport.event.cli.ServiceRequestProperties;
+import org.apache.uima.ducc.transport.event.cli.ServiceSpecificationProperties;
+import org.apache.uima.ducc.transport.event.cli.SpecificationProperties;
+import org.apache.uima.ducc.transport.event.sm.IService.ServiceType;
+
+
+/**
+ * Submit a DUCC service
+ */
+
+public class DuccServiceSubmit extends DuccUi {
+	
+    private String jvmarg_string = null;
+    private Properties jvmargs = null;
+	private IDuccMessageProcessor duccMessageProcessor = new DuccMessage();
+	
+	public DuccServiceSubmit() {
+	}
+	
+	public DuccServiceSubmit(IDuccMessageProcessor duccMessageProcessor) {
+		this.duccMessageProcessor = duccMessageProcessor;
+	}
+	
+    @SuppressWarnings("static-access")
+	private void addOptions(Options options) {
+		options.addOption(OptionBuilder
+				.withDescription(DuccUiConstants.desc_help).hasArg(false)
+				.withLongOpt(DuccUiConstants.name_help).create());
+		options.addOption(OptionBuilder
+				.withDescription(DuccUiConstants.desc_debug).hasArg(false)
+				.withLongOpt(DuccUiConstants.name_debug).create());
+		/*
+		options.addOption(OptionBuilder
+				.withDescription(DuccUiConstants.desc_timestamp).hasArg(false)
+				.withLongOpt(DuccUiConstants.name_timestamp).create());
+		*/
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_service_broker)
+				.withDescription(makeDesc(DuccUiConstants.desc_service_broker,DuccUiConstants.exmp_service_broker)).hasArg()
+				.withLongOpt(DuccUiConstants.name_service_broker).create());
+
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_service_endpoint)
+				.withDescription(makeDesc(DuccUiConstants.desc_service_endpoint,DuccUiConstants.exmp_service_endpoint)).hasArg()
+				.withLongOpt(DuccUiConstants.name_service_endpoint).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_description)
+				.withDescription(makeDesc(DuccUiConstants.desc_description,DuccUiConstants.exmp_description)).hasArg()
+				.withLongOpt(DuccUiConstants.name_description).create());
+		/*
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_notifications)
+				.withDescription(makeDesc(DuccUiConstants.desc_notifications,DuccUiConstants.exmp_notifications)).hasArg()
+				.withLongOpt(DuccUiConstants.name_notifications).create());
+		*/
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_scheduling_class)
+				.withDescription(makeDesc(DuccUiConstants.desc_scheduling_class,DuccUiConstants.exmp_scheduling_class)).hasArg()
+				.withLongOpt(DuccUiConstants.name_scheduling_class).create());
+		/*
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_scheduling_priority)
+				.withDescription(makeDesc(DuccUiConstants.desc_scheduling_priority,DuccUiConstants.exmp_scheduling_priority)).hasArg()
+				.withLongOpt(DuccUiConstants.name_scheduling_priority).create());
+		*/
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_log_directory)
+				.withDescription(makeDesc(DuccUiConstants.desc_log_directory,DuccUiConstants.exmp_log_directory)).hasArg()
+				.withLongOpt(DuccUiConstants.name_log_directory).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_working_directory)
+				.withDescription(makeDesc(DuccUiConstants.desc_working_directory,DuccUiConstants.exmp_working_directory)).hasArg()
+				.withLongOpt(DuccUiConstants.name_working_directory).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_jvm)
+				.withDescription(makeDesc(DuccUiConstants.desc_jvm,DuccUiConstants.exmp_jvm)).hasArg()
+				.withLongOpt(DuccUiConstants.name_jvm).create());
+		/*
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_driver_jvm_args)
+				.withDescription(makeDesc(DuccUiConstants.desc_driver_jvm_args,DuccUiConstants.exmp_driver_jvm_args)).hasArg()
+				.withLongOpt(DuccUiConstants.name_driver_jvm_args).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_driver_classpath)
+				.withDescription(makeDesc(DuccUiConstants.desc_driver_classpath,DuccUiConstants.exmp_driver_classpath)).hasArg()
+				.withLongOpt(DuccUiConstants.name_driver_classpath).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_driver_environment)
+				.withDescription(makeDesc(DuccUiConstants.desc_driver_environment,DuccUiConstants.exmp_driver_environment)).hasArg()
+				.withLongOpt(DuccUiConstants.name_driver_environment).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_driver_memory_size)
+				.withDescription(makeDesc(DuccUiConstants.desc_driver_memory_size,DuccUiConstants.exmp_driver_memory_size)).hasArg()
+				.withLongOpt(DuccUiConstants.name_driver_memory_size).create());
+        */
+        // allo CR only so we can detect it and refuse it as a service
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_driver_descriptor_CR)
+				.withDescription(makeDesc(DuccUiConstants.desc_driver_descriptor_CR,DuccUiConstants.exmp_driver_descriptor_CR)).hasArg()
+				.withLongOpt(DuccUiConstants.name_driver_descriptor_CR).create());
+        /*
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_driver_descriptor_CR_overrides)
+				.withDescription(makeDesc(DuccUiConstants.desc_driver_descriptor_CR_overrides,DuccUiConstants.exmp_driver_descriptor_CR_overrides)).hasArg()
+				.withLongOpt(DuccUiConstants.name_driver_descriptor_CR_overrides).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_driver_exception_handler)
+				.withDescription(makeDesc(DuccUiConstants.desc_driver_exception_handler,DuccUiConstants.exmp_driver_exception_handler)).hasArg()
+				.withLongOpt(DuccUiConstants.name_driver_exception_handler).create());
+		*/
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_process_jvm_args)
+				.withDescription(makeDesc(DuccUiConstants.desc_process_jvm_args,DuccUiConstants.exmp_process_jvm_args)).hasArg()
+				.withLongOpt(DuccUiConstants.name_process_jvm_args).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_process_classpath)
+				.withDescription(makeDesc(DuccUiConstants.desc_process_classpath,DuccUiConstants.exmp_process_classpath)).hasArg()
+				.withLongOpt(DuccUiConstants.name_process_classpath).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_process_environment)
+				.withDescription(makeDesc(DuccUiConstants.desc_process_environment,DuccUiConstants.exmp_process_environment)).hasArg()
+				.withLongOpt(DuccUiConstants.name_process_environment).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_process_memory_size)
+				.withDescription(makeDesc(DuccUiConstants.desc_process_memory_size,DuccUiConstants.exmp_process_memory_size)).hasArg()
+				.withLongOpt(DuccUiConstants.name_process_memory_size).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_process_DD)
+				.withDescription(makeDesc(DuccUiConstants.desc_process_DD,DuccUiConstants.exmp_process_DD)).hasArg()
+				.withLongOpt(DuccUiConstants.name_process_DD).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_process_descriptor_CM)
+				.withDescription(makeDesc(DuccUiConstants.desc_process_descriptor_CM,DuccUiConstants.exmp_process_descriptor_CM)).hasArg()
+				.withLongOpt(DuccUiConstants.name_process_descriptor_CM).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_process_descriptor_CM_overrides)
+				.withDescription(makeDesc(DuccUiConstants.desc_process_descriptor_CM_overrides,DuccUiConstants.exmp_process_descriptor_CM_overrides)).hasArg()
+				.withLongOpt(DuccUiConstants.name_process_descriptor_CM_overrides).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_process_descriptor_AE)
+				.withDescription(makeDesc(DuccUiConstants.desc_process_descriptor_AE,DuccUiConstants.exmp_process_descriptor_AE)).hasArg()
+				.withLongOpt(DuccUiConstants.name_process_descriptor_AE).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_process_descriptor_AE_overrides)
+				.withDescription(makeDesc(DuccUiConstants.desc_process_descriptor_AE_overrides,DuccUiConstants.exmp_process_descriptor_AE_overrides)).hasArg()
+				.withLongOpt(DuccUiConstants.name_process_descriptor_AE_overrides).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_process_descriptor_CC)
+				.withDescription(makeDesc(DuccUiConstants.desc_process_descriptor_CC,DuccUiConstants.exmp_process_descriptor_CC)).hasArg()
+				.withLongOpt(DuccUiConstants.name_process_descriptor_CC).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_process_descriptor_CC_overrides)
+				.withDescription(makeDesc(DuccUiConstants.desc_process_descriptor_CC_overrides,DuccUiConstants.exmp_process_descriptor_CC_overrides)).hasArg()
+				.withLongOpt(DuccUiConstants.name_process_descriptor_CC_overrides).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_process_deployments_max)
+				.withDescription(makeDesc(DuccUiConstants.desc_process_deployments_max,DuccUiConstants.exmp_process_deployments_max)).hasArg()
+				.withLongOpt(DuccUiConstants.name_process_deployments_max).create());
+		/*
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_process_deployments_min)
+				.withDescription(makeDesc(DuccUiConstants.desc_process_deployments_min,DuccUiConstants.exmp_process_deployments_min)).hasArg()
+				.withLongOpt(DuccUiConstants.name_process_deployments_min).create());
+		*/
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_process_initialization_failures_cap)
+				.withDescription(makeDesc(DuccUiConstants.desc_process_initialization_failures_cap,DuccUiConstants.exmp_process_initialization_failures_cap)).hasArg()
+				.withLongOpt(DuccUiConstants.name_process_initialization_failures_cap).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_process_failures_limit)
+				.withDescription(makeDesc(DuccUiConstants.desc_process_failures_limit,DuccUiConstants.exmp_process_failures_limit)).hasArg()
+				.withLongOpt(DuccUiConstants.name_process_failures_limit).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_process_thread_count)
+				.withDescription(makeDesc(DuccUiConstants.desc_process_thread_count,DuccUiConstants.exmp_process_thread_count)).hasArg()
+				.withLongOpt(DuccUiConstants.name_process_thread_count).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_process_per_item_time_max)
+				.withDescription(makeDesc(DuccUiConstants.desc_process_per_item_time_max,DuccUiConstants.exmp_process_per_item_time_max)).hasArg()
+				.withLongOpt(DuccUiConstants.name_process_per_item_time_max).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_process_get_meta_time_max)
+				.withDescription(makeDesc(DuccUiConstants.desc_process_get_meta_time_max,DuccUiConstants.exmp_process_get_meta_time_max)).hasArg()
+				.withLongOpt(DuccUiConstants.name_process_get_meta_time_max).create());
+		options.addOption(OptionBuilder
+				.withArgName(DuccUiConstants.parm_specification)
+				.withDescription(DuccUiConstants.desc_specification).hasArg()
+				.withLongOpt(DuccUiConstants.name_specification).create());
+		/*
+		options.addOption(OptionBuilder
+				.withDescription(DuccUiConstants.desc_wait_for_completion).hasArg(false)
+				.withLongOpt(DuccUiConstants.name_wait_for_completion).create());
+		options.addOption(OptionBuilder
+				.withDescription(DuccUiConstants.desc_submit_cancel_service_on_interrupt).hasArg(false)
+				.withLongOpt(DuccUiConstants.name_submit_cancel_service_on_interrupt).create());
+		*/
+		options.addOption(OptionBuilder
+                          .withArgName    (DuccUiConstants.parm_service_dependency)
+                          .withDescription(makeDesc(DuccUiConstants.desc_service_dependency,DuccUiConstants.exmp_service_dependency))
+                          .hasArgs        ()
+                          .withValueSeparator(',')
+                          .withLongOpt    (DuccUiConstants.name_service_dependency)
+                          .create         ()
+                          );
+
+		options.addOption(OptionBuilder
+                          .withLongOpt    (RegistrationOption.ServiceCustomEndpoint.decode()) 
+                          .withDescription(RegistrationOption.ServiceCustomEndpoint.description()) 
+                          .withArgName    (RegistrationOption.ServiceCustomEndpoint.argname())
+                          .hasArg(true)
+                          .create()
+                          );
+	}
+
+	//**********
+	
+	private String[] required_options = {  };
+	
+	private boolean missing_required_options(Properties properties) {
+		boolean retVal = false;
+		for(int i=0; i<required_options.length; i++) {
+			String required_option = required_options[i];
+			if (properties.containsKey(required_option)) {
+				duccMessageProcessor.err("missing required option: "+required_option);
+				retVal = true;
+			}
+		}
+		return retVal;
+	}
+	
+	//**********
+
+    private static final HashMap<String, List<String>> consumer = new HashMap<String, List<String>>(){
+		private static final long serialVersionUID = 1L;
+
+		{
+            put("", Arrays.asList( ServiceRequestProperties.key_process_DD,
+					  			   ServiceRequestProperties.key_process_descriptor_CM,
+					  			   ServiceRequestProperties.key_process_descriptor_AE,
+					  			   ServiceRequestProperties.key_process_descriptor_CC
+            					   ));
+        }
+    };
+    
+    private static final String consumer_list = ServiceRequestProperties.key_process_DD
+	   									   	  	+", "
+	   									   	  	+ServiceRequestProperties.key_process_descriptor_CM
+	   									   	  	+", "
+	   									   	  	+ServiceRequestProperties.key_process_descriptor_AE
+	   									   	  	+", "
+	   									   	  	+ServiceRequestProperties.key_process_descriptor_CC
+	   									   	  	;
+    
+	private boolean has_consumer(Properties properties) {
+		boolean retVal = true;
+		Iterator<Entry<String, List<String>>> iteratorA = consumer.entrySet().iterator();
+		while(iteratorA.hasNext()) {
+			boolean has_one = false;
+			Entry<String, List<String>> entrySet = iteratorA.next();
+			Iterator<String> iteratorB = entrySet.getValue().iterator();
+			while(iteratorB.hasNext()) {
+				String option = iteratorB.next();
+				if (properties.containsKey(option)) {
+					has_one = true;
+					break;
+				}
+			}
+			if(!has_one) {
+				duccMessageProcessor.err("missing option, specify at least one of: "+consumer_list);
+				retVal = false;
+			}
+		}
+		return retVal;
+	}
+	
+	//**********
+    
+    private static final HashMap<String, List<String>> mutually_exclusive_options = new HashMap<String, List<String>>(){
+		private static final long serialVersionUID = 1L;
+
+		{
+            put(ServiceRequestProperties.key_process_DD, Arrays.asList( ServiceRequestProperties.key_process_descriptor_CM,
+            														ServiceRequestProperties.key_process_descriptor_AE,
+            														ServiceRequestProperties.key_process_descriptor_CC
+            														));
+        }
+    };
+
+	private boolean has_mutually_exclusive_options(Properties properties) {
+		boolean retVal = false;
+		Iterator<Entry<String, List<String>>> iteratorA = mutually_exclusive_options.entrySet().iterator();
+		while(iteratorA.hasNext()) {
+			Entry<String, List<String>> entrySet = iteratorA.next();
+			if (properties.containsKey(entrySet.getKey())) {
+				Iterator<String> iteratorB = entrySet.getValue().iterator();
+				while(iteratorB.hasNext()) {
+					String option = iteratorB.next();
+					if (properties.containsKey(option)) {
+						duccMessageProcessor.err("conflicting options: "+entrySet.getKey()+" and "+option);
+						retVal = true;
+					}
+				}
+			}
+		}
+		return retVal;
+	}
+	
+	//**********
+	
+	private long getThreadsLimit() {
+		long limit = 0;
+		try {
+			String p_limit = DuccPropertiesResolver.getInstance().getProperty(DuccPropertiesResolver.ducc_submit_threads_limit);
+			if(p_limit != null) {
+				p_limit = p_limit.trim();
+				if(!p_limit.equals("unlimited")) {
+					limit = Long.parseLong(p_limit);
+				}
+			}
+		}
+		catch(Throwable t) {
+			duccMessageProcessor.throwable(t);
+		}
+		return limit;
+	}
+	
+	private boolean adjust_max_threads(Properties properties) {
+		boolean retVal = false;
+		try {
+			long limit = getThreadsLimit();
+			if(limit == 0) {
+				return retVal;
+			}
+			String p_threads = properties.getProperty(ServiceRequestProperties.key_process_thread_count);
+			if(p_threads == null) {
+				p_threads = DuccUiConstants.dval_process_thread_count;
+			}
+			long threads = Long.parseLong(p_threads);
+			String p_procs = properties.getProperty(ServiceRequestProperties.key_process_deployments_max);
+			if(p_procs == null) {
+				long procs = limit / threads;
+				p_procs = "unlimited";
+				String a_procs = ""+procs;
+				duccMessageProcessor.err(ServiceRequestProperties.key_process_deployments_max+": requested="+p_procs+" adjusted="+a_procs);
+				properties.setProperty(ServiceRequestProperties.key_process_deployments_max, a_procs);
+				retVal = true;
+			}
+			else {
+				long procs = Long.parseLong(p_procs);
+				if( (procs * threads) > limit ) {
+					procs = limit / threads;
+					String a_procs = ""+procs;
+					duccMessageProcessor.err(ServiceRequestProperties.key_process_deployments_max+": requested="+p_procs+" adjusted="+a_procs);
+					properties.setProperty(ServiceRequestProperties.key_process_deployments_max, a_procs);
+					retVal = true;
+				}
+			}
+		}
+		catch(Throwable t) {
+			duccMessageProcessor.throwable(t);
+		}
+		return retVal;
+	}
+	
+	//**********
+	
+	private String getDuccProperty(String propertyName, String defaultValue) {
+		String propertyValue = defaultValue;
+		try {
+			String value = DuccPropertiesResolver.getInstance().getProperty(propertyName);
+			if(value != null) {
+				propertyValue = value;
+			}
+		}
+		catch(Throwable t) {
+			duccMessageProcessor.throwable(t);
+		}
+		return propertyValue;
+	}
+	
+	private void adjust_process_jvm_args(Properties serviceRequestProperties) {
+		String additionalJvmArgs = getDuccProperty(DuccPropertiesResolver.ducc_submit_process_jvm_args, null);
+		if(additionalJvmArgs != null) {
+			String jvmArgs = serviceRequestProperties.getProperty(ServiceRequestProperties.key_process_jvm_args);
+			if(jvmArgs == null) {
+				jvmArgs = additionalJvmArgs;
+			}
+			else {
+				jvmArgs += " "+additionalJvmArgs;
+			}
+			serviceRequestProperties.setProperty(ServiceRequestProperties.key_process_jvm_args, jvmArgs);
+		}
+	}
+	
+	private void adjust_jvm_args(Properties serviceRequestProperties) {
+		adjust_process_jvm_args(serviceRequestProperties);
+	}
+
+    /*
+     * resolve ${defaultBrokerURL} in service dependencies - must fail if resolution needed but can't resolve
+     */
+    boolean resolve_service_dependencies(String endpoint, Properties props)
+    {
+        String deps = props.getProperty(ServiceRequestProperties.key_service_dependency);
+        try {
+            deps = DuccUiUtilities.resolve_service_dependencies(endpoint, deps, jvmargs);                
+            if ( deps != null ) {
+                props.setProperty(ServiceRequestProperties.key_service_dependency, deps);
+            }
+            return true;
+        } catch ( Throwable t ) {
+            duccMessageProcessor.err(t.getMessage());
+            return false;
+        }
+    }
+	
+	//**********
+	
+	protected int help(Options options) {
+		HelpFormatter formatter = new HelpFormatter();
+		formatter.setWidth(DuccUiConstants.help_width);
+		formatter.printHelp(DuccServiceSubmit.class.getName(), options);
+		return DuccUiConstants.ERROR;
+	}
+
+	private boolean use_signature = false;
+	
+	public int run(String[] args) throws Exception {
+		ServiceRequestProperties serviceRequestProperties = new ServiceRequestProperties();
+
+		/*
+		 * parser is not thread safe?
+		 */
+		synchronized(DuccUi.class) {
+			Options options = new Options();
+			addOptions(options);
+			/*
+			for (String s : args) {
+				System.out.println("arg |"+s+"|");
+			}
+			*/
+			CommandLineParser parser = new PosixParser();
+			CommandLine commandLine = parser.parse(options, args);
+			/*
+			 * give help & exit when requested
+			 */
+			if (commandLine.hasOption(DuccUiConstants.name_help)) {
+				return help(options);
+			}
+			if(commandLine.getOptions().length == 0) {
+				return help(options);
+			}
+
+			/*
+			 * require DUCC_HOME 
+			 */
+			String ducc_home_key = "DUCC_HOME";
+			String ducc_home = System.getenv(ducc_home_key);
+			if(ducc_home == null) {
+				duccMessageProcessor.err("missing required environment variable: "+ducc_home_key);
+				return DuccUiConstants.ERROR;
+			}
+
+			/*
+			 * detect duplicate options
+			 */
+			if (DuccUiUtilities.duplicate_options(duccMessageProcessor, commandLine)) {
+				return DuccUiConstants.ERROR;
+			}
+			/*
+			 * marshal user
+			 */
+			String user = DuccUiUtilities.getUser();
+			serviceRequestProperties.setProperty(ServiceSpecificationProperties.key_user, user);
+			String property = DuccPropertiesResolver.getInstance().getProperty(DuccPropertiesResolver.ducc_signature_required);
+			if(property != null) {
+				String signatureRequiredProperty = property.trim().toLowerCase();
+				if(signatureRequiredProperty.equals("on")) {
+					Crypto crypto = new Crypto(System.getProperty("user.home"));
+					byte[] cypheredMessage = crypto.encrypt(user);
+					serviceRequestProperties.put(ServiceSpecificationProperties.key_signature, cypheredMessage);
+					use_signature = true;
+				}
+			}
+			/*
+			 * marshal command line options into properties
+			 */
+			Option[] optionList = commandLine.getOptions();
+			// pass 1
+			for (int i=0; i<optionList.length; i++) {
+				Option option = optionList[i];
+				String name = option.getLongOpt();
+				if(name.equals(SpecificationProperties.key_specification)) {
+					File file = new File(option.getValue());
+					FileInputStream fis = new FileInputStream(file);
+					serviceRequestProperties.load(fis);
+				}
+			}
+
+            jvmarg_string = (String) serviceRequestProperties.get(ServiceRequestProperties.key_process_jvm_args);
+            jvmargs = DuccUiUtilities.jvmArgsToProperties(jvmarg_string);
+            DuccUiUtilities.resolvePropertiesPlaceholders(serviceRequestProperties, jvmargs);
+
+			// trim
+			DuccUiUtilities.trimProperties(serviceRequestProperties);
+			// pass 2
+			for (int i=0; i<optionList.length; i++) {
+				Option option = optionList[i];
+				String name = option.getLongOpt();
+
+				String value = null;
+                if ( option.hasArgs() ) {        // if multiple args, make into blank-delimited string for the props file
+                    String[] arglist = commandLine.getOptionValues(name);
+                    int len = arglist.length;
+                    StringBuffer sb = new StringBuffer();
+                    for ( int ii = 0; ii < len; ii++ ) {
+                        String a = arglist[ii].trim();
+                        if ( a.equals("") ) continue;
+                        sb.append(a);
+                        if ( ii < (len-1) ) {
+                            sb.append(", ");
+                        }
+                    }
+                    value = sb.toString();
+                } else {
+                    value = option.getValue();
+                }
+
+				if(value == null) {
+					value = "";
+				}
+
+                // System.out.println(name + " " + value);
+				name = trimmer(name);
+				value = trimmer(value);
+				serviceRequestProperties.setProperty(name, value);
+			}
+		}
+
+        //
+        // Simple sanity checking in case somebody tries to submit a regular job as a service
+        //
+        String[] forbidden = {
+            DuccUiConstants.name_driver_descriptor_CR,
+            DuccUiConstants.name_process_descriptor_AE,
+            DuccUiConstants.name_process_descriptor_CC,
+            DuccUiConstants.name_process_descriptor_CM,
+        };
+        for (String s : forbidden) {
+            String tmp = (String) serviceRequestProperties.get(s);
+            if ( tmp != null ) {
+                duccMessageProcessor.out("Job is not a service, it contains " + s);
+                return DuccUiConstants.ERROR;
+            }
+        }
+        
+		/*
+		 * employ default log directory if not specified
+		 */
+		String log_directory = serviceRequestProperties.getProperty(ServiceRequestProperties.key_log_directory);
+		if(log_directory == null) {
+			// no log directory was specified - default to user's home + "/ducc/logs"
+			log_directory = System.getProperty("user.home")+IDucc.userLogsSubDirectory;
+		}
+		else {
+			if(log_directory.startsWith(File.separator)) {
+			// absolute log directory was specified
+			}
+			else {
+				// relative log directory was specified - default to user's home + relative directory
+				if(log_directory.endsWith(File.separator)) {
+					log_directory = System.getProperty("user.home")+log_directory;
+				}
+				else {
+					log_directory = System.getProperty("user.home")+File.separator+log_directory;
+				}
+			}
+		}
+		// tack on "services" to complete logging directory
+		if(log_directory.endsWith(File.separator)) {
+			log_directory = log_directory+"services";
+		}
+		else {
+			log_directory = log_directory+File.separator+"services";
+		}
+		serviceRequestProperties.setProperty(ServiceRequestProperties.key_log_directory,log_directory);
+		/*
+		 * employ default working directory if not specified
+		 */
+		String working_directory = serviceRequestProperties.getProperty(ServiceRequestProperties.key_working_directory);
+		if(working_directory == null) {
+			working_directory = System.getProperty("user.dir");
+			serviceRequestProperties.setProperty(ServiceRequestProperties.key_working_directory,working_directory);
+		}
+		/*
+		 * employ default process classpath if not specified
+		 */
+		String process_classpath = serviceRequestProperties.getProperty(ServiceRequestProperties.key_process_classpath);
+		if(process_classpath == null) {
+			process_classpath = System.getProperty("java.class.path");
+			serviceRequestProperties.setProperty(ServiceRequestProperties.key_process_classpath,process_classpath);
+		}
+		/*
+		 * employ default process initialization failures cap if not specified
+		 */
+		String process_initialization_failures_cap = serviceRequestProperties.getProperty(ServiceRequestProperties.key_process_initialization_failures_cap);
+		if(process_initialization_failures_cap == null) {
+			serviceRequestProperties.setProperty(ServiceRequestProperties.key_process_initialization_failures_cap,DuccUiConstants.dval_process_initialization_failures_cap);
+		}
+
+// 		/*
+// 		 * employ default process failures limit if not specified
+// 		 */
+// 		String process_failures_limit = serviceRequestProperties.getProperty(ServiceRequestProperties.key_process_failures_limit);
+// 		if(process_failures_limit == null) {
+// 			serviceRequestProperties.setProperty(ServiceRequestProperties.key_process_failures_limit,DuccUiConstants.dval_process_failures_limit);
+// 		}
+// 		/*
+// 		 * employ default broker/endpoint if not specified
+// 		 */
+// 		String broker = serviceRequestProperties.getProperty(ServiceRequestProperties.key_service_broker);
+// 		if(broker == null) {
+        //String broker = DuccUiUtilities.buildBrokerUrl();
+// 		}
+ 		//if(serviceRequestProperties.containsKey(DuccUiConstants.name_debug)) {
+ 		//	System.out.println("broker:"+" "+broker);
+ 		//}
+
+        String service_endpoint = serviceRequestProperties.getProperty(RegistrationOption.ServiceCustomEndpoint.decode());
+        if(service_endpoint == null) {
+            // A null endpoint means it MUST be UimaAs.  Otherwise it's the user's responsibility to
+            // have it set correctly, because really can't tell.
+
+            //
+            // The service endpoint is extracted from the DD. It is for internal use only, not publicly settable or documented.
+            //
+            try {
+                String dd = (String) serviceRequestProperties.get(ServiceRequestProperties.key_process_DD);
+                String wd = (String) serviceRequestProperties.get(ServiceRequestProperties.key_working_directory);
+                //System.err.println("DD: " + dd);
+                //System.err.println("WD: " + wd);
+                //System.err.println("jvmargs: " + jvmarg_string);
+                service_endpoint = DuccUiUtilities.getEndpoint(wd, dd, jvmargs);
+            } catch ( IllegalArgumentException e ) {
+                duccMessageProcessor.exception(e);
+                duccMessageProcessor.err("Cannot read/process DD descriptor for endpoint: " + e.getMessage());
+                return DuccUiConstants.ERROR;
+            }
+        } else {
+            // If there is an endpoint and it is UIMA-AS then it is used blindly, but might want resolution
+            // If there is an endpoint and it is CUSTOM then it's a custom service which is not yet supported
+
+            if ( service_endpoint.startsWith(ServiceType.Custom.decode()) ) {
+                duccMessageProcessor.out("CUSTOM services are not yet supported for submission.");
+                return DuccUiConstants.ERROR;
+            }
+        }
+        serviceRequestProperties.put(ServiceRequestProperties.key_service_request_endpoint, service_endpoint);
+ 		if(serviceRequestProperties.containsKey(DuccUiConstants.name_debug)) {
+ 			duccMessageProcessor.out("service_endpoint:"+" "+service_endpoint);
+ 		}
+
+		if(serviceRequestProperties.containsKey(DuccUiConstants.name_debug)) {
+			serviceRequestProperties.dump();
+		}
+
+        if ( ! resolve_service_dependencies(service_endpoint, serviceRequestProperties) ) {            
+            return DuccUiConstants.ERROR;
+        }
+
+		/*
+		 * check for required options
+		 */
+		if (missing_required_options(serviceRequestProperties)) {
+			return DuccUiConstants.ERROR;
+		}
+		/*
+		 * check for mutually exclusive options
+		 */
+		if (has_mutually_exclusive_options(serviceRequestProperties)) {
+			return DuccUiConstants.ERROR;
+		}
+		/*
+		 * check for minimum set of options
+		 */
+		if (!has_consumer(serviceRequestProperties)) {
+			return DuccUiConstants.ERROR;
+		}
+		/*
+		 * set DUCC_LD_LIBRARY_PATH in process environment
+		 */
+		if (!DuccUiUtilities.ducc_environment(duccMessageProcessor, serviceRequestProperties, ServiceRequestProperties.key_process_environment)) {
+			return DuccUiConstants.ERROR;
+		}
+		/*
+		 * limit total number of threads
+		 */
+		adjust_max_threads(serviceRequestProperties);
+		/*
+		 * adjust driver and process jvm args
+		 */
+		adjust_jvm_args(serviceRequestProperties);
+		/*
+		 * send to JM & get reply
+		 */
+//		CamelContext context = new DefaultCamelContext();
+//		ActiveMQComponent amqc = ActiveMQComponent.activeMQComponent(broker);
+//		String jmsProvider = DuccPropertiesResolver.getInstance().getProperty(DuccPropertiesResolver.ducc_jms_provider);
+//        context.addComponent(jmsProvider, amqc);
+//        context.start();
+//        DuccEventDispatcher duccEventDispatcher;
+//        duccEventDispatcher = new DuccEventDispatcher(context,endpoint);
+        
+        String port = 
+                DuccPropertiesResolver.
+                  getInstance().
+                    getProperty(DuccPropertiesResolver.ducc_orchestrator_http_port);
+        if ( port == null ) {
+          throw new DuccRuntimeException("Unable to Submit a Job. Ducc Orchestrator HTTP Port Not Defined. Add ducc.orchestrator.http.port ducc.properties");
+        }
+        String orNode = 
+                DuccPropertiesResolver.
+                  getInstance().
+                    getProperty(DuccPropertiesResolver.ducc_orchestrator_node);
+        if ( orNode == null ) {
+          throw new DuccRuntimeException("Unable to Submit a Job. Ducc Orchestrator Node Not Defined. Add ducc.orchestrator.node to ducc.properties");
+        }
+        
+        String targetUrl = "http://"+orNode+":"+port+"/or";
+        DuccEventHttpDispatcher duccEventDispatcher = new DuccEventHttpDispatcher(targetUrl);        
+        SubmitServiceDuccEvent submitServiceDuccEvent = new SubmitServiceDuccEvent();
+        submitServiceDuccEvent.setProperties(serviceRequestProperties);
+        DuccEvent duccRequestEvent = submitServiceDuccEvent;
+        DuccEvent duccReplyEvent = null;
+        SubmitServiceReplyDuccEvent submitServiceReplyDuccEvent = null;
+        try {
+        	duccReplyEvent = duccEventDispatcher.dispatchAndWaitForDuccReply(duccRequestEvent);
+        }
+        finally {
+          duccEventDispatcher.close();
+        	//context.stop();
+        }
+        /*
+         * process reply
+         */
+        submitServiceReplyDuccEvent = (SubmitServiceReplyDuccEvent) duccReplyEvent;
+        int retVal = 0;
+        Properties properties = submitServiceReplyDuccEvent.getProperties();
+        @SuppressWarnings("unchecked")
+		ArrayList<String> value_submit_warnings = (ArrayList<String>) properties.get(ServiceSpecificationProperties.key_submit_warnings);
+        if(value_submit_warnings != null) {
+        	duccMessageProcessor.out("Service"+" "+"warnings:");
+        	Iterator<String> reasons = value_submit_warnings.iterator();
+        	while(reasons.hasNext()) {
+        		duccMessageProcessor.out(reasons.next());
+        	}
+        }
+        @SuppressWarnings("unchecked")
+		ArrayList<String> value_submit_errors = (ArrayList<String>) properties.get(ServiceSpecificationProperties.key_submit_errors);
+        if(value_submit_errors != null) {
+        	duccMessageProcessor.out("Service"+" "+"errors:");
+        	Iterator<String> reasons = value_submit_errors.iterator();
+        	while(reasons.hasNext()) {
+        		duccMessageProcessor.out(reasons.next());
+        	}
+	        retVal = DuccUiConstants.ERROR;
+        }
+        String serviceId = "?";
+        if(retVal == DuccUiConstants.ERROR) {
+        	duccMessageProcessor.out("Service"+" "+"not"+" "+"submitted");
+        }
+        else {
+        	serviceId = submitServiceReplyDuccEvent.getProperties().getProperty(ServiceRequestProperties.key_id);
+        	saveServiceSpec(serviceId, serviceRequestProperties);
+        	duccMessageProcessor.out("Service"+" "+serviceId+" "+"submitted");
+        	/*
+        	if(serviceRequestProperties.containsKey(DuccUiConstants.name_wait_for_completion)) {
+        		try {
+        			ArrayList<String> arrayList = new ArrayList<String>();
+        			arrayList.add("--"+DuccUiConstants.name_service_id);
+        			arrayList.add(serviceId);
+        			arrayList.add("--"+DuccUiConstants.name_service_broker);
+        			arrayList.add(broker);
+        			if(serviceRequestProperties.containsKey(DuccUiConstants.name_debug)) {
+        				arrayList.add("--"+DuccUiConstants.name_debug);
+        			}
+        			if(serviceRequestProperties.containsKey(DuccUiConstants.name_timestamp)) {
+        				arrayList.add("--"+DuccUiConstants.name_timestamp);
+        			}
+        			if(serviceRequestProperties.containsKey(DuccUiConstants.name_submit_cancel_service_on_interrupt)) {
+        				arrayList.add("--"+DuccUiConstants.name_monitor_cancel_service_on_interrupt);
+        			}
+        			String[] argList = arrayList.toArray(new String[0]);
+        			DuccServiceMonitor duccServiceMonitor = new DuccServiceMonitor();
+        			retVal = duccServiceMonitor.run(argList);
+        		} catch (Exception e) {
+        			e.printStackTrace();
+        			retVal = DuccUiConstants.ERROR;
+        		}
+        	}
+        	*/
+        }
+		return retVal;
+	}
+	
+	private void saveServiceSpec(String serviceId, ServiceRequestProperties serviceRequestProperties) {
+		try {
+			String directory = serviceRequestProperties.getProperty(ServiceRequestProperties.key_log_directory)+File.separator+serviceId+File.separator;
+			IOHelper.mkdirs(directory);
+			String fileName = directory+"service-specification.properties";
+			String comments = null;
+			FileOutputStream fos = null;
+			OutputStreamWriter out = null;
+			fos = new FileOutputStream(fileName);
+			out = new OutputStreamWriter(fos);
+
+			if(use_signature) {
+				String key = SpecificationProperties.key_signature;
+				Object value = serviceRequestProperties.remove(key);
+				serviceRequestProperties.store(out, comments);
+				serviceRequestProperties.put(key, value);
+			}
+			else {
+				serviceRequestProperties.store(out, comments);
+			}
+
+			out.close();
+			fos.close();
+		}
+		catch(Throwable t) {
+			duccMessageProcessor.throwable(t);
+		}
+	}
+	
+	public static void main(String[] args) {
+		try {
+			DuccServiceSubmit duccServiceSubmit = new DuccServiceSubmit();
+			duccServiceSubmit.run(args);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+	
+}