]> git.argeo.org Git - gpl/argeo-slc.git/blobdiff - runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/core/execution/tasks/SystemCall.java
Use execDir to choose config and data dir when not forked.
[gpl/argeo-slc.git] / runtime / org.argeo.slc.support.simple / src / main / java / org / argeo / slc / core / execution / tasks / SystemCall.java
index 38b0f78b4f5b759390a3d1141145c28e00a371a2..2bb835b24accc14999f675f74fbec86cbf05382e 100644 (file)
@@ -1,26 +1,26 @@
 package org.argeo.slc.core.execution.tasks;
 
-import java.io.BufferedReader;
 import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.apache.commons.io.IOUtils;
+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.ExecuteWatchdog;
+import org.apache.commons.exec.Executor;
+import org.apache.commons.exec.LogOutputStream;
+import org.apache.commons.exec.PumpStreamHandler;
+import org.apache.commons.exec.ShutdownHookProcessDestroyer;
+import org.apache.commons.lang.NotImplementedException;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.argeo.slc.SlcException;
-import org.argeo.slc.execution.Executable;
-
-public class SystemCall implements Executable {
-       // TODO: specify environment variables
 
+/** Execute and OS system call. */
+public class SystemCall implements Runnable {
        private final Log log = LogFactory.getLog(getClass());
 
        private String execDir;
@@ -29,15 +29,17 @@ public class SystemCall implements Executable {
        private List<String> command = null;
 
        private Boolean synchronous = true;
-       private Boolean captureStdIn = false;
 
        private String stdErrLogLevel = "ERROR";
        private String stdOutLogLevel = "INFO";
 
        private Map<String, List<String>> osCommands = new HashMap<String, List<String>>();
        private Map<String, String> osCmds = new HashMap<String, String>();
+       private Map<String, String> environmentVariables = new HashMap<String, String>();
+
+       private Long watchdogTimeout = 24 * 60 * 60 * 1000l;
 
-       public void execute() {
+       public void run() {
                try {
                        if (log.isTraceEnabled()) {
                                log.debug("os.name=" + System.getProperty("os.name"));
@@ -53,8 +55,6 @@ public class SystemCall implements Executable {
                                dir = new File(execDir).getCanonicalFile();
                        }
 
-                       Process process = null;
-
                        // Check if an OS specific command overrides
                        String osName = System.getProperty("os.name");
                        List<String> commandToUse = null;
@@ -68,6 +68,29 @@ public class SystemCall implements Executable {
                        else
                                cmdToUse = cmd;
 
+                       // Prepare executor
+                       if (dir == null)
+                               dir = new File(getUsedDir(dir));
+                       if (!dir.exists())
+                               dir.mkdirs();
+
+                       Executor executor = new DefaultExecutor();
+                       executor.setWatchdog(new ExecuteWatchdog(watchdogTimeout));
+                       PumpStreamHandler pumpStreamHandler = new PumpStreamHandler(
+                                       new LogOutputStream() {
+                                               protected void processLine(String line, int level) {
+                                                       log(stdOutLogLevel, line);
+                                               }
+                                       }, new LogOutputStream() {
+                                               protected void processLine(String line, int level) {
+                                                       log(stdErrLogLevel, line);
+                                               }
+                                       }, null);
+                       executor.setStreamHandler(pumpStreamHandler);
+                       executor.setProcessDestroyer(new ShutdownHookProcessDestroyer());
+                       executor.setWorkingDirectory(dir);
+                       final CommandLine commandLine;
+
                        // Which command definition to use
                        if (commandToUse == null && cmdToUse == null)
                                throw new SlcException("Please specify a command.");
@@ -78,44 +101,53 @@ public class SystemCall implements Executable {
                                if (log.isTraceEnabled())
                                        log.trace("Execute '" + cmdToUse + "' in "
                                                        + getUsedDir(dir));
-                               process = Runtime.getRuntime().exec(cmdToUse, null, dir);
+
+                               commandLine = CommandLine.parse(cmdToUse);
                        } else if (commandToUse != null) {
                                if (log.isTraceEnabled())
                                        log.trace("Execute '" + commandToUse + "' in "
                                                        + getUsedDir(dir));
-                               ProcessBuilder processBuilder = new ProcessBuilder(commandToUse);
-                               processBuilder.directory(dir);
-                               process = processBuilder.start();
+                               if (commandToUse.size() == 0)
+                                       throw new SlcException("Command line is empty.");
+
+                               commandLine = new CommandLine(commandToUse.get(0));
+                               for (int i = 1; i < commandToUse.size(); i++)
+                                       commandLine.addArgument(commandToUse.get(i));
                        } else {
                                // all cases covered previously
+                               throw new NotImplementedException();
                        }
 
-                       // Manage standard streams
-                       StreamReaderThread stdOutThread = new StreamReaderThread(process
-                                       .getInputStream()) {
-                               protected void callback(String line) {
-                                       stdOutCallback(line);
+                       // 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.");
                                }
-                       };
-                       stdOutThread.start();
-                       StreamReaderThread stdErrThread = new StreamReaderThread(process
-                                       .getInputStream()) {
-                               protected void callback(String line) {
-                                       stdErrCallback(line);
+
+                               public void onProcessFailed(ExecuteException e) {
+                                       throw new SlcException("Process " + commandLine
+                                                       + " failed.", e);
                                }
                        };
-                       stdErrThread.start();
-                       if (captureStdIn)
-                               new StdInThread(process.getOutputStream()).start();
-
-                       // Wait for the end of the process
-                       if (synchronous) {
-                               Integer exitCode = process.waitFor();
-                               if (exitCode != 0)
-                                       log.warn("Process return exit code " + exitCode);
-                       } else {
-                               // asynchronous: return
-                       }
+
+                       if (synchronous)
+                               try {
+                                       int exitValue = executor.execute(commandLine,
+                                                       environmentVariablesToUse);
+                                       executeResultHandler.onProcessComplete(exitValue);
+                               } catch (ExecuteException e1) {
+                                       executeResultHandler.onProcessFailed(e1);
+                               }
+                       else
+                               executor.execute(commandLine, environmentVariablesToUse,
+                                               executeResultHandler);
                } catch (Exception e) {
                        throw new SlcException("Could not execute command " + cmd, e);
                }
@@ -132,14 +164,6 @@ public class SystemCall implements Executable {
                else
                        return dir.getPath();
        }
-       
-       protected void stdOutCallback(String line) {
-               log(stdOutLogLevel, line);
-       }
-
-       protected void stdErrCallback(String line) {
-               log(stdErrLogLevel, line);
-       }
 
        protected void log(String logLevel, String line) {
                if ("ERROR".equals(logLevel))
@@ -176,10 +200,6 @@ public class SystemCall implements Executable {
                this.synchronous = synchronous;
        }
 
-       public void setCaptureStdIn(Boolean captureStdIn) {
-               this.captureStdIn = captureStdIn;
-       }
-
        public void setCommand(List<String> command) {
                this.command = command;
        }
@@ -192,69 +212,12 @@ public class SystemCall implements Executable {
                this.osCmds = osCmds;
        }
 
-       protected abstract class StreamReaderThread extends Thread {
-               private final InputStream stream;
-
-               public StreamReaderThread(InputStream stream) {
-                       this.stream = stream;
-               }
-
-               @Override
-               public void run() {
-                       BufferedReader in = null;
-                       try {
-                               in = new BufferedReader(new InputStreamReader(stream));
-                               String line = null;
-                               while ((line = in.readLine()) != null) {
-                                       stdOutCallback(line);
-                               }
-                       } catch (IOException e) {
-                               if (log.isTraceEnabled()) {
-                                       log.trace("Could not read stream", e);
-                                       // catch silently
-                                       // because the other methods
-                                       // to check whether the stream
-                                       // is closed would probably
-                                       // be to costly
-                               }
-                       } finally {
-                               if (synchronous)
-                                       IOUtils.closeQuietly(in);
-                       }
-               }
-
-               protected abstract void callback(String line);
+       public void setEnvironmentVariables(Map<String, String> environmentVariables) {
+               this.environmentVariables = environmentVariables;
        }
 
-       protected class StdInThread extends Thread {
-               private final OutputStream stream;
-
-               public StdInThread(OutputStream stream) {
-                       this.stream = stream;
-               }
-
-               @Override
-               public void run() {
-                       BufferedReader in = null;
-                       Writer out = null;
-                       try {
-                               out = new OutputStreamWriter(stream);
-                               in = new BufferedReader(new InputStreamReader(System.in));
-                               String line = null;
-                               while ((line = in.readLine()) != null) {
-                                       out.write(line);
-                                       out.write("\n");
-                                       out.flush();
-                               }
-                       } catch (IOException e) {
-                               throw new SlcException("Could not write to stdin stream", e);
-                       } finally {
-                               if (synchronous) {
-                                       IOUtils.closeQuietly(in);
-                                       IOUtils.closeQuietly(out);
-                               }
-                       }
-               }
-
+       public void setWatchdogTimeout(Long watchdogTimeout) {
+               this.watchdogTimeout = watchdogTimeout;
        }
+
 }