--- /dev/null
+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 + "')";
+ }
+}