/* * Copyright 2005-2010 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 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.StringWriter; import java.io.Writer; import java.util.Arrays; import java.util.logging.Level; import java.util.logging.Logger; /** * * @author $author$ * @version $Revision$ */ public class SimpleProcess { private static final Logger LOG = Logger.getLogger(SimpleProcess.class .getName()); private File directory; private String[] cmd; private String stdout; private String stderr; /** * Creates a new SimpleProcess object. * */ public SimpleProcess(File aDirectory, String[] aCmd) { directory = aDirectory; cmd = Arrays.copyOf(aCmd, aCmd.length); } /** * * @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 { StringBuffer fullcmd = new StringBuffer(); for (String part : cmd) { fullcmd.append(" " + part); } LOG.fine("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 myStdout = new StringWriter(); StringWriter myStderr = new StringWriter(); Thread stdoutReader = readAndLogStream("STDOUT> ", proc .getInputStream(), myStdout); Thread stderrReader = readAndLogStream("STDERR> ", proc .getErrorStream(), myStderr); try { proc.waitFor(); } catch (InterruptedException e) { IOException exception = new IOException( "Process was terminated: " + this); exception.initCause(e); throw exception; } waitForReader(stdoutReader); waitForReader(stderrReader); stdout = myStdout.toString(); stderr = myStderr.toString(); if (proc.exitValue() != 0) { LOG.warning("Exit value was non-zero: " + this); } else { LOG.fine("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 .log( Level.WARNING, this + ": error waiting for output stream reader of process to finish", e); } } 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.fine(aPrefix + str); aOutput.write(str); } } catch (IOException e) { LOG.log(Level.FINE, SimpleProcess.this + ": error reading input stream", e); } finally { if (br != null) { try { br.close(); } catch (IOException e) { LOG.log(Level.WARNING, "Error closing stream " + aPrefix, e); } } } } }; inputReader.start(); return inputReader; } @Override public String toString() { StringBuffer fullcmd = new StringBuffer(); for (String part : cmd) { fullcmd.append(part + " "); } return "process(dir = '" + directory + "', cmd = '" + fullcmd + "')"; } }