/** * Run a shell command. * * @param args shell arguments to call * @return the result of running the command * @throws ProcessRunException if there's an error running the process */ public RunResult run(List<String> args) throws ProcessRunException { for (int i = 0; i < retries; i++) { LOG.debug("Running: " + args); ProcessRunner runner = new ProcessRunner(args); RunResult result = runner.run(); if (result.getReturnCode() == 0) { return result; } LOG.error("Error running command! Got return code: " + result.getReturnCode()); if (i + 1 == retries) { return result; } try { LOG.debug("Sleeping for " + RETRY_SLEEP_TIME / 1000 + "s"); Thread.sleep(RETRY_SLEEP_TIME); } catch (InterruptedException e) { throw new RuntimeException("Shouldn't happen!"); } } throw new RuntimeException("Shouldn't happen"); }
@Override public void shutDown() { synchronized (this.extensionToRunnerMap) { for (ProcessRunner runner : this.extensionToRunnerMap.values()) { for (Process p : runner.getProcesses()) p.destroy(); } } }
@Override public void directoryChanged(DirectoryEvent e) { // Only interested in file create event if (e.getEventType() != DirectoryEvent.ENTRY_CREATE) return; String[] parts = e.getFile().toString().split("\\."); if (parts.length == 0) return; ProcessRunner runner = this.extensionToRunnerMap.get(parts[parts.length - 1]); if (runner == null) return; try { runner.execute(e.getFile()); } catch (IOException ex) { ex.printStackTrace(); } }
/** * Blocking method that saves (if required) a finished workflow runs output. * * <p>Blocks until the workflow run has finished. Works even if the workflow result was not 0. The * first time this method is called it saves the output to file. * * @return Output of this class including parameters passed to the bat.script and a capture of * anything that sends to output or error streams. Does not include the results of the * workflow run use getOutputFile() for these. * @throws TavernaException Thrown if there is an InterruptedException, ProcessException or error * saving the output. * @throws ProcessException If the process was not started. */ public String getOutput() throws TavernaException, ProcessException { if (outputFile == null) { return saveOutput(); } try { return runner.getOutput(); } catch (InterruptedException ex) { throw new TavernaException("Workflow was interrupted.", ex); } }
/** * Blocks until the workflow run has finished and then reports if it was successful. * * <p>A workflow run is considered successful if it returns with a 0 result. * * @return True is and only if the workflow run ended with a 0. * @throws TavernaException Wrapper around any InterruptedException, or if the process was never * started. * @throws ProcessException If the process was not started. */ public boolean wasSuccessful() throws TavernaException, ProcessException { try { boolean result = runner.waitFor() == 0; if (outputFile == null) { saveOutput(); } return result; } catch (InterruptedException ex) { throw new TavernaException("Error checking if run was successfull", ex); } }
private String saveOutput() throws TavernaException, ProcessException { String output = null; FileWriter writer = null; try { output = runner.getOutput(); outputFile = new File(runDirectory, "Output.txt"); writer = new FileWriter(outputFile); writer.write(output); writer.close(); } catch (InterruptedException ex) { throw new TavernaException("Workflow was interrupted.", ex); } catch (IOException ex) { throw new TavernaException("Workflow output could not be saved.", ex); } finally { try { if (writer != null) { writer.close(); } } catch (IOException ex) { throw new TavernaException("Workflow output could not be saved.", ex); } } return output; }
/** * Starts a run of Tavernas Command Line tool based on the provided parameters. * * @param tavernaHome Location of the bat or sh file to be run. * @param outputRoot Location where the different outputs will be written. This are: * <dl> * <dt>BaclavaOutput.xml * <dd>Output saved by the workflow * <dt>Output.txt * <dd>Output of this class including parameters passed to the bat.script and a capture of * anything that sends to output or error streams. * <dt>TavernaLog.txt * <dd>Log file generated by the workflow * </dl> * * @param inputs Array of the inputs plus the values provided by the users. If not null this is * the preferred source of inputs. * @param inputsURI URI to a Baclava file that holds the inputs. File uris should begin with * "file:" Ignored if null or "inputs" not null. If both "inputs" and "inputsURI" are null * workflow is assumed not to have any inputs. * @param workflowURI URI to a workflow file that holds the inputs. File uris should begin with * "file:" * @throws TavernaException Throw if the inputs passed in are determined as incorrect before the * workflow is run. * @throws IOException Throw if accessing any of the File parameters, or child files created, * causes such an exception. */ public CommandLineRun( File tavernaHome, File outputRoot, TavernaInput[] inputs, String inputsURI, String workflowURI) throws TavernaException, IOException, URISyntaxException { ArrayList<String> cmd = getLaunch(tavernaHome); runDirectory = Utils.createCalendarBasedDirectory(outputRoot); baclavaFile = new File(runDirectory, "BaclavaOutput.xml"); cmd.add("-outputdoc=" + baclavaFile.getAbsolutePath()); File logFile = new File(runDirectory, "TavernaLog.txt"); cmd.add("-logfile=" + logFile.getAbsolutePath()); if (inputs != null) { // the useris passing all inputs individually System.out.append("Running workflow with individual inputs."); // for (TavernaInput input:inputs){ // cmd.addAll(input.getInputArguments()); // } // Create Baclava input file from all the inputs gathered and pass that as an input to // the Taverna Command Line Tool/Server - this is more convenient as we use just one file // for all the inputs and we can also pass more complex inputs rather than just one-line // strings Map<String, Object> valueMap = new HashMap<String, Object>(); for (TavernaInput input : inputs) { valueMap.put(input.getName(), input.getValue()); } Map<String, DataThing> dataThingsMap = DataThingBasedBaclava.bakeDataThingMap(valueMap); // Build the XML Baclava document containing the workflow inputs Document document = DataThingBasedBaclava.getDataDocument(dataThingsMap); Random randomGenerator = new Random(); File baclavaInputFile = new File( System.getProperty("java.io.tmpdir"), Integer.toString(randomGenerator.nextInt(999999)) + "-baclava.xml"); java.io.FileWriter writer = null; try { XMLOutputter out = new XMLOutputter(); writer = new java.io.FileWriter(baclavaInputFile); out.output(document, writer); writer.flush(); writer.close(); } catch (Exception ex) { System.out.println( "Failed to save Baclava inputs to file " + baclavaInputFile.getAbsolutePath()); ex.printStackTrace(); } finally { try { if (writer != null) { writer.close(); } } catch (Exception ex2) { // Ignore } } // Probably won't work on Windows String baclavaInputURL = "file://" + new URI(baclavaInputFile.getAbsolutePath()).toASCIIString(); System.out.println( "Converted all individual inputs to a local Baclava file : " + baclavaInputURL); cmd.add("-inputdoc=" + baclavaInputURL); } else if (inputsURI != null) { // the user is passing a Baclava file with all the inputs System.out.println("Running workflow with Baclava inputs from " + inputsURI); cmd.add("-inputdoc=" + inputsURI); } cmd.add(workflowURI); String[] command = new String[0]; command = cmd.toArray(command); System.out.println("Executing command " + cmd.toString()); runner = new ProcessRunner(command, tavernaHome); runner.start(); }
/** * Used to destroy a workflow run. * * <p>Stops a workflow run by passing a destroy request to the process that is running it. */ public void destroy() { runner.destroy(); }
/** * Returns the output of the workflow run up to this point. * * <p>Non blocking method that returns the output of the workflow up to this point. Expected to * hold the parameters used to start the workflow. Depending on when it is called may (but is * never guaranteed to) include intermediate workflow output or even results. * * <p>Unlike other methods this one is not expected to fail or throw an Exception even if the run * fails or was interrupted but this behaviour is not guaranteed. * * @return Partial workflow output */ public String getRunInfo() { return runner.getRunInfo(); }