Author: challngr Date: Thu Feb 21 16:13:54 2013 New Revision: 1448703 URL: http://svn.apache.org/r1448703 Log: UIMA-2687
Added: uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/CliBase.java uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/ConsoleListener.java uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccletSubmit.java Modified: uima/sandbox/uima-ducc/trunk/uima-ducc-cli/pom.xml uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccServiceApi.java uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccUi.java uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccUiConstants.java uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/SubmitServiceDuccEvent.java uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/cli/SpecificationProperties.java Modified: uima/sandbox/uima-ducc/trunk/uima-ducc-cli/pom.xml URL: http://svn.apache.org/viewvc/uima/sandbox/uima-ducc/trunk/uima-ducc-cli/pom.xml?rev=1448703&r1=1448702&r2=1448703&view=diff ============================================================================== --- uima/sandbox/uima-ducc/trunk/uima-ducc-cli/pom.xml (original) +++ uima/sandbox/uima-ducc/trunk/uima-ducc-cli/pom.xml Thu Feb 21 16:13:54 2013 @@ -99,6 +99,54 @@ uima-ducc-cli.jar uima-ducc-common.jar u </execution> <execution> + <id>DuccProcessSubmit</id> + <goals><goal>jar</goal></goals> + <phase>package</phase> + <configuration> + <!-- Name the jar --> + <finalName>uima-ducc-process-submit</finalName> + <archive> + <index>false</index> + <manifest> + <addClasspath>false</addClasspath> + <mainClass>org.apache.uima.ducc.cli.DuccletSubmit</mainClass> + </manifest> + <manifestEntries> + <class-path>${DUCC_CP}</class-path> + </manifestEntries> + </archive> + <excludes> + <exclude>**/</exclude> + <exclude>META-INF/*</exclude> + </excludes> + </configuration> + </execution> + + <execution> + <id>DuccProcessCancel</id> + <goals><goal>jar</goal></goals> + <phase>package</phase> + <configuration> + <!-- Name the jar --> + <finalName>uima-ducc-process-cancel</finalName> + <archive> + <index>false</index> + <manifest> + <addClasspath>false</addClasspath> + <mainClass>org.apache.uima.ducc.cli.DuccProcessCancel</mainClass> + </manifest> + <manifestEntries> + <class-path>${DUCC_CP}</class-path> + </manifestEntries> + </archive> + <excludes> + <exclude>**/</exclude> + <exclude>META-INF/*</exclude> + </excludes> + </configuration> + </execution> + + <execution> <id>DuccJobMonitor</id> <goals><goal>jar</goal></goals> <phase>package</phase> Added: uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/CliBase.java URL: http://svn.apache.org/viewvc/uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/CliBase.java?rev=1448703&view=auto ============================================================================== --- uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/CliBase.java (added) +++ uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/CliBase.java Thu Feb 21 16:13:54 2013 @@ -0,0 +1,351 @@ + +/* + * 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.FileOutputStream; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +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.Options; +import org.apache.commons.cli.PosixParser; +import org.apache.uima.ducc.common.IDucc; +import org.apache.uima.ducc.common.utils.DuccProperties; +import org.apache.uima.ducc.common.utils.Utils; +import org.apache.uima.ducc.transport.dispatcher.DuccEventHttpDispatcher; +import org.apache.uima.ducc.transport.event.cli.SpecificationProperties; + +public abstract class CliBase + extends DuccUi +{ + + private boolean init_done = false; + protected String ducc_home; + protected DuccProperties ducc_properties; + protected DuccEventHttpDispatcher dispatcher; + + protected Options options; + protected CommandLineParser parser; + protected CommandLine commandLine; + + protected long friendlyId = -1; + + protected Properties cli_props; + protected ArrayList<String> errors = new ArrayList<String>(); + protected ArrayList<String> warnings = new ArrayList<String>(); + protected ArrayList<String> messages = new ArrayList<String>(); + + abstract void addOptions(Options options); + abstract boolean execute() throws Exception; + + protected ConsoleListener console_listener = null; + + + String getLogDirectory(DuccProperties properties) + { + /* + * employ default log directory if not specified + */ + String log_directory = properties.getProperty("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; + } + } + } + properties.setProperty("log_directory", log_directory); + + /* + * make sure the logdir is actually legal. + */ + File f = new File(log_directory); + if ( f.exists() ) { + if ( !f.isDirectory() ) { + addError("Specified log_directory is not a directory: " + log_directory); + return null; + } + } else if ( !f.mkdirs() ) { + addError("Cannot create log_directory: " + log_directory); + return null; + } + + if ( ! f.canWrite() ) { + addError("Log directory exists but cannot be written: " + f); + return null; + } + return log_directory; + } + + + synchronized void init(String[] args, Properties cli_props, String host_s, String port_s, String servlet) + throws Exception + { + if ( init_done ) return; + + ducc_home = Utils.findDuccHome(); + + this.cli_props = cli_props; + options = new Options(); + parser = new PosixParser(); + addOptions(options); + commandLine = parser.parse(options, args); + + if (commandLine.hasOption(DuccUiConstants.name_help)) { + usage(null); + } + if(commandLine.getOptions().length == 0) { + usage(null); + } + + String propsfile = ducc_home + "/resources/ducc.properties"; + ducc_properties = new DuccProperties(); + ducc_properties.load(propsfile); + + String host = ducc_properties.getStringProperty(host_s); + String port = ducc_properties.getStringProperty(port_s); + + if ( host == null ) { + throw new IllegalStateException(host_s + " is not set in ducc.properties"); + } + + if ( port == null ) { + throw new IllegalStateException(port_s + " is not set in ducc.properties"); + } + + String targetUrl = "http://"+ host + ":" + port + "/" + servlet; + dispatcher = new DuccEventHttpDispatcher(targetUrl); + + init_done = true; + } + + void saveSpec(String id, String name, DuccProperties props) + throws Exception + { + String directory = props.getProperty("log_directory") + File.separator + id; + String fileName = directory + File.separator + name; + File f = new File(directory); + f.mkdirs(); + + String comments = null; + FileOutputStream fos = null; + OutputStreamWriter out = null; + fos = new FileOutputStream(fileName); + out = new OutputStreamWriter(fos); + + String key = SpecificationProperties.key_signature; + if ( props.containsKey(key) ) { + Object value = props.remove(key); + props.store(out, comments); + props.put(key, value); + } else { + props.store(out, comments); + } + + out.close(); + fos.close(); + } + + void adjustLdLibraryPath(DuccProperties requestProps, String key) + { + String source = "LD_LIBRARY_PATH"; + String target = "DUCC_"+source; + String environment_string = requestProps.getProperty(key); + Properties environment_properties = DuccUiUtilities.environmentMap(environment_string); + if (environment_properties.containsKey(source)) { + if (environment_properties.containsKey(target)) { + addWarning(key + " environment conflict: " + target + " takes precedence over " + source); + } else { + target += "="+environment_properties.getProperty(source); + environment_string += " "+target; + requestProps.setProperty(key, environment_string); + } + } + } + + void usage(String message) + { + if ( message != null ) { + System.out.println(message); + } + HelpFormatter formatter = new HelpFormatter(); + formatter.setWidth(DuccUiConstants.help_width); + formatter.printHelp(DuccletSubmit.class.getName(), options); + System.exit(1); + } + + /** + * Set a property via the API. + * + * @param key This is the property name. + * @param value This is the value of the property. + * @param props This is the Properties objct to update. + * + * @returns true if the property is set. Returns false if the property is not legal for this API. + */ + public boolean setProperty(String key, String value) + { + + if ( key.startsWith("--") ) { + key = key.substring(2); + } + Option option = options.getOption(key); + if (option == null ) { + return false; + } + cli_props.setProperty(key, value); + return true; + } + + public boolean hasProperty(String key) + { + return cli_props.containsKey(key); + } + + public String getProperty(String key) + { + return (String) cli_props.getProperty(key); + } + + synchronized void addWarning(String w) + { + this.warnings.add(w); + } + + + synchronized void addError(String e ) + { + this.errors.add(e); + } + + + synchronized void addMessage(String m) + { + this.messages.add(m); + } + + + synchronized void addErrors(ArrayList<String> e) + { + this.errors.addAll(e); + } + + synchronized void addWarnings(ArrayList<String> w) + { + this.warnings.addAll(w); + } + + synchronized public String[] getMessages() + { + return messages.toArray(new String[messages.size()]); + } + + synchronized public String[] getWarnings() + { + return warnings.toArray(new String[warnings.size()]); + } + + synchronized public String[] getErrors() + { + return errors.toArray(new String[errors.size()]); + } + + synchronized long getDuccId() + { + return friendlyId; + } + + protected void startConsoleListener() + throws Throwable + { + console_listener = new ConsoleListener(this); + Thread t = new Thread(console_listener); + t.start(); + } + + protected void stopConsoleListener() + { + if ( console_listener != null ) { + console_listener.shutdown(); + console_listener = null; + } + } + + protected void set_console_port(DuccProperties props, String key) + { + if ( key != null ) { + if ( console_listener == null ) { + addWarning("Attempt to set console port but listener is not running."); + return; + } + + String console_host_address = console_listener.getConsoleHostAddress(); + int console_listener_port = console_listener.getConsolePort(); + + String envval = "DUCC_CONSOLE_LISTENER"; + String env = props.getProperty(key); + // Set the host:port for the console listener into the env + String console_address = console_host_address + ":" + console_listener_port; + String dp = envval + "=" + console_address; + if ( env == null ) { + env = dp; + } else { + env = env + " " + dp; + } + props.setProperty(key, env); + } + } + + public boolean isConsoleAttached() + { + return ( (console_listener != null ) && ( !console_listener.isShutdown())); + } + + public void waitForCompletion() + { + if ( console_listener != null ) { + console_listener.waitForCompletion(); + } + console_listener = null; + } + + public void closeConsole() + { + if ( console_listener != null ) { + console_listener.shutdown(); + } + console_listener = null; + } + +} Added: uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/ConsoleListener.java URL: http://svn.apache.org/viewvc/uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/ConsoleListener.java?rev=1448703&view=auto ============================================================================== --- uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/ConsoleListener.java (added) +++ uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/ConsoleListener.java Thu Feb 21 16:13:54 2013 @@ -0,0 +1,256 @@ + +/* + * 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.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.HashMap; +import java.util.Map; + +import org.apache.uima.ducc.common.NodeIdentity; + +class ConsoleListener + implements Runnable +{ + private ServerSocket sock; + private CliBase submit; + private Map<Integer, StdioListener> listeners = new HashMap<Integer, StdioListener>(); + + private int console_listener_port; + private String console_host_address; + + private boolean in_shutdown = false; + private int callers; // number of remote processes we expect to listen for + + ConsoleListener(CliBase submit) + throws Throwable + { + this.submit = submit; + this.sock = new ServerSocket(0); + this.console_listener_port = sock.getLocalPort(); + + NodeIdentity ni = new NodeIdentity(); + this.console_host_address = ni.getIp(); + this.callers = 1; // assume we'll get at least one listener, else we would not have been called. + } + + String getConsoleHostAddress() + { + return console_host_address; + } + + int getConsolePort() + { + return console_listener_port; + } + + /** + * The caller knows there may be more than one remote process calling us but + * we've no clue when or if they will show up. We assume here they do, and + * rely on some external influence to correct us if not. + */ + synchronized void incrementCallers() + { + callers++; + } + + synchronized void waitForCompletion() + { + try { + while ( (callers > 0) && ( !in_shutdown) ) { + wait(); + } + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + private synchronized void releaseWait() + { + callers--; + notify(); + } + + synchronized boolean isShutdown() + { + return in_shutdown; + } + + void shutdown() + { + in_shutdown = true; + try { + sock.close(); + for ( StdioListener sl : listeners.values() ) { + sl.close(); + } + } catch (Throwable t) { + t.printStackTrace(); + } + } + + private void delete(int port) + { + listeners.remove(port); + if ( listeners.size() == 0 ) { + synchronized(submit) { + releaseWait(); + } + shutdown(); + } + } + + public void run() + { + System.out.println("Listening on " + console_host_address + " " + console_listener_port); + + while ( true ) { + try { + Socket s = sock.accept(); + StdioListener sl = new StdioListener(s, this); + int p = s.getPort(); + listeners.put(p, sl); + + Thread t = new Thread(sl); + t.start(); + } catch (Throwable t) { + if ( ! in_shutdown ) shutdown(); + return; + } + } + } + + class StdioListener + implements Runnable + { + Socket sock; + InputStream is; + boolean done = false; + ConsoleListener cl; + String remote_host; + String leader; + + StdioListener(Socket sock, ConsoleListener cl) + { + this.sock = sock; + this.cl = cl; + + InetAddress ia = sock.getInetAddress(); + remote_host = ia.getHostName(); + System.out.println("===== Listener starting: " + remote_host + ":" + sock.getPort()); + int ndx = remote_host.indexOf('.'); + if ( ndx >= 0 ) { + // this is just for console decoration, keep it short, who cares about the domain + remote_host = remote_host.substring(0, ndx); + } + leader = "[" + remote_host + "] "; + } + + public void close() + throws Throwable + { + System.out.println("===== Listener completing: " + remote_host + ":" + sock.getPort()); + this.done = true; + is.close(); + cl.delete(sock.getPort()); + } + + /** + * We received a buffer of bytes that needs to be put into a string and printed. We want + * to split along \n boundaries so we can insert the host name at the start of every line. + * + * Simple, except that the end of the buffer may not be \n, instead it could be the + * start of another line. + * + * We want to save the partial lines as the start of the next line so they can all be + * printed all nicely. + */ + String partial = null; + public void printlines(byte[] buf, int count) + { + String tmp = new String(buf, 0, count); + String[] lines = tmp.split("\n"); + int len = lines.length - 1; + if ( len < 0 ) { + // this is a lone linend. Spew the partial if it exists and just return. + if ( partial != null ) { + System.out.println(leader + partial); + partial = null; + } + return; + } + + + if ( partial != null ) { + // some leftover, it's the start of the first line of the new buffer. + lines[0] = partial + lines[0]; + partial = null; + } + + for ( int i = 0; i < len; i++ ) { + // spew everything but the last line + System.out.println(leader + lines[i]); + } + + if ( tmp.endsWith("\n") ) { + // if the last line ends with linend, there is no partial, just spew + System.out.println(leader + lines[len]); + partial = null; + } else { + // otherwise, wait for the next buffer + partial = lines[len]; + } + } + + public void run() + { + byte[] buf = new byte[4096]; + try { + is = sock.getInputStream(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return; + } + + try { + int count = 0; + while ( (count = is.read(buf)) > 0 ) { + printlines(buf, count); + } + System.out.println(leader + "EOF: exiting"); + } catch ( Throwable t ) { + t.printStackTrace(); + } + try { + close(); + } catch (Throwable e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + +} + Modified: uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccServiceApi.java URL: http://svn.apache.org/viewvc/uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccServiceApi.java?rev=1448703&r1=1448702&r2=1448703&view=diff ============================================================================== --- uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccServiceApi.java (original) +++ uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccServiceApi.java Thu Feb 21 16:13:54 2013 @@ -609,7 +609,7 @@ public class DuccServiceApi } // Must enforce this for registered services - reply.put(DuccUiConstants.parm_process_deployments_max, "1"); + reply.put(DuccUiConstants.name_process_deployments_max, "1"); // // Now: let's resolve placeholders. Modified: uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccUi.java URL: http://svn.apache.org/viewvc/uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccUi.java?rev=1448703&r1=1448702&r2=1448703&view=diff ============================================================================== --- uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccUi.java (original) +++ uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccUi.java Thu Feb 21 16:13:54 2013 @@ -37,4 +37,5 @@ public class DuccUi { } return retVal; } + } Modified: uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccUiConstants.java URL: http://svn.apache.org/viewvc/uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccUiConstants.java?rev=1448703&r1=1448702&r2=1448703&view=diff ============================================================================== --- uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccUiConstants.java (original) +++ uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccUiConstants.java Thu Feb 21 16:13:54 2013 @@ -267,6 +267,20 @@ public class DuccUiConstants { public static final String exmp_process_environment = "\"LANG=en_US.UTF-8\""; public static final String dval_process_environment = ""; + public static final String name_process_executable = "process_executable"; + public static final String parm_process_executable = "string"; + public static final String desc_process_executable = "Executable program."; + public static final String labl_process_executable = "Executable"; + public static final String exmp_process_executable = "/bin/sleep"; + public static final String dval_process_executable = ""; + + public static final String name_process_executable_args = "process_executable_args"; + public static final String parm_process_executable_args = "Argument String"; + public static final String desc_process_executable_args = "The process arguments."; + public static final String labl_process_executable_args = "Arguments"; + public static final String exmp_process_executable_args = "-i 20 -f out.file"; + public static final String dval_process_executable_args = ""; + public static final String name_process_memory_size = JobSpecificationProperties.key_process_memory_size; public static final String parm_process_memory_size = "size[KB|MB|GB|TB]"; public static final String desc_process_memory_size = "Size of memory for process, defaults to GB if units omitted."; Added: uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccletSubmit.java URL: http://svn.apache.org/viewvc/uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccletSubmit.java?rev=1448703&view=auto ============================================================================== --- uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccletSubmit.java (added) +++ uima/sandbox/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/DuccletSubmit.java Thu Feb 21 16:13:54 2013 @@ -0,0 +1,382 @@ +/* + * 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.lang.management.ManagementFactory; +import java.util.ArrayList; +import java.util.Properties; + +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionBuilder; +import org.apache.commons.cli.Options; +import org.apache.uima.ducc.common.crypto.Crypto; +import org.apache.uima.ducc.common.utils.DuccPropertiesResolver; +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; + + +/** + * Submit a DUCC service + */ + +public class DuccletSubmit + extends CliBase +{ + + static String or_port = "ducc.orchestrator.http.port"; + static String or_host = "ducc.orchestrator.node"; + boolean console_attach = false; + + int pid = -1; + ServiceRequestProperties serviceRequestProperties; + + public DuccletSubmit(String[] args) + throws Exception + { + serviceRequestProperties = new ServiceRequestProperties(); + init(args, serviceRequestProperties, or_host, or_port, "or"); + } + + public DuccletSubmit(Properties props) + throws Exception + { + serviceRequestProperties = new ServiceRequestProperties(); + // TODO - can we get OR to just use properties and not these specialized classes? + // Until then, we need to pass in the right kind of props, sigh. + for ( Object k : props.keySet() ) { + Object v = props.get(k); + serviceRequestProperties.put(k, v); + } + init(null, props, or_host, or_port, "or"); + } + + @SuppressWarnings("static-access") + 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 + .withArgName(DuccUiConstants.parm_description) + .withDescription(makeDesc(DuccUiConstants.desc_description,DuccUiConstants.exmp_description)).hasArg() + .withLongOpt(DuccUiConstants.name_description).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_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_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_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_specification) + .withDescription(DuccUiConstants.desc_specification) + .hasArg (true) + .withLongOpt (DuccUiConstants.name_specification) + .create () + ); + + options.addOption(OptionBuilder + .withDescription(DuccUiConstants.desc_process_attach_console) + .hasOptionalArg () + .withLongOpt (DuccUiConstants.name_process_attach_console) + .create () + ); + + options.addOption(OptionBuilder + .withArgName (DuccUiConstants.parm_process_executable) + .withDescription(makeDesc(DuccUiConstants.desc_process_executable,DuccUiConstants.exmp_process_executable)).hasArg() + .withLongOpt (DuccUiConstants.name_process_executable) + .hasArg (true) + .create () + ); + + options.addOption(OptionBuilder + .withArgName (DuccUiConstants.parm_process_executable_args) + .withDescription(makeDesc(DuccUiConstants.desc_process_executable_args,DuccUiConstants.exmp_process_executable_args)) + .hasArgs () + .withLongOpt (DuccUiConstants.name_process_executable_args) + .create () + ); + + } + + public boolean execute() throws Exception + { + /* + * parser is not thread safe? + */ + synchronized(DuccUi.class) { + + /* + * require DUCC_HOME + */ + String ducc_home_key = "DUCC_HOME"; + String ducc_home = System.getenv(ducc_home_key); + if(ducc_home == null) { + addError("missing required environment variable: " + ducc_home_key); + return false; + } + + /* + * 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(); + // 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); + } + } + + 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 = ""; + } + + name = trimmer(name); + value = trimmer(value); + setProperty(name, value); + } + } + + /* + * make sure the logdir is actually legal. + */ + String log_directory = getLogDirectory(serviceRequestProperties); + if ( log_directory == null ) { // on failure, the internal errors are already set + return false; + } + + // tack on "services" or "processes" to complete logging directory + if(log_directory.endsWith(File.separator)) { + log_directory = log_directory + "processes"; + } else { + log_directory = log_directory + File.separator + "processes"; + } + serviceRequestProperties.setProperty("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); + } + + // These must be enforce so OR doesn't complain + serviceRequestProperties.setProperty(DuccUiConstants.name_process_thread_count, "1"); + serviceRequestProperties.setProperty(DuccUiConstants.name_process_deployments_max, "1"); + + serviceRequestProperties.put(ServiceRequestProperties.key_service_type_other, ""); + + if(serviceRequestProperties.containsKey(DuccUiConstants.name_debug)) { + serviceRequestProperties.dump(); + } + + /* + * set DUCC_LD_LIBRARY_PATH in process environment + */ + adjustLdLibraryPath(serviceRequestProperties, ServiceRequestProperties.key_process_environment); + + /* + * identify invoker + */ + serviceRequestProperties.setProperty(ServiceRequestProperties.key_submitter_pid_at_host, ManagementFactory.getRuntimeMXBean().getName()); + + console_attach = + serviceRequestProperties.containsKey(DuccUiConstants.name_process_attach_console); + + if ( console_attach ) { + try { + startConsoleListener(); + } catch ( Throwable t ) { + throw new IllegalStateException("Cannot start console listener. Reason:" + t.getMessage()); + } + set_console_port(serviceRequestProperties, DuccUiConstants.name_process_environment); + } + + SubmitServiceDuccEvent ev = new SubmitServiceDuccEvent(serviceRequestProperties); + SubmitServiceReplyDuccEvent reply = null; + + try { + reply = (SubmitServiceReplyDuccEvent) dispatcher.dispatchAndWaitForDuccReply(ev); + } catch (Exception e) { + addError("Process not submitted: " + e.getMessage()); + return false; + } finally { + dispatcher.close(); + } + + /* + * process reply + */ + boolean retval = true; + Properties properties = reply.getProperties(); + @SuppressWarnings("unchecked") + ArrayList<String> or_warnings = (ArrayList<String>) properties.get(ServiceSpecificationProperties.key_submit_warnings); + if (or_warnings != null) { + addWarnings(or_warnings); + } + + @SuppressWarnings("unchecked") + ArrayList<String> or_errors = (ArrayList<String>) properties.get(ServiceSpecificationProperties.key_submit_errors); + if(or_errors != null) { + addErrors(or_errors); + retval = false; + } + + if ( retval ) { + String pid = reply.getProperties().getProperty(ServiceRequestProperties.key_id); + if (pid == null ) { + retval = false; + } else { + friendlyId = Long.parseLong(pid); + if ( friendlyId < 0 ) { + retval = false; + } else { + saveSpec(pid, "process.properties", serviceRequestProperties); + } + } + } + + return retval; + } + + public static void main(String[] args) + { + try { + DuccletSubmit ds = new DuccletSubmit(args); + boolean rc = ds.execute(); + + String [] messages = ds.getMessages(); + String [] warnings = ds.getWarnings(); + String [] errors = ds.getErrors(); + + if ( messages != null ) { + for (String s : messages ) { + System.out.println(s); + } + } + + if ( warnings != null ) { + for (String s : warnings ) { + System.out.println("WARN: " + s); + } + } + + if ( errors != null ) { + for (String s : errors ) { + System.out.println("ERROR: " + s); + } + } + + if ( rc ) { + System.out.println("Process " + ds.getDuccId() + " submitted."); + + if ( ds.isConsoleAttached() ) { + ds.waitForCompletion(); + } + + System.exit(0); + } else { + System.out.println("Could not submit process"); + System.exit(1); + } + } catch (Exception e) { + System.out.println("Cannot initialize: " + e.getMessage()); + System.exit(1); + } + } + +} Modified: uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/SubmitServiceDuccEvent.java URL: http://svn.apache.org/viewvc/uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/SubmitServiceDuccEvent.java?rev=1448703&r1=1448702&r2=1448703&view=diff ============================================================================== --- uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/SubmitServiceDuccEvent.java (original) +++ uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/SubmitServiceDuccEvent.java Thu Feb 21 16:13:54 2013 @@ -18,10 +18,18 @@ */ package org.apache.uima.ducc.transport.event; +import org.apache.uima.ducc.common.utils.DuccProperties; + @SuppressWarnings("serial") public class SubmitServiceDuccEvent extends AbstractDuccJobEvent { public SubmitServiceDuccEvent() { super(EventType.SUBMIT_SERVICE); } + + public SubmitServiceDuccEvent(DuccProperties props) + { + super(EventType.SUBMIT_SERVICE); + setProperties(props); + } } Modified: uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/cli/SpecificationProperties.java URL: http://svn.apache.org/viewvc/uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/cli/SpecificationProperties.java?rev=1448703&r1=1448702&r2=1448703&view=diff ============================================================================== --- uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/cli/SpecificationProperties.java (original) +++ uima/sandbox/uima-ducc/trunk/uima-ducc-transport/src/main/java/org/apache/uima/ducc/transport/event/cli/SpecificationProperties.java Thu Feb 21 16:13:54 2013 @@ -19,13 +19,14 @@ package org.apache.uima.ducc.transport.event.cli; import java.io.Serializable; -import java.util.Properties; + +import org.apache.uima.ducc.common.utils.DuccProperties; /** * Job characteristics provided by user. */ @SuppressWarnings("serial") -public class SpecificationProperties extends Properties implements Serializable { +public class SpecificationProperties extends DuccProperties implements Serializable { public static String key_submit_errors = "submit_errors"; public static String key_submit_warnings = "submit_warnings";