/* 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
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
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
* 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
* 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
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