Add a file with the runnig command and environment in each wrok dir
authorSasha Sherstnev <a.sherstnev@dundee.ac.uk>
Thu, 8 Aug 2013 13:23:35 +0000 (14:23 +0100)
committerSasha Sherstnev <a.sherstnev@dundee.ac.uk>
Fri, 9 Aug 2013 09:18:01 +0000 (10:18 +0100)
engine/compbio/engine/local/ExecutableWrapper.java

index 9e652f9..5809be4 100644 (file)
@@ -1,6 +1,8 @@
 /* Copyright (c) 2009 Peter Troshin\r
- *  \r
- *  JAva Bioinformatics Analysis Web Services (JABAWS) @version: 1.0     \r
+ * Copyright (c) 2013 Alexander Sherstnev\r
+ * \r
+ *  Java Bioinformatics Analysis Web Services (JABAWS)\r
+ * @version: 2.5\r
  * \r
  *  This library is free software; you can redistribute it and/or modify it under the terms of the\r
  *  Apache License version 2 as published by the Apache Software Foundation\r
@@ -22,6 +24,8 @@ import java.io.File;
 import java.io.IOException;\r
 import java.io.PrintStream;\r
 import java.util.List;\r
+import java.util.Map;\r
+import java.util.Map.Entry;\r
 import java.util.concurrent.Callable;\r
 import java.util.concurrent.ExecutionException;\r
 import java.util.concurrent.ExecutorService;\r
@@ -48,62 +52,58 @@ import compbio.util.annotation.Immutable;
 public final class ExecutableWrapper implements\r
        Callable<ConfiguredExecutable<?>> {\r
 \r
+    public static final String PROC_IN_FILE = "procInput.txt";\r
     public static final String PROC_OUT_FILE = "procOutput.txt";\r
     public static final String PROC_ERR_FILE = "procError.txt";\r
 \r
     private static ExecutorService es;\r
-\r
-    private static final Logger log = Logger.getLogger(ExecutableWrapper.class);\r
-\r
     private final ConfiguredExecutable<?> confExec;\r
-\r
     private final ProcessBuilder pbuilder;\r
 \r
-    public ExecutableWrapper(ConfiguredExecutable<?> executable,\r
-           String workDirectory) throws JobSubmissionException {\r
-       this.confExec = executable;\r
-       String cmd = null;\r
-       try {\r
-           cmd = executable.getCommand(ExecProvider.Local);\r
-           PathValidator.validateExecutable(cmd);\r
-       } catch (IllegalArgumentException e) {\r
-           log.error(e.getMessage(), e.getCause());\r
-           throw new JobSubmissionException(e);\r
-       }\r
-       List<String> params = executable.getParameters().getCommands();\r
-       params.add(0, cmd);\r
-\r
-       pbuilder = new ProcessBuilder(params);\r
-       if (executable.getEnvironment() != null) {\r
-           log.debug("Setting command environment variables: " + pbuilder.environment());\r
-           Util.mergeEnvVariables(pbuilder.environment(), executable.getEnvironment());\r
-           log.debug("Process environment:" + pbuilder.environment());\r
-       }\r
-       log.debug("Setting command: " + pbuilder.command());\r
-       PathValidator.validateDirectory(workDirectory);\r
-       pbuilder.directory(new File(workDirectory));\r
-       log.debug("Current working directory is " + SysPrefs.getCurrentDirectory());\r
-       log.debug("Setting working directory: " + workDirectory);\r
-       // Initialize private executor to dump processes output if any to the\r
-       // file system\r
-       synchronized (log) {\r
-           if (es == null) {\r
-               // Two threads are necessary for the process to write in two\r
-               // streams error and output\r
-               // simultaneously and hold the stream until exit. If only one\r
-               // thread is used, the second stream may never\r
-               // get access to the thread efficiently deadlocking the\r
-               // proccess!\r
-               this.es = Executors.newCachedThreadPool();\r
-               log.debug("Initializing executor for local processes output dump");\r
-               // Make sure that the executors are going to be properly closed\r
-               Runtime.getRuntime().addShutdownHook(new Thread() {\r
-                   @Override\r
-                   public void run() {\r
-                       shutdownService();\r
-                   }\r
-               });\r
-           }\r
+    private static final Logger log = Logger.getLogger(ExecutableWrapper.class);\r
+\r
+    public ExecutableWrapper(ConfiguredExecutable<?> executable, String workDirectory) throws JobSubmissionException {\r
+       this.confExec = executable;\r
+       String cmd = null;\r
+       try {\r
+               cmd = executable.getCommand(ExecProvider.Local);\r
+               PathValidator.validateExecutable(cmd);\r
+       } catch (IllegalArgumentException e) {\r
+               log.error(e.getMessage(), e.getCause());\r
+               throw new JobSubmissionException(e);\r
+       }\r
+       List<String> params = executable.getParameters().getCommands();\r
+       params.add(0, cmd);\r
+\r
+       pbuilder = new ProcessBuilder(params);\r
+       if (executable.getEnvironment() != null) {\r
+               log.debug("Setting command environment variables: " + pbuilder.environment());\r
+               Util.mergeEnvVariables(pbuilder.environment(), executable.getEnvironment());\r
+               log.debug("Process environment:" + pbuilder.environment());\r
+       }\r
+       log.debug("Setting command: " + pbuilder.command());\r
+       PathValidator.validateDirectory(workDirectory);\r
+       pbuilder.directory(new File(workDirectory));\r
+       log.debug("Current working directory is " + SysPrefs.getCurrentDirectory());\r
+       log.debug("Setting working directory: " + workDirectory);\r
+       // Initialize private executor to dump processes output if any to the file system\r
+       synchronized (log) {\r
+               if (es == null) {\r
+                       /* \r
+                        * Two threads are necessary for the process to write in two streams error and output\r
+                        * simultaneously and hold the stream until exit. If only one thread is used, the\r
+                        * second stream may never get access to the thread efficiently deadlocking the proccess!\r
+                        */\r
+                       this.es = Executors.newCachedThreadPool();\r
+                               log.debug("Initializing executor for local processes output dump");\r
+                               // Make sure that the executors are going to be properly closed\r
+                               Runtime.getRuntime().addShutdownHook(new Thread() {\r
+                               @Override\r
+                               public void run() {\r
+                                       shutdownService();\r
+                               }\r
+                               });\r
+               }\r
        }\r
     }\r
 \r
