Java tutorial
import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Iterator; import java.util.logging.Level; import java.util.logging.Logger; /** * Launches a process, redirecting the output of that sub-process to the output * of this (the parent) process. * * @author Klaas Waslander */ public final class ProcessLauncher { /** the logger for this class */ private final static Logger LOGGER = Logger.getLogger(ProcessLauncher.class.getName()); private String commandLine; private String[] commandArray; private File baseDir; private ArrayList listeners = new ArrayList(1); private Process subProcess; private boolean finished = false; StringBuffer out = new StringBuffer(); StringBuffer err = new StringBuffer(); /** * Constructs new process launcher with the given command line. */ public ProcessLauncher(String commandLine) { this(commandLine, null); } public ProcessLauncher(String commandLine, File baseDir) { this.commandLine = commandLine; this.baseDir = baseDir; } /** * Constructs new process launcher with the given command array. */ public ProcessLauncher(String[] commandArray) { this(commandArray, null); } public ProcessLauncher(String[] commandArray, File baseDir) { this.commandArray = commandArray; this.baseDir = baseDir; } /** * Constructs new process launcher with the given command element list. */ public ProcessLauncher(ArrayList commandList) { this(commandList, null); } public ProcessLauncher(ArrayList commandList, File baseDir) { this(toStringArray(commandList), baseDir); } private static String[] toStringArray(ArrayList list) { String[] result = new String[list.size()]; Iterator iter = list.iterator(); int arrayIndex = 0; while (iter.hasNext()) { result[arrayIndex++] = iter.next().toString(); } return result; } /** * Classes implementing this interface can receive output generated by * processes launched using the ProcessLauncher. */ public interface OutputListener { public void standardOutput(char[] output); public void errorOutput(char[] output); } /** * Add a listener for output from the to-be-launched process. */ public void addOutputListener(OutputListener listener) { this.listeners.add(listener); } /** fire error output event */ private void fireErr(char[] err) { if (this.listeners.isEmpty()) { this.err.append(out); } Iterator iter = this.listeners.iterator(); while (iter.hasNext()) { ((OutputListener) iter.next()).errorOutput(err); } } /** fire standard output event */ private void fireOut(char[] out) { if (this.listeners.isEmpty()) { this.out.append(out); } Iterator iter = this.listeners.iterator(); while (iter.hasNext()) { ((OutputListener) iter.next()).standardOutput(out); } } /** * Get standard output, in case no listeners were registered - never returns * null. */ public String getStandardOutput() { if (!this.listeners.isEmpty()) { throw new IllegalStateException( "Cannot get standard output, because outputlisteners have been registered."); } return this.out.toString(); } /** * Get error output, in case no listeners were registered - never returns * null. */ public String getErrorOutput() { if (!this.listeners.isEmpty()) { throw new IllegalStateException( "Cannot get error output, because outputlisteners have been registered."); } return this.err.toString(); } /** * Get the commandline that is used to launch the process. */ public String getCommandLine() { String usedCommand = this.commandLine; if (this.commandLine == null && this.commandArray != null) { usedCommand = ""; for (int i = 0; i < this.commandArray.length; i++) { if (i > 0) { usedCommand += " "; } usedCommand += this.commandArray[i]; } } return usedCommand; } /** * Check whether execution has finished. */ public boolean hasFinished() { return finished; } /** * Launches the process, and blocks until that process completes execution. * * @throws CommandNotExistsException * If the command could not be executed because it does not exist */ public int launch() throws CommandNotExistsException { this.err.setLength(0); this.out.setLength(0); BackgroundPrinter stdout = null; BackgroundPrinter stderr = null; try { if (this.commandArray != null) { this.subProcess = Runtime.getRuntime().exec(this.commandArray, null, this.baseDir); } else { this.subProcess = Runtime.getRuntime().exec(this.commandLine, null, this.baseDir); } stdout = new BackgroundPrinter(subProcess.getInputStream(), false); stderr = new BackgroundPrinter(subProcess.getErrorStream(), true); stdout.start(); stderr.start(); // kill process and wait max 10 seconds for output to complete int exitValue = this.subProcess.waitFor(); stdout.join(10000); stderr.join(10000); /* * if (exitValue != 0) { LOGGER.fine("WARNING: exit value " + exitValue + " * for command \"" + getCommandLine() + "\""); } */ return exitValue; } catch (IOException ioe) { // usually caused if the command does not exist at all throw new CommandNotExistsException("Command probably does not exist: " + ioe); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Exception while running/launching \"" + getCommandLine() + "\".", e); } finally { if (this.subProcess != null) { this.subProcess.destroy(); this.subProcess = null; } if (stdout != null) { stdout.close(); } if (stderr != null) { stderr.close(); } this.finished = true; } return -1; } /** * Tries to abort the currently running process. */ public void abort() { if (this.subProcess != null) { this.subProcess.destroy(); this.subProcess = null; } } /** * Catches output from a "java.lang.Process" and writes it to either * System.err or System.out. * * @author Klaas Waslander - Sun Java Center */ private class BackgroundPrinter extends Thread { private InputStream in; boolean isErrorOutput; public BackgroundPrinter(InputStream in, boolean isErrorOutput) { this.in = in; this.isErrorOutput = isErrorOutput; } public void run() { try { BufferedReader reader = new BufferedReader(new InputStreamReader(this.in)); // read buffer char[] buf = new char[1024]; // write data to target, until no more data is left to read int numberOfReadBytes; while ((numberOfReadBytes = reader.read(buf)) != -1) { char[] clearedbuf = new char[numberOfReadBytes]; System.arraycopy(buf, 0, clearedbuf, 0, numberOfReadBytes); if (this.isErrorOutput) { fireErr(clearedbuf); } else { fireOut(clearedbuf); } } /* * } catch (IOException ioe) { // ignore this: process has ended, * causing IOException } catch (NullPointerException ioe) { // ignore * this: there was no resulting output */ } catch (Exception e) { LOGGER.log(Level.FINE, "Exception while reading from stream from subprocess.", e); } } public void close() { try { this.in.close(); } catch (Exception e) { LOGGER.log(Level.WARNING, "Closing background stream for launched process caused exception.", e); } } } /** * Exception that is thrown when a command could not be executed because it * (probably) does not exist at all. * * @author Klaas Waslander */ public static class CommandNotExistsException extends RuntimeException { /** * Construct a new exception for a command that does not exist. * * @param msg * The message for this exception. */ public CommandNotExistsException(String msg) { super(msg); } } }