You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by bu...@apache.org on 2019/10/30 21:17:36 UTC
svn commit: r1869191 -
/uima/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/CliBase.java
Author: burn
Date: Wed Oct 30 21:17:35 2019
New Revision: 1869191
URL: http://svn.apache.org/viewvc?rev=1869191&view=rev
Log:
UIMA-6130 Reformat all but comments
Modified:
uima/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/CliBase.java
Modified: uima/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/CliBase.java
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/CliBase.java?rev=1869191&r1=1869190&r2=1869191&view=diff
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/CliBase.java (original)
+++ uima/uima-ducc/trunk/uima-ducc-cli/src/main/java/org/apache/uima/ducc/cli/CliBase.java Wed Oct 30 21:17:35 2019
@@ -47,782 +47,766 @@ import org.apache.uima.ducc.transport.ev
/**
* Define common methods and data used by all the DUCC API and CLI.
*/
-public abstract class CliBase
- implements IUiOptions
-{
-
- private String myClassName = "N/A";
- private boolean init_done = false;
- protected String ducc_home;
- protected IDuccEventDispatcher dispatcher;
-
- protected CommandLine commandLine;
-
- protected long friendlyId = -1;
- protected int returnCode = 0;
-
- protected DuccProperties cli_props;
- protected ArrayList<String> errors = new ArrayList<String>();
- protected ArrayList<String> warnings = new ArrayList<String>();
- protected ArrayList<String> messages = new ArrayList<String>();
-
- protected boolean debug;
- private boolean load_defaults = true;
-
- protected ConsoleListener console_listener = null;
- protected boolean suppress_console_log;
- protected String host_address = "N/A";
- protected boolean console_attach = false;
- protected IDuccCallback consoleCb = null;
-
- protected MonitorListener monitor_listener = null;
-
- CountDownLatch waiter = null;
-
- protected Properties userSpecifiedProperties;
-
- /**
- * All extenders must implement execute - this method does whatever processing on the input
- * is needed and passes the CLI request to the internal DUCC processes.
- *
- * @return Return true if execution works, and false otherwise.
- * @throws java.lang.Exception The specific exception is a function of the implementor.
- */
- public abstract boolean execute() throws Exception;
+public abstract class CliBase implements IUiOptions {
- protected void inhibitDefaults()
- {
- this.load_defaults = false;
- }
+ private String myClassName = "N/A";
- /*
- * Make the log directory absolute if necessary and check that it is usable.
- * If not provided it will have been given a default value.
- * UIMA-4617 Make it relative to the run-time working directory, not HOME
- */
- String getLogDirectory(String working_directory) throws IOException {
- String log_directory = cli_props.getProperty(UiOption.LogDirectory.pname());
- File f;
- if (log_directory.startsWith(File.separator)) {
- f = new File(log_directory);
- } else {
- f = new File(working_directory, log_directory); // Relative to working directory
- log_directory = f.getCanonicalPath();
- cli_props.setProperty(UiOption.LogDirectory.pname(), log_directory);
- }
+ private boolean init_done = false;
- /*
- * make sure the logdir is actually legal.
- * JD may also be creating it so to reduce any race or NFS delay blindly create and then test
- */
- f.mkdirs();
- if ( ! f.isDirectory() || ! f.canWrite()) {
- throw new IllegalArgumentException("Specified log_directory is not a writable directory: " + log_directory);
- }
+ protected String ducc_home;
- return log_directory;
- }
+ protected IDuccEventDispatcher dispatcher;
- /*
- * Ensure the working directory exists and is absolute
- */
- String getWorkingDirectory() throws IOException {
- String working_directory = cli_props.getProperty(UiOption.WorkingDirectory.pname());
- File f = new File(working_directory);
- if ( ! f.exists() ) {
- throw new IllegalArgumentException("Working directory " + working_directory + " does not exist.");
- }
- if ( ! f.isAbsolute() ) {
- working_directory = f.getCanonicalPath();
- cli_props.setProperty(UiOption.WorkingDirectory.pname(), working_directory);
- }
- return working_directory;
- }
+ protected CommandLine commandLine;
- /*
- * Check the syntax & if a service refers to itself -- place-holders already resolved
- * Strip any broker URL decorations
- */
- boolean check_service_dependencies(String endpoint)
- {
- String deps = cli_props.getProperty(UiOption.ServiceDependency.pname());
- try {
- String dependencies = DuccUiUtilities.check_service_dependencies(endpoint, deps);
- if (dependencies != null) {
- cli_props.setProperty(UiOption.ServiceDependency.pname(), dependencies);
- }
- return true;
- } catch ( Throwable t ) {
- message("ERROR:", t.toString());
- return false;
- }
- }
+ protected long friendlyId = -1;
- /*
- * Check if -Xmx value is >= memory size ... if both are specified
- */
- void check_heap_size(String argsOption) {
- String jvmArgs = cli_props.getProperty(argsOption);
- String memSize = cli_props.getProperty(UiOption.ProcessMemorySize.pname());
- if (jvmArgs == null || memSize == null) {
- return;
- }
+ protected int returnCode = 0;
- // The numbers may be terminated by a units factor, white-space, or the end of the string
- // The units factor may be any of kKmMgG ... if omitted is bytes
- // Match -Xmx###[units-flag] and take the last one specified (IBM & Oracle JREs do this)
- String xmxRegex = "-Xmx([0-9]+)($|[\\skKmMgG])";
- Pattern patn = Pattern.compile(xmxRegex);
- Matcher matcher = patn.matcher(jvmArgs);
- Long size = null;
- String unit = null;
- while (matcher.find()) {
- size = Long.valueOf(matcher.group(1));
- unit = matcher.group(2);
- }
- if (size == null) {
- return;
- }
- if (unit.isEmpty()) { // Was last option in list
- unit = " ";
- }
- char factor = unit.toLowerCase().charAt(0);
- int shift = "gmk".indexOf(factor); // Number of 1024's to divide size by to get GB
- if (shift < 0) { // No explicit unit factor ... white-space => bytes
- shift = 3;
- }
- long sizeGB = size >> (10 * shift); // Shift 10 bits per K
- int memGB = Integer.valueOf(memSize);
- if (sizeGB >= memGB) {
- String text = "WARNING - process_memory_size is " + memSize + "G but the max heap is " + size + unit + " --- swapping may occur";
- message(text);
- }
- }
+ protected DuccProperties cli_props;
- void setUser()
- throws Exception
- {
- /*
- * marshal user
- */
- String user = DuccUiUtilities.getUser();
- cli_props.setProperty(UiOption.User.pname(), 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(user, true);
- byte[] cypheredMessage = crypto.getSignature();
- cli_props.put(UiOption.Signature.pname(), cypheredMessage);
- }
- }
- }
+ protected ArrayList<String> errors = new ArrayList<String>();
- /*
- * Standard init for all except the Service calls that are sent to the SM
- */
+ protected ArrayList<String> warnings = new ArrayList<String>();
- protected synchronized void init(String myClassName, UiOption[] opts, String[] args, DuccProperties cli_props,
- IDuccCallback consoleCb) throws Exception {
- this.init (myClassName, opts, args, null, cli_props, consoleCb, "orchestrator");
- }
+ protected ArrayList<String> messages = new ArrayList<String>();
- protected synchronized void init(String myClassName, UiOption[] opts, Properties props, DuccProperties cli_props,
- IDuccCallback consoleCb) throws Exception {
- this.init (myClassName, opts, null, props, cli_props, consoleCb, "orchestrator");
- }
+ protected boolean debug;
- /**
- *
- * @param myClassName Name of the class invoking me, for help string
- * @param uiOpts Array of IUioptions permitted for this command
- * @param args Arguments from the command line (or null)
- * @param props Properties passed in from the API (or null)
- * @param cli_props (Initially) empty properties file to be filled in
- * @param consoleCb Console callback object (optional)
- * @param servlet The name of the http servlet that will serve this request
- * @throws Exception If initialization fails, e.g. invalid arguments or properties
- */
- protected synchronized void init(String myClassName, IUiOption[] uiOpts, String[] args, Properties props,
- DuccProperties cli_props, IDuccCallback consoleCb, String servlet)
- throws Exception
- {
-
- // Either args or props passed in, not both
- if (args != null) {
- CliFixups.cleanupArgs(args, myClassName);
- } else {
- CliFixups.cleanupProps(props, myClassName);
- }
+ private boolean load_defaults = true;
- if ( init_done ) return;
+ protected ConsoleListener console_listener = null;
- if ( consoleCb == null ) {
- this.consoleCb = new DefaultCallback();
- } else {
- this.consoleCb = consoleCb;
- }
-
- this.myClassName = myClassName;
- ducc_home = Utils.findDuccHome();
+ protected boolean suppress_console_log;
- this.cli_props = cli_props;
- commandLine = new CommandLine(args, uiOpts, props);
- try {
- commandLine.parse();
- } catch (Exception e) {
- usage(e.getMessage());
- }
+ protected String host_address = "N/A";
- if ( commandLine.contains(UiOption.Help)) {
- usage(null);
- }
+ protected boolean console_attach = false;
- debug = commandLine.contains(UiOption.Debug);
+ protected IDuccCallback consoleCb = null;
- // Load the specification file, if given on the command line. Note that registration
- // bypasses the somewhat redundant --specification option so we check two options.
- // Cannot have both as --specification && --register are never both valid.
- String fname = null;
- for (IUiOption spec : new IUiOption[]{ UiOption.Specification, UiOption.Register }) {
- if ( commandLine.isOption(spec) && commandLine.contains(spec)) { // legal for this command, and also specified?
- fname = commandLine.get(spec);
- if (fname.length() == 0) { // Check if --register has no value
- fname = null;
- }
- break;
- }
- }
- // If have a specification file re-parse using it for default values
- if ( fname != null ) {
- FileInputStream fis = new FileInputStream(new File(fname));
- Properties defaults = new Properties();
- defaults.load(fis);
- fis.close();
- CliFixups.cleanupProps(defaults, myClassName); // May correct or drop deprecated options
-
- // If invoked with overriding properties add to or replace the defaults
- if (props != null) {
- defaults.putAll(props);
- }
- commandLine = new CommandLine(args, uiOpts, defaults);
- commandLine.parse();
- }
- commandLine.verify(); // Insure all the rules specified by the IUiOpts are enforced
-
- // Copy options into cli_props
- setOptions(uiOpts);
-
- // Save a copy of the user-specified ones by cloning the underlying properties
- userSpecifiedProperties = (Properties)((Properties)cli_props).clone();
-
- // May need to suppress logging in console listener, or in the DUCC process.
- suppress_console_log = cli_props.containsKey(UiOption.SuppressConsoleLog.pname());
-
- // This is not used by DUCC ... allows ducc-mon to display the origin of a job
- cli_props.setProperty(UiOption.SubmitPid.pname(), ManagementFactory.getRuntimeMXBean().getName());
-
- // Apply defaults for and fixup the environment if needed
- // -- unless default loading is inhibited, as it must be for modify operations
- // What this routine does is fill in all the options that weren't specified
- // on the command line with their defaults. For 'modify' we want to bypass
- // this because ONLY the options from the command line should be set.
- // So modify must not change the log directory.
- if ( load_defaults ) {
- setDefaults(uiOpts, suppress_console_log);
- }
- setUser();
+ protected MonitorListener monitor_listener = null;
- //NodeIdentity ni = new NodeIdentity(); UIMA-3899, use getHostAddress() directly. jrc
- host_address = InetAddress.getLocalHost().getHostAddress();
+ CountDownLatch waiter = null;
- initConsoleListener();
+ protected Properties userSpecifiedProperties;
- // AllInOne doesn't dispatch requests (and local doesn't need a running DUCC!)
- if (!cli_props.containsKey(UiOption.AllInOne.pname())) {
- dispatcher = DispatcherFactory.create(cli_props, servlet);
- }
+ /**
+ * All extenders must implement execute - this method does whatever processing on the input
+ * is needed and passes the CLI request to the internal DUCC processes.
+ *
+ * @return Return true if execution works, and false otherwise.
+ * @throws java.lang.Exception The specific exception is a function of the implementor.
+ */
+ public abstract boolean execute() throws Exception;
- init_done = true;
+ protected void inhibitDefaults() {
+ this.load_defaults = false;
+ }
+
+ /*
+ * Make the log directory absolute if necessary and check that it is usable.
+ * If not provided it will have been given a default value.
+ * UIMA-4617 Make it relative to the run-time working directory, not HOME
+ */
+ String getLogDirectory(String working_directory) throws IOException {
+ String log_directory = cli_props.getProperty(UiOption.LogDirectory.pname());
+ File f;
+ if (log_directory.startsWith(File.separator)) {
+ f = new File(log_directory);
+ } else {
+ f = new File(working_directory, log_directory); // Relative to working directory
+ log_directory = f.getCanonicalPath();
+ cli_props.setProperty(UiOption.LogDirectory.pname(), log_directory);
}
/*
- * Save options as properties after resolving any ${..} placeholders
+ * make sure the logdir is actually legal.
+ * JD may also be creating it so to reduce any race or NFS delay blindly create and then test
*/
- void setOptions(IUiOption[] uiOpts)
- throws Exception
- {
- // Find the environment variables that are always propagated
- List<String> envNameList;
- String envNames = DuccPropertiesResolver.get(DuccPropertiesResolver.ducc_environment_propagated);
- if (envNames != null) {
- envNameList = Arrays.asList(envNames.split("\\s+"));
- } else {
- envNameList = new ArrayList<String>(0);
- }
-
- Map<IUiOption, String> parsed = commandLine.allOptions();
- for (IUiOption opt : parsed.keySet() ) {
- // If a "flexible" boolean that accepts various true/false values, add it only if true
- String val;
- if (opt.optargs() && "true".equals(opt.deflt())) {
- boolean bval = commandLine.getBoolean(opt);
- if (bval) {
- val = "";
- } else {
- if (debug) System.out.println("CLI omitted boolean " + opt.pname() + " = '" + parsed.get(opt) + "'");
- continue;
- }
- } else {
- val = parsed.get(opt);
- if (val == null) { // Should only happen for no-arg options
- val = "";
- } else {
- if (val.contains("${")) {
- val = resolvePlaceholders(val, envNameList);
- }
- }
- }
- val = val.trim();
- cli_props.put(opt.pname(), val);
- if (debug) System.out.println("CLI set " + opt.pname() + " = '" + val + "'");
- }
+ f.mkdirs();
+ if (!f.isDirectory() || !f.canWrite()) {
+ throw new IllegalArgumentException("Specified log_directory is not a writable directory: " + log_directory);
}
- /*
- * Check for missing required options, set defaults, and validate where possible
- * Also fixup the environment for all that use it.
- */
- void setDefaults(IUiOption[] uiOpts, boolean suppress_console) throws IOException {
- String logDir = null, workingDir = null;
- ArrayList<String> envNameList = new ArrayList<String>(0); // Why this when are resolving against use caller's environment?
- for (IUiOption uiopt : uiOpts) {
- if (!cli_props.containsKey(uiopt.pname())) {
- //
- // here deal with stuff that wasn't given explicitly in the command
- //
- // our convention - optargs() implies boolean, but it does't have to.
- // If the arg is not expllicitly specified, we assume
- // it is (boolean,false) for the sake of dealing with defaults.
- // -- and then just leave it out --
- // similarly - noargs() is definitely boolean, same treatement
- //
- if ( (! uiopt.optargs()) && (! uiopt.noargs() ) && uiopt.deflt() != null) {
- String deflt = uiopt.deflt();
- if (deflt.startsWith("$$")) { // Lookup default in ducc.properties
- deflt = DuccPropertiesResolver.get(deflt.substring(2));
- if (deflt == null) {
- throw new IllegalArgumentException("Invalid default (undefined property) for " + uiopt.pname());
- }
- } else if (deflt.contains("${")) {
- deflt = resolvePlaceholders(deflt, envNameList);
- }
- if (debug) System.out.println("CLI set default: " + uiopt.pname() + " = " + deflt);
- cli_props.put(uiopt.pname(), deflt);
- }
- } else {
- //
- // here clean up stuff that was specified but we want to validate it
- //
- if (uiopt == UiOption.ProcessMemorySize || uiopt == UiOption.ReservationMemorySize) {
- String val = cli_props.getStringProperty(uiopt.pname());
- if (!val.matches("^\\d+$")) {
- throw new IllegalArgumentException("Invalid non-numeric value for " + uiopt.pname() + ": " + val);
- }
- }
- }
- // NOTE: These 3 options must be in this order so each depends on the previous
- if (uiopt == UiOption.WorkingDirectory) {
- workingDir = getWorkingDirectory();
- } else if (uiopt == UiOption.LogDirectory) {
- logDir = getLogDirectory(workingDir);
- } else if (uiopt == UiOption.Environment) {
- // If this request accepts the --environment option may need to augment it by
- // renaming LD_LIBRARY_PATH & propagating some user values
- // Pass in the log directory so DUCC_UMASK may be set. UIMA-5328
- String environment = cli_props.getProperty(uiopt.pname());
- String allInOne = cli_props.getProperty(UiOption.AllInOne.pname());
- environment = DuccUiUtilities.fixupEnvironment(environment, allInOne, logDir);
- cli_props.setProperty(uiopt.pname(), environment);
- }
- }
- }
+ return log_directory;
+ }
- /*
- * Resolve any ${..} placeholders against user's system properties and environment
- * NOTE - this resolves against the caller's sys-props & environment ... the one in DuccUiUtilities
- * resolves against the process JVM args to match what is done by Spring in UIMA-AS.
- * 2.0: Leave unresolved entries as is & warn if not one of the always-propagated ones
- */
- private String resolvePlaceholders(String contents, List<String> envNameList) {
- // Placeholders syntax ${<placeholder>}
- Pattern pattern = Pattern.compile("\\$\\{(.*?)\\}"); // Stops on first '}'
- Matcher matcher = pattern.matcher(contents);
-
- StringBuffer sb = new StringBuffer();
- while (matcher.find()) {
- final String key = matcher.group(1);
- String value = System.getProperty(key);
- if (value == null) {
- value = System.getenv(key);
- }
- if (value != null) {
- matcher.appendReplacement(sb, value);
- } else {
- matcher.appendReplacement(sb, ""); // Can't include the value as it looks like a group specification
- value = "${" + key + "}";
- sb.append(value);
- if (!envNameList.contains(key)) {
- message("WARN: undefined placeholder", value, "not replaced");
- }
- }
- }
- matcher.appendTail(sb);
- return sb.toString();
+ /*
+ * Ensure the working directory exists and is absolute
+ */
+ String getWorkingDirectory() throws IOException {
+ String working_directory = cli_props.getProperty(UiOption.WorkingDirectory.pname());
+ File f = new File(working_directory);
+ if (!f.exists()) {
+ throw new IllegalArgumentException("Working directory " + working_directory + " does not exist.");
+ }
+ if (!f.isAbsolute()) {
+ working_directory = f.getCanonicalPath();
+ cli_props.setProperty(UiOption.WorkingDirectory.pname(), working_directory);
+ }
+ return working_directory;
+ }
+
+ /*
+ * Check the syntax & if a service refers to itself -- place-holders already resolved
+ * Strip any broker URL decorations
+ */
+ boolean check_service_dependencies(String endpoint) {
+ String deps = cli_props.getProperty(UiOption.ServiceDependency.pname());
+ try {
+ String dependencies = DuccUiUtilities.check_service_dependencies(endpoint, deps);
+ if (dependencies != null) {
+ cli_props.setProperty(UiOption.ServiceDependency.pname(), dependencies);
+ }
+ return true;
+ } catch (Throwable t) {
+ message("ERROR:", t.toString());
+ return false;
}
+ }
- /*
- * Undocumented feature:
- * Existence of environment variable DUCC_SAVE_SPECIFICATION
- * will result in specification written to filesystem,
- * otherwise not. Orchestrator writes specifications to DB.
- */
- private boolean isSaveSpecification() {
- boolean retVal = false;
- String savespec = System.getenv("DUCC_SAVE_SPECIFICATION");
- if ( savespec != null ) {
- retVal = true;
- }
- return retVal;
- }
-
- /*
- * If DB is disabled, then save specification to filesystem
- */
- private boolean isDbDisabled() {
- boolean retVal = DbHelper.isDbEnabled();
- return retVal;
+ /*
+ * Check if -Xmx value is >= memory size ... if both are specified
+ */
+ void check_heap_size(String argsOption) {
+ String jvmArgs = cli_props.getProperty(argsOption);
+ String memSize = cli_props.getProperty(UiOption.ProcessMemorySize.pname());
+ if (jvmArgs == null || memSize == null) {
+ return;
+ }
+
+ // The numbers may be terminated by a units factor, white-space, or the end of the string
+ // The units factor may be any of kKmMgG ... if omitted is bytes
+ // Match -Xmx###[units-flag] and take the last one specified (IBM & Oracle JREs do this)
+ String xmxRegex = "-Xmx([0-9]+)($|[\\skKmMgG])";
+ Pattern patn = Pattern.compile(xmxRegex);
+ Matcher matcher = patn.matcher(jvmArgs);
+ Long size = null;
+ String unit = null;
+ while (matcher.find()) {
+ size = Long.valueOf(matcher.group(1));
+ unit = matcher.group(2);
+ }
+ if (size == null) {
+ return;
+ }
+ if (unit.isEmpty()) { // Was last option in list
+ unit = " ";
+ }
+ char factor = unit.toLowerCase().charAt(0);
+ int shift = "gmk".indexOf(factor); // Number of 1024's to divide size by to get GB
+ if (shift < 0) { // No explicit unit factor ... white-space => bytes
+ shift = 3;
+ }
+ long sizeGB = size >> (10 * shift); // Shift 10 bits per K
+ int memGB = Integer.valueOf(memSize);
+ if (sizeGB >= memGB) {
+ String text = "WARNING - process_memory_size is " + memSize + "G but the max heap is " + size + unit + " --- swapping may occur";
+ message(text);
+ }
+ }
+
+ void setUser() throws Exception {
+ /*
+ * marshal user
+ */
+ String user = DuccUiUtilities.getUser();
+ cli_props.setProperty(UiOption.User.pname(), 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(user, true);
+ byte[] cypheredMessage = crypto.getSignature();
+ cli_props.put(UiOption.Signature.pname(), cypheredMessage);
+ }
}
-
- /*
- * Save specification to filesystem if:
- * 1. User requested or
- * 2. DB is disabled
- */
- private boolean isSavable() {
- boolean retVal = false;
- if(isSaveSpecification()) {
- retVal = true;
- }
- else if(isDbDisabled()) {
- retVal = true;
- }
- return retVal;
- }
-
- void saveSpec(String name, DuccProperties props)
- throws Exception
- {
- if ( ! isSavable() ) {
- return;
- }
- String directory = props.getProperty("log_directory") + File.separator + friendlyId;
- String fileName = directory + File.separator + name;
- File f = new File(directory);
-
- f.mkdirs();
- if ( ! f.exists() ) {
- throw new IllegalStateException("saveSpec: Cannot create log directory: " + f.toString());
- }
+ }
- // Save the specification (but exclude the 'signature' entry)
- String comments = null;
- OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(fileName));
- String key = UiOption.Signature.pname();
- if ( props.containsKey(key) ) {
- Object value = props.remove(key);
- props.store(out, comments);
- props.put(key, value);
- } else {
- props.store(out, comments);
- }
- out.close();
+ /*
+ * Standard init for all except the Service calls that are sent to the SM
+ */
- // Also save just the values the user provided
- fileName = directory + File.separator + DuccUiConstants.user_specified_properties;
- out = new OutputStreamWriter(new FileOutputStream(fileName));
- userSpecifiedProperties.store(out, comments);
- out.close();
- }
-
- /**
- * Extract messages and job pid from reply. This sets messages and errors into the appropriate
- * structures for the API, and extracts the numeric id of the [job, ducclet, reservation, service]
- * returned by the Orchestrator.
- *
- * @param reply - an Orchestrator reply event
- *
- * @return true if the action succeeded and false otherwise. The action in this case, is whatever
- * the Orchestrator was asked to do: submit something, cancel something, etc.
- */
- boolean extractReply(AbstractDuccOrchestratorEvent reply)
- {
- /*
- * process reply
- */
- boolean rc = true;
- Properties properties = reply.getProperties();
- @SuppressWarnings("unchecked")
- ArrayList<String> value_submit_warnings = (ArrayList<String>) properties.get(UiOption.SubmitWarnings.pname());
- if(value_submit_warnings != null) {
- message("Job warnings:");
- Iterator<String> reasons = value_submit_warnings.iterator();
- while(reasons.hasNext()) {
- message("WARN:", reasons.next());
- }
- }
- @SuppressWarnings("unchecked")
- ArrayList<String> value_submit_errors = (ArrayList<String>) properties.get(UiOption.SubmitErrors.pname());
- if(value_submit_errors != null) {
- message("Job errors:");
- Iterator<String> reasons = value_submit_errors.iterator();
- while(reasons.hasNext()) {
- message("ERROR:", reasons.next());
- }
- rc = false;
- }
+ protected synchronized void init(String myClassName, UiOption[] opts, String[] args, DuccProperties cli_props, IDuccCallback consoleCb)
+ throws Exception {
+ this.init(myClassName, opts, args, null, cli_props, consoleCb, "orchestrator");
+ }
+
+ protected synchronized void init(String myClassName, UiOption[] opts, Properties props, DuccProperties cli_props, IDuccCallback consoleCb)
+ throws Exception {
+ this.init(myClassName, opts, null, props, cli_props, consoleCb, "orchestrator");
+ }
- String pid = reply.getProperties().getProperty(UiOption.JobId.pname());
- if (pid == null ) {
- message("ERROR: Request ID not found in reply");
- rc = false;
- } else {
- friendlyId = Long.parseLong(pid);
- if ( friendlyId < 0 ) {
- message("ERROR: Invalid Request ID", pid);
- rc = false;
- }
- }
+ /**
+ *
+ * @param myClassName Name of the class invoking me, for help string
+ * @param uiOpts Array of IUioptions permitted for this command
+ * @param args Arguments from the command line (or null)
+ * @param props Properties passed in from the API (or null)
+ * @param cli_props (Initially) empty properties file to be filled in
+ * @param consoleCb Console callback object (optional)
+ * @param servlet The name of the http servlet that will serve this request
+ * @throws Exception If initialization fails, e.g. invalid arguments or properties
+ */
+ protected synchronized void init(String myClassName, IUiOption[] uiOpts, String[] args, Properties props, DuccProperties cli_props,
+ IDuccCallback consoleCb, String servlet) throws Exception {
- return rc;
+ // Either args or props passed in, not both
+ if (args != null) {
+ CliFixups.cleanupArgs(args, myClassName);
+ } else {
+ CliFixups.cleanupProps(props, myClassName);
}
- void usage(String message)
- {
- if ( message != null ) {
- System.out.println(message);
- }
- System.out.println(commandLine.formatHelp(myClassName));
- System.exit(1);
+ if (init_done)
+ return;
+
+ if (consoleCb == null) {
+ this.consoleCb = new DefaultCallback();
+ } else {
+ this.consoleCb = consoleCb;
}
- /**
- * Set a property via the API. This method allows the API user to
- * build up or override properties after the initial API object is constructed.
- *
- * @param key This is the property name.
- * @param value This is the value of the property.
- *
- * @return true if the property is set. Returns false if the property is not legal for this API.
- */
- public boolean setProperty(String key, String value)
- {
+ this.myClassName = myClassName;
+ ducc_home = Utils.findDuccHome();
- if ( ! commandLine.isOptionName(key)) {
- return false;
- }
- cli_props.setProperty(key, value);
- return true;
+ this.cli_props = cli_props;
+ commandLine = new CommandLine(args, uiOpts, props);
+ try {
+ commandLine.parse();
+ } catch (Exception e) {
+ usage(e.getMessage());
}
- protected IDuccCallback getCallback()
- {
- return consoleCb;
+ if (commandLine.contains(UiOption.Help)) {
+ usage(null);
}
- /*
- * NOTE: We do NOT want to be intentionally throwing from the CLI. Pls pass e.getMessage() or
- * e.toString() to this instead of throwing.
- */
- synchronized void message(String ... e )
- {
- if ( e.length > 1 ) {
- StringBuffer sb = new StringBuffer();
- int i = 0;
- for (i = 0; i < e.length - 1; i++) {
- sb.append(e[i]);
- sb.append(' ');
- }
- sb.append(e[i]);
- consoleCb.status(sb.toString());
- } else {
- consoleCb.status(e[0]);
- }
- }
+ debug = commandLine.contains(UiOption.Debug);
- /**
- * This returns the return code from the execution of the requested work. Return code is only
- * available when the monitor wait completes ... if not waiting then assume success.
- *
- * @return The exit code of the job, process, etc.
- */
- public int getReturnCode()
- {
- waitForCompletion();
- return returnCode;
+ // Load the specification file, if given on the command line. Note that registration
+ // bypasses the somewhat redundant --specification option so we check two options.
+ // Cannot have both as --specification && --register are never both valid.
+ String fname = null;
+ for (IUiOption spec : new IUiOption[] { UiOption.Specification, UiOption.Register }) {
+ if (commandLine.isOption(spec) && commandLine.contains(spec)) { // legal for this command, and also specified?
+ fname = commandLine.get(spec);
+ if (fname.length() == 0) { // Check if --register has no value
+ fname = null;
+ }
+ break;
+ }
}
+ // If have a specification file re-parse using it for default values
+ if (fname != null) {
+ FileInputStream fis = new FileInputStream(new File(fname));
+ Properties defaults = new Properties();
+ defaults.load(fis);
+ fis.close();
+ CliFixups.cleanupProps(defaults, myClassName); // May correct or drop deprecated options
- /**
- * This returns the unique numeric id for the requested work. For submissions (job, reservation, etc)
- * this is the newly assigned id.
- * @return The unique numeric id of the job, reservation, etc.
- */
- synchronized public long getDuccId()
- {
- return friendlyId;
- }
-
- synchronized void consoleExits()
- {
- if ( waiter != null ) waiter.countDown();
- }
-
- synchronized void monitorExits(int rc)
- {
- this.returnCode = rc;
- if ( waiter != null ) waiter.countDown();
- if ( console_listener != null ) {
- console_listener.shutdown();
- }
+ // If invoked with overriding properties add to or replace the defaults
+ if (props != null) {
+ defaults.putAll(props);
+ }
+ commandLine = new CommandLine(args, uiOpts, defaults);
+ commandLine.parse();
}
+ commandLine.verify(); // Insure all the rules specified by the IUiOpts are enforced
- // TODO TODO TODO - do we have to support lots of these for multi-threaded stuff? Hope not ...
- protected synchronized void startMonitors(boolean start_stdin, DuccContext context)
- throws Exception
- {
- int wait_count = 0;
+ // Copy options into cli_props
+ setOptions(uiOpts);
- if ( console_listener != null ) {
- wait_count++;
- }
+ // Save a copy of the user-specified ones by cloning the underlying properties
+ userSpecifiedProperties = (Properties) ((Properties) cli_props).clone();
- boolean monitor_attach =
- (
- cli_props.containsKey(UiOption.WaitForCompletion.pname()) ||
- cli_props.containsKey(UiOption.CancelOnInterrupt.pname())
- );
+ // May need to suppress logging in console listener, or in the DUCC process.
+ suppress_console_log = cli_props.containsKey(UiOption.SuppressConsoleLog.pname());
- if ( monitor_attach ) {
- wait_count++;
- }
+ // This is not used by DUCC ... allows ducc-mon to display the origin of a job
+ cli_props.setProperty(UiOption.SubmitPid.pname(), ManagementFactory.getRuntimeMXBean().getName());
- // Probably over-cautious but create the waiter before starting the threads that use it
- if ( wait_count > 0 ) {
- waiter = new CountDownLatch(wait_count);
- if ( console_listener != null ) {
- startConsoleListener(start_stdin);
- }
- if ( monitor_attach ) {
- startMonitor(context);
- }
- }
+ // Apply defaults for and fixup the environment if needed
+ // -- unless default loading is inhibited, as it must be for modify operations
+ // What this routine does is fill in all the options that weren't specified
+ // on the command line with their defaults. For 'modify' we want to bypass
+ // this because ONLY the options from the command line should be set.
+ // So modify must not change the log directory.
+ if (load_defaults) {
+ setDefaults(uiOpts, suppress_console_log);
}
+ setUser();
+
+ //NodeIdentity ni = new NodeIdentity(); UIMA-3899, use getHostAddress() directly. jrc
+ host_address = InetAddress.getLocalHost().getHostAddress();
+
+ initConsoleListener();
- protected synchronized void startMonitor(DuccContext context)
- {
- monitor_listener = new MonitorListener(this, friendlyId, cli_props, context);
- Thread mlt = new Thread(monitor_listener); //MonitorListenerThread
- mlt.start();
+ // AllInOne doesn't dispatch requests (and local doesn't need a running DUCC!)
+ if (!cli_props.containsKey(UiOption.AllInOne.pname())) {
+ dispatcher = DispatcherFactory.create(cli_props, servlet);
}
- /*
- * Needs to be done before submitting the job because the job needs the ports. We'll
- * just define the listener, but not start it until the job monitor starts, in case the
- * submission fails.
- */
- protected void initConsoleListener() throws Exception {
- String value;
+ init_done = true;
+ }
- console_attach = cli_props.containsKey(UiOption.AttachConsole.pname());
- if (console_attach) {
- console_listener = new ConsoleListener(this, consoleCb);
- value = console_listener.getConsoleHostAddress();
- if (myClassName.equals(DuccManagedReservationSubmit.class.getName())) {
- value += "?splitstreams"; // Add a query string so APs have separate streams
- }
- } else if (suppress_console_log) {
- value = "suppress";
+ /*
+ * Save options as properties after resolving any ${..} placeholders
+ */
+ void setOptions(IUiOption[] uiOpts) throws Exception {
+ // Find the environment variables that are always propagated
+ List<String> envNameList;
+ String envNames = DuccPropertiesResolver.get(DuccPropertiesResolver.ducc_environment_propagated);
+ if (envNames != null) {
+ envNameList = Arrays.asList(envNames.split("\\s+"));
+ } else {
+ envNameList = new ArrayList<String>(0);
+ }
+
+ Map<IUiOption, String> parsed = commandLine.allOptions();
+ for (IUiOption opt : parsed.keySet()) {
+ // If a "flexible" boolean that accepts various true/false values, add it only if true
+ String val;
+ if (opt.optargs() && "true".equals(opt.deflt())) {
+ boolean bval = commandLine.getBoolean(opt);
+ if (bval) {
+ val = "";
} else {
- return;
- }
- // Set the console "suppress" flag or the host:port for the console listener into the env
- String key = UiOption.Environment.pname();
- String env = cli_props.getProperty(key);
- if (env == null) {
- env = "DUCC_CONSOLE_LISTENER=" + value;
+ if (debug)
+ System.out.println("CLI omitted boolean " + opt.pname() + " = '" + parsed.get(opt) + "'");
+ continue;
+ }
+ } else {
+ val = parsed.get(opt);
+ if (val == null) { // Should only happen for no-arg options
+ val = "";
} else {
- env += " DUCC_CONSOLE_LISTENER=" + value;
- }
- cli_props.setProperty(key, env);
+ if (val.contains("${")) {
+ val = resolvePlaceholders(val, envNameList);
+ }
+ }
+ }
+ val = val.trim();
+ cli_props.put(opt.pname(), val);
+ if (debug)
+ System.out.println("CLI set " + opt.pname() + " = '" + val + "'");
+ }
+ }
+
+ /*
+ * Check for missing required options, set defaults, and validate where possible
+ * Also fixup the environment for all that use it.
+ */
+ void setDefaults(IUiOption[] uiOpts, boolean suppress_console) throws IOException {
+ String logDir = null, workingDir = null;
+ ArrayList<String> envNameList = new ArrayList<String>(0); // Why this when are resolving against use caller's environment?
+ for (IUiOption uiopt : uiOpts) {
+ if (!cli_props.containsKey(uiopt.pname())) {
+ //
+ // here deal with stuff that wasn't given explicitly in the command
+ //
+ // our convention - optargs() implies boolean, but it does't have to.
+ // If the arg is not expllicitly specified, we assume
+ // it is (boolean,false) for the sake of dealing with defaults.
+ // -- and then just leave it out --
+ // similarly - noargs() is definitely boolean, same treatement
+ //
+ if ((!uiopt.optargs()) && (!uiopt.noargs()) && uiopt.deflt() != null) {
+ String deflt = uiopt.deflt();
+ if (deflt.startsWith("$$")) { // Lookup default in ducc.properties
+ deflt = DuccPropertiesResolver.get(deflt.substring(2));
+ if (deflt == null) {
+ throw new IllegalArgumentException("Invalid default (undefined property) for " + uiopt.pname());
+ }
+ } else if (deflt.contains("${")) {
+ deflt = resolvePlaceholders(deflt, envNameList);
+ }
+ if (debug)
+ System.out.println("CLI set default: " + uiopt.pname() + " = " + deflt);
+ cli_props.put(uiopt.pname(), deflt);
+ }
+ } else {
+ //
+ // here clean up stuff that was specified but we want to validate it
+ //
+ if (uiopt == UiOption.ProcessMemorySize || uiopt == UiOption.ReservationMemorySize) {
+ String val = cli_props.getStringProperty(uiopt.pname());
+ if (!val.matches("^\\d+$")) {
+ throw new IllegalArgumentException("Invalid non-numeric value for " + uiopt.pname() + ": " + val);
+ }
+ }
+ }
+ // NOTE: These 3 options must be in this order so each depends on the previous
+ if (uiopt == UiOption.WorkingDirectory) {
+ workingDir = getWorkingDirectory();
+ } else if (uiopt == UiOption.LogDirectory) {
+ logDir = getLogDirectory(workingDir);
+ } else if (uiopt == UiOption.Environment) {
+ // If this request accepts the --environment option may need to augment it by
+ // renaming LD_LIBRARY_PATH & propagating some user values
+ // Pass in the log directory so DUCC_UMASK may be set. UIMA-5328
+ String environment = cli_props.getProperty(uiopt.pname());
+ String allInOne = cli_props.getProperty(UiOption.AllInOne.pname());
+ environment = DuccUiUtilities.fixupEnvironment(environment, allInOne, logDir);
+ cli_props.setProperty(uiopt.pname(), environment);
+ }
+ }
+ }
+
+ /*
+ * Resolve any ${..} placeholders against user's system properties and environment
+ * NOTE - this resolves against the caller's sys-props & environment ... the one in DuccUiUtilities
+ * resolves against the process JVM args to match what is done by Spring in UIMA-AS.
+ * 2.0: Leave unresolved entries as is & warn if not one of the always-propagated ones
+ */
+ private String resolvePlaceholders(String contents, List<String> envNameList) {
+ // Placeholders syntax ${<placeholder>}
+ Pattern pattern = Pattern.compile("\\$\\{(.*?)\\}"); // Stops on first '}'
+ Matcher matcher = pattern.matcher(contents);
+
+ StringBuffer sb = new StringBuffer();
+ while (matcher.find()) {
+ final String key = matcher.group(1);
+ String value = System.getProperty(key);
+ if (value == null) {
+ value = System.getenv(key);
+ }
+ if (value != null) {
+ matcher.appendReplacement(sb, value);
+ } else {
+ matcher.appendReplacement(sb, ""); // Can't include the value as it looks like a group specification
+ value = "${" + key + "}";
+ sb.append(value);
+ if (!envNameList.contains(key)) {
+ message("WARN: undefined placeholder", value, "not replaced");
+ }
+ }
+ }
+ matcher.appendTail(sb);
+ return sb.toString();
+ }
+
+ /*
+ * Undocumented feature:
+ * Existence of environment variable DUCC_SAVE_SPECIFICATION
+ * will result in specification written to filesystem,
+ * otherwise not. Orchestrator writes specifications to DB.
+ */
+ private boolean isSaveSpecification() {
+ boolean retVal = false;
+ String savespec = System.getenv("DUCC_SAVE_SPECIFICATION");
+ if (savespec != null) {
+ retVal = true;
}
+ return retVal;
+ }
+ /*
+ * If DB is disabled, then save specification to filesystem
+ */
+ private boolean isDbDisabled() {
+ boolean retVal = DbHelper.isDbEnabled();
+ return retVal;
+ }
+
+ /*
+ * Save specification to filesystem if:
+ * 1. User requested or
+ * 2. DB is disabled
+ */
+ private boolean isSavable() {
+ boolean retVal = false;
+ if (isSaveSpecification()) {
+ retVal = true;
+ } else if (isDbDisabled()) {
+ retVal = true;
+ }
+ return retVal;
+ }
+
+ void saveSpec(String name, DuccProperties props) throws Exception {
+ if (!isSavable()) {
+ return;
+ }
+ String directory = props.getProperty("log_directory") + File.separator + friendlyId;
+ String fileName = directory + File.separator + name;
+ File f = new File(directory);
+
+ f.mkdirs();
+ if (!f.exists()) {
+ throw new IllegalStateException("saveSpec: Cannot create log directory: " + f.toString());
+ }
+
+ // Save the specification (but exclude the 'signature' entry)
+ String comments = null;
+ OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(fileName));
+ String key = UiOption.Signature.pname();
+ if (props.containsKey(key)) {
+ Object value = props.remove(key);
+ props.store(out, comments);
+ props.put(key, value);
+ } else {
+ props.store(out, comments);
+ }
+ out.close();
+
+ // Also save just the values the user provided
+ fileName = directory + File.separator + DuccUiConstants.user_specified_properties;
+ out = new OutputStreamWriter(new FileOutputStream(fileName));
+ userSpecifiedProperties.store(out, comments);
+ out.close();
+ }
+
+ /**
+ * Extract messages and job pid from reply. This sets messages and errors into the appropriate
+ * structures for the API, and extracts the numeric id of the [job, ducclet, reservation, service]
+ * returned by the Orchestrator.
+ *
+ * @param reply - an Orchestrator reply event
+ *
+ * @return true if the action succeeded and false otherwise. The action in this case, is whatever
+ * the Orchestrator was asked to do: submit something, cancel something, etc.
+ */
+ boolean extractReply(AbstractDuccOrchestratorEvent reply) {
/*
- * Be sure to call this BEFORE submission, to insure the callback address is set in properties.
+ * process reply
*/
- protected synchronized void startConsoleListener(boolean start_stdin)
- throws Exception
- {
- if ( console_attach ) {
- console_listener.startStdin(start_stdin);
- Thread t = new Thread(console_listener);
- t.start();
- } else {
- message("WARN: Attermpt to start console but no console listener is defined.");
- }
+ boolean rc = true;
+ Properties properties = reply.getProperties();
+ @SuppressWarnings("unchecked")
+ ArrayList<String> value_submit_warnings = (ArrayList<String>) properties.get(UiOption.SubmitWarnings.pname());
+ if (value_submit_warnings != null) {
+ message("Job warnings:");
+ Iterator<String> reasons = value_submit_warnings.iterator();
+ while (reasons.hasNext()) {
+ message("WARN:", reasons.next());
+ }
+ }
+ @SuppressWarnings("unchecked")
+ ArrayList<String> value_submit_errors = (ArrayList<String>) properties.get(UiOption.SubmitErrors.pname());
+ if (value_submit_errors != null) {
+ message("Job errors:");
+ Iterator<String> reasons = value_submit_errors.iterator();
+ while (reasons.hasNext()) {
+ message("ERROR:", reasons.next());
+ }
+ rc = false;
+ }
+
+ String pid = reply.getProperties().getProperty(UiOption.JobId.pname());
+ if (pid == null) {
+ message("ERROR: Request ID not found in reply");
+ rc = false;
+ } else {
+ friendlyId = Long.parseLong(pid);
+ if (friendlyId < 0) {
+ message("ERROR: Invalid Request ID", pid);
+ rc = false;
+ }
+ }
+
+ return rc;
+ }
+
+ void usage(String message) {
+ if (message != null) {
+ System.out.println(message);
+ }
+ System.out.println(commandLine.formatHelp(myClassName));
+ System.exit(1);
+ }
+
+ /**
+ * Set a property via the API. This method allows the API user to
+ * build up or override properties after the initial API object is constructed.
+ *
+ * @param key This is the property name.
+ * @param value This is the value of the property.
+ *
+ * @return 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 (!commandLine.isOptionName(key)) {
+ return false;
+ }
+ cli_props.setProperty(key, value);
+ return true;
+ }
+
+ protected IDuccCallback getCallback() {
+ return consoleCb;
+ }
+
+ /*
+ * NOTE: We do NOT want to be intentionally throwing from the CLI. Pls pass e.getMessage() or
+ * e.toString() to this instead of throwing.
+ */
+ synchronized void message(String... e) {
+ if (e.length > 1) {
+ StringBuffer sb = new StringBuffer();
+ int i = 0;
+ for (i = 0; i < e.length - 1; i++) {
+ sb.append(e[i]);
+ sb.append(' ');
+ }
+ sb.append(e[i]);
+ consoleCb.status(sb.toString());
+ } else {
+ consoleCb.status(e[0]);
}
+ }
- protected synchronized void stopListeners()
- {
- if ( console_listener != null ) {
- console_listener.shutdown();
- console_listener = null;
- }
+ /**
+ * This returns the return code from the execution of the requested work. Return code is only
+ * available when the monitor wait completes ... if not waiting then assume success.
+ *
+ * @return The exit code of the job, process, etc.
+ */
+ public int getReturnCode() {
+ waitForCompletion();
+ return returnCode;
+ }
- if ( monitor_listener != null ) {
- monitor_listener.shutdown();
- monitor_listener = null;
- }
+ /**
+ * This returns the unique numeric id for the requested work. For submissions (job, reservation, etc)
+ * this is the newly assigned id.
+ * @return The unique numeric id of the job, reservation, etc.
+ */
+ synchronized public long getDuccId() {
+ return friendlyId;
+ }
+
+ synchronized void consoleExits() {
+ if (waiter != null)
+ waiter.countDown();
+ }
+
+ synchronized void monitorExits(int rc) {
+ this.returnCode = rc;
+ if (waiter != null)
+ waiter.countDown();
+ if (console_listener != null) {
+ console_listener.shutdown();
+ }
+ }
+
+ // TODO TODO TODO - do we have to support lots of these for multi-threaded stuff? Hope not ...
+ protected synchronized void startMonitors(boolean start_stdin, DuccContext context) throws Exception {
+ int wait_count = 0;
+
+ if (console_listener != null) {
+ wait_count++;
+ }
+
+ boolean monitor_attach = (cli_props.containsKey(UiOption.WaitForCompletion.pname()) || cli_props.containsKey(UiOption.CancelOnInterrupt.pname()));
+
+ if (monitor_attach) {
+ wait_count++;
+ }
+
+ // Probably over-cautious but create the waiter before starting the threads that use it
+ if (wait_count > 0) {
+ waiter = new CountDownLatch(wait_count);
+ if (console_listener != null) {
+ startConsoleListener(start_stdin);
+ }
+ if (monitor_attach) {
+ startMonitor(context);
+ }
+ }
+ }
+
+ protected synchronized void startMonitor(DuccContext context) {
+ monitor_listener = new MonitorListener(this, friendlyId, cli_props, context);
+ Thread mlt = new Thread(monitor_listener); //MonitorListenerThread
+ mlt.start();
+ }
+
+ /*
+ * Needs to be done before submitting the job because the job needs the ports. We'll
+ * just define the listener, but not start it until the job monitor starts, in case the
+ * submission fails.
+ */
+ protected void initConsoleListener() throws Exception {
+ String value;
+
+ console_attach = cli_props.containsKey(UiOption.AttachConsole.pname());
+ if (console_attach) {
+ console_listener = new ConsoleListener(this, consoleCb);
+ value = console_listener.getConsoleHostAddress();
+ if (myClassName.equals(DuccManagedReservationSubmit.class.getName())) {
+ value += "?splitstreams"; // Add a query string so APs have separate streams
+ }
+ } else if (suppress_console_log) {
+ value = "suppress";
+ } else {
+ return;
+ }
+ // Set the console "suppress" flag or the host:port for the console listener into the env
+ String key = UiOption.Environment.pname();
+ String env = cli_props.getProperty(key);
+ if (env == null) {
+ env = "DUCC_CONSOLE_LISTENER=" + value;
+ } else {
+ env += " DUCC_CONSOLE_LISTENER=" + value;
}
+ cli_props.setProperty(key, env);
+ }
- /**
- * This is used to find if the remote console is redirected to the local process, and if so, is it still
- * active.
- * @return True if the console is still attached to the remote process, false otherwise.
- */
- public boolean isConsoleAttached()
- {
- return ( (console_listener != null ) && ( !console_listener.isShutdown()));
+ /*
+ * Be sure to call this BEFORE submission, to insure the callback address is set in properties.
+ */
+ protected synchronized void startConsoleListener(boolean start_stdin) throws Exception {
+ if (console_attach) {
+ console_listener.startStdin(start_stdin);
+ Thread t = new Thread(console_listener);
+ t.start();
+ } else {
+ message("WARN: Attermpt to start console but no console listener is defined.");
+ }
+ }
+
+ protected synchronized void stopListeners() {
+ if (console_listener != null) {
+ console_listener.shutdown();
+ console_listener = null;
+ }
+
+ if (monitor_listener != null) {
+ monitor_listener.shutdown();
+ monitor_listener = null;
}
+ }
- /**
- * Wait for the listeners - maybe a console listener, maybe a job listener, maybe both.
- *
- * @return true if a monitor wait was done, false otherwise. A monitor wait
- * results in a return code from the process. In all other cases
- * the return code is spurious.
- */
- public boolean waitForCompletion()
- {
- try {
- if ( waiter != null ) {
- waiter.await();
- return true;
- }
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return false;
+ /**
+ * This is used to find if the remote console is redirected to the local process, and if so, is it still
+ * active.
+ * @return True if the console is still attached to the remote process, false otherwise.
+ */
+ public boolean isConsoleAttached() {
+ return ((console_listener != null) && (!console_listener.isShutdown()));
+ }
+
+ /**
+ * Wait for the listeners - maybe a console listener, maybe a job listener, maybe both.
+ *
+ * @return true if a monitor wait was done, false otherwise. A monitor wait
+ * results in a return code from the process. In all other cases
+ * the return code is spurious.
+ */
+ public boolean waitForCompletion() {
+ try {
+ if (waiter != null) {
+ waiter.await();
+ return true;
+ }
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
}
+ return false;
+ }
}