package org.wamblee.io; 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.PrintStream; import java.io.StringWriter; import java.io.Writer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class SimpleProcess { private static final Log LOG = LogFactory.getLog(SimpleProcess.class); private File _directory; private String[] _cmd; private String _stdout; private String _stderr; public SimpleProcess(File aDirectory, String[] aCmd) { _directory = aDirectory; _cmd = aCmd; } /** * @return the stdout */ public String getStdout() { return _stdout; } /** * @return the stderr */ public String getStderr() { return _stderr; } /** * Runs the process and blocks until it is done. * * @return Exit status of the process. * @throws IOException * In case of problems. */ public int run() throws IOException { return runImpl(); } private int runImpl() throws IOException { try { String fullcmd = ""; for (String part: _cmd) { fullcmd += " " + part; } LOG.debug("Executing '" + fullcmd + "' in directory '" + _directory + "'"); java.lang.Process proc = Runtime.getRuntime().exec(_cmd, null, _directory); // Read standard output and error in separate threads to avoid // deadlock. StringWriter stdout = new StringWriter(); StringWriter stderr = new StringWriter(); Thread stdoutReader = readAndLogStream("STDOUT> ", proc .getInputStream(), stdout); Thread stderrReader = readAndLogStream("STDERR> ", proc .getErrorStream(), stderr); try { proc.waitFor(); } catch (InterruptedException e) { IOException exception = new IOException( "Process was terminated: " + this); exception.initCause(e); throw exception; } waitForReader(stdoutReader); waitForReader(stderrReader); _stdout = stdout.toString(); _stderr = stderr.toString(); if (proc.exitValue() != 0) { LOG.warn("Exit value was non-zero: " + this); } else { LOG.debug("Process finished"); } return proc.exitValue(); } catch (IOException e) { IOException exception = new IOException("Error executing process: " + this); exception.initCause(e); throw exception; } } private void waitForReader(Thread aReaderThread) { try { aReaderThread.join(); } catch (InterruptedException e) { LOG .warn(this + ": error waiting for output stream reader of process to finish"); } } private Thread readAndLogStream(final String aPrefix, final InputStream aStream, final Writer aOutput) { Thread inputReader = new Thread() { @Override public void run() { BufferedReader br = null; try { br = new BufferedReader(new InputStreamReader(aStream)); String str; while ((str = br.readLine()) != null) { LOG.debug(aPrefix + str); aOutput.write(str); } } catch (IOException e) { LOG.warn(SimpleProcess.this + ": error reading input stream", e); } finally { if (br != null) { try { br.close(); } catch (IOException e) { LOG.warn("Error closing stream " + aPrefix); } } } } }; inputReader.start(); return inputReader; } @Override public String toString() { String fullcmd = ""; for (String part: _cmd) { fullcmd += part + " "; } return "process(dir = '" + _directory + "', cmd = '" + fullcmd + "')"; } }