Launches a process, redirecting the output of that sub-process to the output of this (the parent) process. : ProcessBuilder « Development Class « Java






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

   
    
    
  








Related examples in the same category

1.ProcessBuilder Demo
2.Use ProcessBuilder.environment()
3.Use of ProcessBuilder that duplicates the functions of the DoRuntime example:
4.Exec Helper
5.Process Watcher
6.Execute a command