Mega Code Archive

 
Categories / Java / Development Class
 

Launches a process, redirecting the output of that sub-process to the output of this (the parent) process

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);     }   } }