@@ -114,8 +114,8 @@ public final class ExecutableWrapper implements
      * otherwise as the executor service is taken care of internally.\r
      */\r
     public static final void shutdownService() {\r
-       if (es != null) {\r
-               es.shutdownNow();\r
+       if (es != null) {\r
+               es.shutdownNow();\r
        }\r
     }\r
 \r
@@ -126,6 +126,7 @@ public final class ExecutableWrapper implements
      * capture immediately this could lead to the call method to stale, as\r
      * execution could not proceed without output being captured. Every call to\r
      * call() method will use 2 threads\r
+     * @throws JobSubmissionException \r
      */\r
     @Override\r
     public ConfiguredExecutable<?> call() throws IOException {\r
@@ -134,91 +135,90 @@ public final class ExecutableWrapper implements
        Future<?> outputf = null;\r
        PrintStream errorStream = null;\r
        PrintStream outStream = null;\r
-       try {\r
-           log.info("Calculation started at " + System.nanoTime());\r
-           Util.writeStatFile(confExec.getWorkDirectory(), JobStatus.STARTED\r
-                   .toString());\r
-           // pb.redirectErrorStream(false);\r
-           proc = pbuilder.start();\r
-\r
-           /*\r
-            * any error message?\r
-            */\r
-           errorStream = new PrintStream(new File(pbuilder.directory()\r
-                   + File.separator + getError()));\r
-           StreamGobbler errorGobbler = new StreamGobbler(proc\r
-                   .getErrorStream(), errorStream, OutputType.ERROR);\r
-\r
-           // any output?\r
-           outStream = new PrintStream(new File(pbuilder.directory()\r
-                   + File.separator + getOutput()));\r
-           StreamGobbler outputGobbler = new StreamGobbler(proc\r
-                   .getInputStream(), outStream, OutputType.OUTPUT);\r
-\r
-           // kick them off\r
-           errorf = es.submit(errorGobbler);\r
-           outputf = es.submit(outputGobbler);\r
-\r
-           // any error???\r
-           int exitVal = proc.waitFor();\r
-           log.info("Calculation completed at " + System.nanoTime());\r
-           Util.writeStatFile(confExec.getWorkDirectory(), JobStatus.FINISHED\r
-                   .toString());\r
-           // Let streams to write for a little more\r
-           errorf.get(2, TimeUnit.SECONDS);\r
-           outputf.get(2, TimeUnit.SECONDS);\r
-           // Close streams\r
-           errorStream.close();\r
-           outStream.close();\r
-           log.debug("Local process exit value: " + exitVal);\r
+       PrintStream comStream = null;\r
+\r
+    try {\r
+               log.info("Calculation started at " + System.nanoTime());\r
+               Util.writeStatFile(confExec.getWorkDirectory(), JobStatus.STARTED.toString());\r
+               proc = pbuilder.start();\r
+\r
+               // store input command and program environment\r
+               comStream = new PrintStream(new File(pbuilder.directory() + File.separator + PROC_IN_FILE));\r
+               comStream.append("# program command\n");\r
+               for (String par : pbuilder.command()) {\r
+                       comStream.append(par + " ");\r
+               }\r
+               comStream.append("\n\n# program environment\n");\r
+               for (Entry<String, String> var : pbuilder.environment().entrySet()) {\r
+                       comStream.append(var.getKey() + " =\t" + var.getValue() + "\n");\r
+               }\r
+               comStream.close();\r
+\r
+               // any error message?\r
+               errorStream = new PrintStream(new File(pbuilder.directory() + File.separator + getError()));\r
+               StreamGobbler errorGobbler = new StreamGobbler(proc.getErrorStream(), errorStream, OutputType.ERROR);\r
+\r
+               // any output?\r
+               outStream = new PrintStream(new File(pbuilder.directory() + File.separator + getOutput()));\r
+               StreamGobbler outputGobbler = new StreamGobbler(proc.getInputStream(), outStream, OutputType.OUTPUT);\r
+\r
+               // kick it off\r
+               errorf = es.submit(errorGobbler);\r
+               outputf = es.submit(outputGobbler);\r
+\r
+               // any error???\r
+               int exitVal = proc.waitFor();\r
+               log.info("Calculation completed at " + System.nanoTime());\r
+               Util.writeStatFile(confExec.getWorkDirectory(), JobStatus.FINISHED.toString());\r
+               // Let streams to write for a little more\r
+               errorf.get(2, TimeUnit.SECONDS);\r
+               outputf.get(2, TimeUnit.SECONDS);\r
+\r
+               // Close streams\r
+               errorStream.close();\r
+               outStream.close();\r
+               log.debug("Local process exit value: " + exitVal);\r
        } catch (ExecutionException e) {\r
-           // Log and ignore this is not important\r
-           log.trace("Native Process output threw exception: "\r
-                   + e.getMessage());\r
+               // Log and ignore this is not important\r
+               log.trace("Native Process output threw exception: " + e.getMessage());\r
        } catch (TimeoutException e) {\r
-           // Log and ignore this is not important\r
-           log\r
-                   .trace("Native Process output took longer then 2s to write, aborting: "\r
-                           + e.getMessage());\r
+               // Log and ignore this is not important\r
+               log.trace("Native Process output took longer then 2s to write, aborting: " + e.getMessage());\r
        } catch (InterruptedException e) {\r
-           log.error("Native Process was interrupted aborting: "\r
-                   + e.getMessage());\r
-           proc.destroy();\r
-           errorf.cancel(true);\r
-           outputf.cancel(true);\r
-           // restore interruption status\r
-           Thread.currentThread().interrupt();\r
-       } finally {\r
-           if (proc != null) {\r
-               // just to make sure that we do not left anything running\r
+               log.error("Native Process was interrupted aborting: " + e.getMessage());\r
                proc.destroy();\r
-           }\r
-           if (errorf != null) {\r
                errorf.cancel(true);\r
-           }\r
-           if (outputf != null) {\r
                outputf.cancel(true);\r
-           }\r
-           FileUtil.closeSilently(log, errorStream);\r
-           FileUtil.closeSilently(log, outStream);\r
+               // restore interruption status\r
+               Thread.currentThread().interrupt();\r
+       } finally {\r
+               // just to make sure that we do not left anything running\r
+               if (proc != null) {\r
+                       proc.destroy();\r
+               }\r
+               if (errorf != null) {\r
+                       errorf.cancel(true);\r
+               }\r
+               if (outputf != null) {\r
+                       outputf.cancel(true);\r
+               }\r
+               FileUtil.closeSilently(log, errorStream);\r
+               FileUtil.closeSilently(log, outStream);\r
        }\r
        return confExec;\r
     }\r
 \r
     private String getOutput() {\r
-       if (confExec.getOutput() != null\r
-               && confExec.getExecutable() instanceof PipedExecutable<?>) {\r
-           return confExec.getOutput();\r
+       if (confExec.getOutput() != null && confExec.getExecutable() instanceof PipedExecutable<?>) {\r
+               return confExec.getOutput();\r
        }\r
        return PROC_OUT_FILE;\r
     }\r
 \r
     private String getError() {\r
-       if (confExec.getError() != null\r
-               && confExec.getExecutable() instanceof PipedExecutable<?>) {\r
-           return confExec.getError();\r
+       if (confExec.getError() != null && confExec.getExecutable() instanceof PipedExecutable<?>) {\r
+               return confExec.getError();\r
        }\r
        return PROC_ERR_FILE;\r
     }\r
-\r
 }\r