SystemCall, JvmProcess, DetachedLauncher enhancements
authorMathieu Baudier <mbaudier@argeo.org>
Tue, 28 Jul 2009 17:05:59 +0000 (17:05 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Tue, 28 Jul 2009 17:05:59 +0000 (17:05 +0000)
git-svn-id: https://svn.argeo.org/slc/trunk@2824 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/tasks/JvmProcess.java
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/tasks/SystemCall.java
runtime/org.argeo.slc.lib.detached/src/main/java/org/argeo/slc/lib/detached/DetachedLauncher.java
runtime/org.argeo.slc.osgiboot/src/main/java/org/argeo/slc/osgiboot/Launcher.java
runtime/org.argeo.slc.osgiboot/src/main/java/org/argeo/slc/osgiboot/OsgiBoot.java

index edc7188b1a30d150e93c44ca228f201dcc50ccad..1dc91bf5d59558af6dde216a5878744cd5ffbfb2 100644 (file)
@@ -9,16 +9,12 @@ import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
-import org.apache.commons.exec.CommandLine;
 import org.apache.commons.io.IOUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
 import org.argeo.slc.SlcException;
+import org.springframework.beans.factory.InitializingBean;
 import org.springframework.core.io.Resource;
 
-public class JvmProcess extends SystemCall {
-       private final static Log log = LogFactory.getLog(JvmProcess.class);
-
+public class JvmProcess extends SystemCall implements InitializingBean {
        private Properties systemProperties = new Properties();
        private List<Resource> classpath = new ArrayList<Resource>();
        private List<Resource> pBootClasspath = new ArrayList<Resource>();
@@ -27,13 +23,16 @@ public class JvmProcess extends SystemCall {
        private List<String> jvmArgs = new ArrayList<String>();
        private List<String> args = new ArrayList<String>();
 
-       @Override
-       protected CommandLine createCommandLine() {
-               final CommandLine cl;
+       private String systemPropertiesFileProperty = null;
+       private String systemPropertiesFileDir = null;
+       private String systemPropertiesFileName = null;
+
+       public void afterPropertiesSet() throws Exception {
+               List<Object> command = new ArrayList<Object>();
                if (jvm != null)
-                       cl = new CommandLine(asFile(jvm));
+                       command.add(asFile(jvm).getAbsolutePath());
                else
-                       cl = new CommandLine("java");
+                       command.add("java");
 
                if (pBootClasspath.size() > 0) {
                        StringBuffer buf = new StringBuffer("-Xbootclasspath/p:");
@@ -46,37 +45,65 @@ public class JvmProcess extends SystemCall {
 
                                buf.append(asFile(res));
                        }
-                       cl.addArgument(buf.toString());
+                       command.add(buf.toString());
                }
 
                for (String jvmArg : jvmArgs) {
-                       cl.addArgument(jvmArg);
+                       command.add(jvmArg);
                }
 
-               cl.addArgument("-cp");
+               command.add("-cp");
                StringBuffer buf = new StringBuffer("");
                for (Resource res : classpath) {
                        if (buf.length() != 0)
                                buf.append(File.pathSeparatorChar);
                        buf.append(asFile(res));
                }
-               cl.addArgument(buf.toString());
+               command.add(buf.toString());
 
-               for (Map.Entry<Object, Object> entry : systemProperties.entrySet()) {
-                       cl.addArgument("-D" + entry.getKey() + "=" + entry.getValue());
+               if (systemPropertiesFileProperty == null) {
+                       // pass system properties as argument
+                       for (Map.Entry<Object, Object> entry : systemProperties.entrySet()) {
+                               command.add("-D" + entry.getKey() + "=" + entry.getValue());
+                       }
+               } else {
+                       // write system properties in a file to work around OS limitations
+                       // with command line (e.g. Win XP)
+                       String dir = systemPropertiesFileDir;
+                       if (dir == null)
+                               dir = getExecDirToUse();
+                       String fileName = systemPropertiesFileName;
+                       if (fileName == null)
+                               fileName = systemPropertiesFileProperty + ".properties";
+
+                       // Write file
+                       FileOutputStream fos = null;
+                       File file = new File(dir + File.separator + fileName);
+                       try {
+
+                               if (!file.getParentFile().exists())
+                                       file.getParentFile().mkdirs();
+                               fos = new FileOutputStream(file);
+                               systemProperties.store(fos, "Automatically generated by "
+                                               + getClass());
+                               command.add("-D" + systemPropertiesFileProperty + "="
+                                               + file.getCanonicalPath());
+                       } catch (IOException e) {
+                               throw new SlcException("Cannot write to system properties to "
+                                               + file, e);
+                       } finally {
+                               IOUtils.closeQuietly(fos);
+                       }
                }
 
                // Program
-               cl.addArgument(mainClass);
+               command.add(mainClass);
 
                for (String arg : args) {
-                       cl.addArgument(arg);
+                       command.add(arg);
                }
 
-               if (log.isTraceEnabled())
-                       log.debug("Command line:\n" + cl.toString() + "\n");
-
-               return cl;
+               setCommand(command);
        }
 
        protected File asFile(Resource res) {
@@ -161,4 +188,17 @@ public class JvmProcess extends SystemCall {
                this.args = args;
        }
 
+       public void setSystemPropertiesFileProperty(
+                       String systemPropertiesFilePropertyName) {
+               this.systemPropertiesFileProperty = systemPropertiesFilePropertyName;
+       }
+
+       public void setSystemPropertiesFileDir(String systemPropertiesFileDir) {
+               this.systemPropertiesFileDir = systemPropertiesFileDir;
+       }
+
+       public void setSystemPropertiesFileName(String systemPropertiesFileName) {
+               this.systemPropertiesFileName = systemPropertiesFileName;
+       }
+
 }
index f3314ac7f46616b9b84334e1a60e4dec6410d335..93a467a1d3678970ea55698d76f626fee83cf865 100644 (file)
@@ -3,6 +3,8 @@ package org.argeo.slc.core.execution.tasks;
 import java.io.File;
 import java.io.FileWriter;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.io.Writer;
 import java.util.HashMap;
 import java.util.List;
@@ -12,6 +14,7 @@ import org.apache.commons.exec.CommandLine;
 import org.apache.commons.exec.DefaultExecutor;
 import org.apache.commons.exec.ExecuteException;
 import org.apache.commons.exec.ExecuteResultHandler;
+import org.apache.commons.exec.ExecuteStreamHandler;
 import org.apache.commons.exec.ExecuteWatchdog;
 import org.apache.commons.exec.Executor;
 import org.apache.commons.exec.LogOutputStream;
@@ -21,6 +24,7 @@ import org.apache.commons.io.IOUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.argeo.slc.SlcException;
+import org.argeo.slc.UnsupportedException;
 import org.argeo.slc.core.structure.tree.TreeSPath;
 import org.argeo.slc.core.structure.tree.TreeSRelatedHelper;
 import org.argeo.slc.core.test.SimpleResultPart;
@@ -51,10 +55,16 @@ public class SystemCall extends TreeSRelatedHelper implements Runnable,
        private Map<String, String> osCmds = new HashMap<String, String>();
        private Map<String, String> environmentVariables = new HashMap<String, String>();
 
+       private Boolean logCommand = false;
+       private Boolean redirectStreams = true;
+       private String osConsole = null;
+
        private Long watchdogTimeout = 24 * 60 * 60 * 1000l;
 
        private TestResult testResult;
 
+       // Internal use
+
        public SystemCall() {
 
        }
@@ -65,7 +75,6 @@ public class SystemCall extends TreeSRelatedHelper implements Runnable,
        }
 
        public void run() {
-               // Log writers
                final Writer stdOutWriter;
                final Writer stdErrWriter;
                if (stdOutFile != null) {
@@ -89,16 +98,7 @@ public class SystemCall extends TreeSRelatedHelper implements Runnable,
                        }
 
                        // Execution directory
-                       File dir = null;
-                       if (execDir != null) {
-                               // Replace '/' by local file separator, for portability
-                               execDir.replace('/', File.separatorChar);
-                               dir = new File(execDir).getCanonicalFile();
-                       }
-
-                       // Prepare executor
-                       if (dir == null)
-                               dir = new File(getUsedDir(dir));
+                       File dir = new File(getExecDirToUse());
                        if (!dir.exists())
                                dir.mkdirs();
 
@@ -106,59 +106,29 @@ public class SystemCall extends TreeSRelatedHelper implements Runnable,
                        Executor executor = new DefaultExecutor();
                        executor.setWatchdog(new ExecuteWatchdog(watchdogTimeout));
 
-                       // Redirect standard streams
-                       PumpStreamHandler pumpStreamHandler = new PumpStreamHandler(
-                                       new LogOutputStream() {
-                                               protected void processLine(String line, int level) {
-                                                       log(stdOutLogLevel, line);
-                                                       if (stdOutWriter != null)
-                                                               appendLineToFile(stdOutWriter, line);
-                                               }
-                                       }, new LogOutputStream() {
-                                               protected void processLine(String line, int level) {
-                                                       log(stdErrLogLevel, line);
-                                                       if (stdErrWriter != null)
-                                                               appendLineToFile(stdErrWriter, line);
-                                               }
-                                       }, null);
-                       executor.setStreamHandler(pumpStreamHandler);
+                       if (redirectStreams) {
+                               // Redirect standard streams
+                               executor.setStreamHandler(createExecuteStreamHandler(
+                                               stdOutWriter, stdErrWriter));
+                       } else {
+                               // Dummy stream handler (otherwise pump is used)
+                               executor.setStreamHandler(new DummyexecuteStreamHandler());
+                       }
+
                        executor.setProcessDestroyer(new ShutdownHookProcessDestroyer());
                        executor.setWorkingDirectory(dir);
 
                        // Command line to use
                        final CommandLine commandLine = createCommandLine();
+                       if (logCommand)
+                               log.info("Execute command:\n" + commandLine + "\n");
 
                        // Env variables
                        Map<String, String> environmentVariablesToUse = environmentVariables
                                        .size() > 0 ? environmentVariables : null;
 
                        // Execute
-                       ExecuteResultHandler executeResultHandler = new ExecuteResultHandler() {
-
-                               public void onProcessComplete(int exitValue) {
-                                       if (log.isDebugEnabled())
-                                               log.debug("Process " + commandLine
-                                                               + " properly completed.");
-                                       if (testResult != null) {
-                                               forwardPath(testResult, null);
-                                               testResult.addResultPart(new SimpleResultPart(
-                                                               TestStatus.PASSED, "Process " + commandLine
-                                                                               + " properly completed."));
-                                       }
-                               }
-
-                               public void onProcessFailed(ExecuteException e) {
-                                       if (testResult != null) {
-                                               forwardPath(testResult, null);
-                                               testResult.addResultPart(new SimpleResultPart(
-                                                               TestStatus.ERROR, "Process " + commandLine
-                                                                               + " failed.", e));
-                                       } else {
-                                               throw new SlcException("Process " + commandLine
-                                                               + " failed.", e);
-                                       }
-                               }
-                       };
+                       ExecuteResultHandler executeResultHandler = createExecuteResultHandler(commandLine);
 
                        if (synchronous)
                                try {
@@ -180,7 +150,7 @@ public class SystemCall extends TreeSRelatedHelper implements Runnable,
 
        }
 
-       /** Can be overridden by specific command wrapper*/
+       /** Can be overridden by specific command wrapper */
        protected CommandLine createCommandLine() {
                // Check if an OS specific command overrides
                String osName = System.getProperty("os.name");
@@ -204,30 +174,101 @@ public class SystemCall extends TreeSRelatedHelper implements Runnable,
                        throw new SlcException(
                                        "Specify the command either as a line or as a list.");
                else if (cmdToUse != null) {
+                       if (osConsole != null)
+                               cmdToUse = osConsole + " " + cmdToUse;
                        commandLine = CommandLine.parse(cmdToUse);
                } else if (commandToUse != null) {
                        if (commandToUse.size() == 0)
                                throw new SlcException("Command line is empty.");
 
-                       commandLine = new CommandLine(commandToUse.get(0).toString());
-                       for (int i = 1; i < commandToUse.size(); i++)
+                       if (osConsole != null) {
+                               commandLine = CommandLine.parse(osConsole);
+                       } else {
+                               commandLine = new CommandLine(commandToUse.get(0).toString());
+                       }
+
+                       for (int i = (osConsole != null ? 0 : 1); i < commandToUse.size(); i++) {
+                               log.debug(commandToUse.get(i));
                                commandLine.addArgument(commandToUse.get(i).toString());
+                       }
                } else {
                        // all cases covered previously
-                       throw new UnsupportedOperationException();
+                       throw new UnsupportedException();
                }
                return commandLine;
        }
 
+       protected ExecuteStreamHandler createExecuteStreamHandler(
+                       final Writer stdOutWriter, final Writer stdErrWriter) {
+               // Log writers
+
+               PumpStreamHandler pumpStreamHandler = new PumpStreamHandler(
+                               new LogOutputStream() {
+                                       protected void processLine(String line, int level) {
+                                               log(stdOutLogLevel, line);
+                                               if (stdOutWriter != null)
+                                                       appendLineToFile(stdOutWriter, line);
+                                       }
+                               }, new LogOutputStream() {
+                                       protected void processLine(String line, int level) {
+                                               log(stdErrLogLevel, line);
+                                               if (stdErrWriter != null)
+                                                       appendLineToFile(stdErrWriter, line);
+                                       }
+                               }, null);
+               return pumpStreamHandler;
+       }
+
+       protected ExecuteResultHandler createExecuteResultHandler(
+                       final CommandLine commandLine) {
+               return new ExecuteResultHandler() {
+
+                       public void onProcessComplete(int exitValue) {
+                               if (log.isDebugEnabled())
+                                       log
+                                                       .debug("Process " + commandLine
+                                                                       + " properly completed.");
+                               if (testResult != null) {
+                                       forwardPath(testResult, null);
+                                       testResult.addResultPart(new SimpleResultPart(
+                                                       TestStatus.PASSED, "Process " + commandLine
+                                                                       + " properly completed."));
+                               }
+                       }
+
+                       public void onProcessFailed(ExecuteException e) {
+                               if (testResult != null) {
+                                       forwardPath(testResult, null);
+                                       testResult.addResultPart(new SimpleResultPart(
+                                                       TestStatus.ERROR, "Process " + commandLine
+                                                                       + " failed.", e));
+                               } else {
+                                       throw new SlcException("Process " + commandLine
+                                                       + " failed.", e);
+                               }
+                       }
+               };
+       }
+
        /**
-        * Shortcut method returning the current exec dir if the specified one is
-        * null.
+        * Shortcut method getting the execDir to use
         */
-       private String getUsedDir(File dir) {
-               if (dir == null)
-                       return System.getProperty("user.dir");
-               else
-                       return dir.getPath();
+       protected String getExecDirToUse() {
+               try {
+                       File dir = null;
+                       if (execDir != null) {
+                               // Replace '/' by local file separator, for portability
+                               execDir.replace('/', File.separatorChar);
+                               dir = new File(execDir).getCanonicalFile();
+                       }
+
+                       if (dir == null)
+                               return System.getProperty("user.dir");
+                       else
+                               return dir.getPath();
+               } catch (Exception e) {
+                       throw new SlcException("Cannot find exec dir", e);
+               }
        }
 
        protected void log(String logLevel, String line) {
@@ -317,4 +358,35 @@ public class SystemCall extends TreeSRelatedHelper implements Runnable,
                this.testResult = testResult;
        }
 
+       public void setLogCommand(Boolean logCommand) {
+               this.logCommand = logCommand;
+       }
+
+       public void setRedirectStreams(Boolean redirectStreams) {
+               this.redirectStreams = redirectStreams;
+       }
+
+       public void setOsConsole(String osConsole) {
+               this.osConsole = osConsole;
+       }
+
+       private class DummyexecuteStreamHandler implements ExecuteStreamHandler {
+
+               public void setProcessErrorStream(InputStream is) throws IOException {
+               }
+
+               public void setProcessInputStream(OutputStream os) throws IOException {
+               }
+
+               public void setProcessOutputStream(InputStream is) throws IOException {
+               }
+
+               public void start() throws IOException {
+               }
+
+               public void stop() {
+               }
+
+       }
+
 }
index bdfa4f0b0af6944ecda810ce5b3aeebb0d4528e1..4ab0f6067d1d95cd4e511a66aed6df442328bee9 100644 (file)
@@ -116,6 +116,8 @@ public class DetachedLauncher extends JvmProcess implements BundleContextAware,
                                osgiBundles.toString());
                getSystemProperties().setProperty("slc.osgi.locations",
                                osgiLocations.toString());
+               
+               super.afterPropertiesSet();
        }
 
        protected String removeInitialReference(String location) {
index 802577dcc07dba77b737f75e86a5efe88bfe57da..75925165553efaba4c1b4e7ef4080274d88f527e 100644 (file)
@@ -1,5 +1,7 @@
 package org.argeo.slc.osgiboot;
 
+import java.io.FileInputStream;
+import java.io.IOException;
 import java.lang.reflect.Method;
 import java.util.List;
 import java.util.Properties;
@@ -11,8 +13,32 @@ import org.osgi.framework.BundleContext;
 public class Launcher {
 
        public static void main(String[] args) {
+               // Try to load system properties
+               String systemPropertiesFilePath = System
+                               .getProperty(OsgiBoot.PROP_SLC_OSGIBOOT_SYSTEM_PROPERTIES_FILE);
+               if (systemPropertiesFilePath != null) {
+                       FileInputStream in;
+                       try {
+                               in = new FileInputStream(systemPropertiesFilePath);
+                               System.getProperties().load(in);
+                       } catch (IOException e1) {
+                               throw new RuntimeException(
+                                               "Cannot load system properties from "
+                                                               + systemPropertiesFilePath, e1);
+                       }
+                       if (in != null) {
+                               try {
+                                       in.close();
+                               } catch (Exception e) {
+                                       // silent
+                               }
+                       }
+               }
+
+               // Start main class
                startMainClass();
 
+               // Start Equinox
                BundleContext bundleContext = null;
                try {
                        bundleContext = EclipseStarter.startup(args, null);
@@ -20,6 +46,7 @@ public class Launcher {
                        throw new RuntimeException("Cannot start Equinox.", e);
                }
 
+               // OSGi bootstrap
                OsgiBoot osgiBoot = new OsgiBoot(bundleContext);
                osgiBoot.bootstrap();
        }
index 8288370634aa3bd3359780085490a1a0832e54a3..cc4cb40e775ec34f19fae185c47093af69299d60 100644 (file)
@@ -31,6 +31,7 @@ public class OsgiBoot {
        public final static String PROP_SLC_OSGIBOOT_DEBUG = "slc.osgiboot.debug";
        public final static String PROP_SLC_OSGIBOOT_DEFAULT_TIMEOUT = "slc.osgiboot.defaultTimeout";
        public final static String PROP_SLC_OSGIBOOT_MODULES_URL_SEPARATOR = "slc.osgiboot.modulesUrlSeparator";
+       public final static String PROP_SLC_OSGIBOOT_SYSTEM_PROPERTIES_FILE = "slc.osgiboot.systemPropertiesFile";
 
        public final static String DEFAULT_BASE_URL = "reference:file:";
        public final static String EXCLUDES_SVN_PATTERN = "**/.svn/**";