TimeoutProcess.java

/*
 * TimeoutProcess
 *
 * $Id$
 * $URL$
 */
package gov.usgs.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Timer;

/**
 * TimeoutProcess wraps a Process object.
 *
 * It is most commonly used with TimeoutProcessBuilder, which configures the
 * process timeout (and sets the timed out state once the timeout is reached).
 *
 * @see java.lang.Process
 * @see TimeoutProcessBuilder
 * @see ProcessTimeoutException
 */
public class TimeoutProcess {

  /** The wrapped process */
  private Process process;

  /** Whether this process timed out. */
  private boolean timeoutElapsed = false;

  /** Timer object that will destroy this process. */
  private Timer timer = null;

  /** Standard error output. */
  private byte[] errorOutput;

  /**
   * Construct a new TimeoutProcess.
   *
   * @param process the wrapped process.
   */
  protected TimeoutProcess(Process process) {
    this.process = process;
  }

  /** Destroys a process */
  public void destroy() {
    process.destroy();
  }

  /** @return errorOutput byte array */
  public byte[] errorOutput() {
    return errorOutput;
  }

  /** @return exit value */
  public int exitValue() {
    return process.exitValue();
  }

  /** @return InputStream of error stream */
  public InputStream getErrorStream() {
    return process.getErrorStream();
  }

  /** @return InputStream */
  public InputStream getInputStream() {
    return process.getInputStream();
  }

  /** @return OutputStream */
  public OutputStream getOutputStream() {
    return process.getOutputStream();
  }

  /**
   * Wait for the process to complete, either normally or because its timeout was
   * reached.
   *
   * @return exitStatus.
   * @throws InterruptedException    if thread interruption occurs
   * @throws IOException             if IO error occurs
   * @throws ProcessTimeoutException if the process timed out before exiting.
   */
  public int waitFor() throws InterruptedException, IOException, ProcessTimeoutException {
    int status = -1;
    try {
      status = process.waitFor();

      if (timeoutElapsed()) {
        throw new ProcessTimeoutException("The process has timed out.");
      }
    } finally {
      if (timer != null) {
        // the timer hasn't destroyed this process already, cancel it.
        timer.cancel();
      }
    }

    try {
      errorOutput = StreamUtils.readStream(getErrorStream());
    } finally {
      // close streams
      StreamUtils.closeStream(getErrorStream());
      StreamUtils.closeStream(getInputStream());
      StreamUtils.closeStream(getOutputStream());
    }

    return status;
  }

  /** @param timeoutElapsed to set */
  protected void setTimeoutElapsed(boolean timeoutElapsed) {
    this.timeoutElapsed = timeoutElapsed;
  }

  /** @return timeoutElapsed boolean */
  protected boolean timeoutElapsed() {
    return timeoutElapsed;
  }

  /** @param timer to set */
  protected void setTimer(final Timer timer) {
    this.timer = timer;
  }

}