Class ProcessExecutor

java.lang.Object
org.zeroturnaround.exec.ProcessExecutor

public class ProcessExecutor extends Object
Helper for executing sub processes.

It's implemented as a wrapper of ProcessBuilder complementing it with additional features such as:

  • Handling process streams (copied from Commons Exec library).
  • Destroying process on VM exit (copied from Commons Exec library).
  • Checking process exit code.
  • Setting a timeout for running the process and automatically stopping it in case of timeout.
  • Either waiting for the process to finish (execute()) or returning a Future (start().
  • Reading the process output stream into a buffer (readOutput(boolean), ProcessResult).

The default configuration for executing a process is following:

See Also:
  • Field Details

    • log

      private static final org.slf4j.Logger log
    • IS_OS_WINDOWS

      private static final boolean IS_OS_WINDOWS
    • DEFAULT_EXIT_VALUES

      public static final Integer[] DEFAULT_EXIT_VALUES
    • NORMAL_EXIT_VALUE

      private static final Integer NORMAL_EXIT_VALUE
    • DEFAULT_REDIRECT_ERROR_STREAM

      public static final boolean DEFAULT_REDIRECT_ERROR_STREAM
      See Also:
    • builder

      private final ProcessBuilder builder
      Process builder used by this executor.
    • environment

      private final Map<String,String> environment
      Environment variables which are added (removed in case of null values) to the process being started.
    • allowedExitValues

      private Set<Integer> allowedExitValues
      Set of accepted exit codes or null if all exit codes are allowed.
    • timeout

      private Long timeout
      Timeout for running a process. If the process is running too long a TimeoutException is thrown and the process is destroyed.
    • timeoutUnit

      private TimeUnit timeoutUnit
    • stopper

      private ProcessStopper stopper
      Helper for stopping the process in case of timeout or cancellation.
    • streams

      private ExecuteStreamHandler streams
      Process stream Handler (copied from Commons Exec library). If null streams are not handled.
    • closeTimeout

      private Long closeTimeout
      Timeout for closing process' standard streams. In case this timeout is reached we just log a warning but don't throw an error.
    • closeTimeoutUnit

      private TimeUnit closeTimeoutUnit
    • readOutput

      private boolean readOutput
      true if the process output should be read to a buffer and returned by ProcessResult.output().
    • listeners

      private final CompositeProcessListener listeners
      Process event handlers.
    • messageLogger

      private MessageLogger messageLogger
      Helper for logging messages about starting and waiting for the processes.
  • Constructor Details

    • ProcessExecutor

      public ProcessExecutor()
      Creates new ProcessExecutor instance.
    • ProcessExecutor

      public ProcessExecutor(List<String> command)
      Creates new ProcessExecutor instance for the given program and its arguments.
      Parameters:
      command - The list containing the program and its arguments.
    • ProcessExecutor

      public ProcessExecutor(String... command)
      Creates new ProcessExecutor instance for the given program and its arguments.
      Parameters:
      command - A string array containing the program and its arguments.
    • ProcessExecutor

      public ProcessExecutor(Iterable<String> command)
      Creates new ProcessExecutor instance for the given program and its arguments.
      Parameters:
      command - The iterable containing the program and its arguments.
      Since:
      1.8
  • Method Details

    • getCommand

      public List<String> getCommand()
      Returns this process executor's operating system program and arguments. The returned list is a copy.
      Returns:
      this process executor's program and its arguments (not null).
    • command

      public ProcessExecutor command(List<String> command)
      Sets the program and its arguments which are being executed.
      Parameters:
      command - The list containing the program and its arguments.
      Returns:
      This process executor.
    • command

      public ProcessExecutor command(String... command)
      Sets the program and its arguments which are being executed.
      Parameters:
      command - A string array containing the program and its arguments.
      Returns:
      This process executor.
    • command

      public ProcessExecutor command(Iterable<String> command)
      Sets the program and its arguments which are being executed.
      Parameters:
      command - The iterable containing the program and its arguments.
      Returns:
      This process executor.
      Since:
      1.8
    • commandSplit

      public ProcessExecutor commandSplit(String commandWithArgs)
      Splits string by spaces and passes it to command(String...)
      NB: this method do not handle whitespace escaping, "mkdir new\ folder" would be interpreted as {"mkdir", "new\", "folder"} command.
      Parameters:
      commandWithArgs - A string array containing the program and its arguments.
      Returns:
      This process executor.
    • getDirectory

      public File getDirectory()
      Returns this process executor's working directory. Subprocesses subsequently started by this object will use this as their working directory. The returned value may be null -- this means to use the working directory of the current Java process, usually the directory named by the system property user.dir, as the working directory of the child process.
      Returns:
      this process executor's working directory
    • directory

      public ProcessExecutor directory(File directory)
      Sets this working directory for the process being executed. The argument may be null -- this means to use the working directory of the current Java process, usually the directory named by the system property user.dir, as the working directory of the child process.
      Parameters:
      directory - The new working directory
      Returns:
      This process executor.
    • getEnvironment

      public Map<String,String> getEnvironment()
      Returns this process executor's additional environment variables. The returned value is not a copy.
      Returns:
      this process executor's environment variables (not null).
    • environment

      public ProcessExecutor environment(Map<String,String> env)
      Adds additional environment variables for the process being executed.
      Parameters:
      env - environment variables added to the process being executed.
      Returns:
      This process executor.
    • environment

      public ProcessExecutor environment(String name, String value)
      Adds a single additional environment variable for the process being executed.
      Parameters:
      name - name of the environment variable added to the process being executed.
      value - value of the environment variable added to the process being executed.
      Returns:
      This process executor.
      Since:
      1.7
    • redirectErrorStream

      public ProcessExecutor redirectErrorStream(boolean redirectErrorStream)
      Sets this process executor's redirectErrorStream property.

      If this property is true, then any error output generated by subprocesses will be merged with the standard output. This makes it easier to correlate error messages with the corresponding output. The initial value is true.

      Parameters:
      redirectErrorStream - The new property value
      Returns:
      This process executor.
    • exitValueAny

      public ProcessExecutor exitValueAny()
      Allows any exit value for the process being executed.
      Returns:
      This process executor.
    • exitValueNormal

      public ProcessExecutor exitValueNormal()
      Allows only 0 as the exit value for the process being executed.
      Returns:
      This process executor.
    • exitValue

      public ProcessExecutor exitValue(Integer exitValue)
      Sets the allowed exit value for the process being executed.
      Parameters:
      exitValue - single exit value or null if all exit values are allowed.
      Returns:
      This process executor.
    • exitValues

      public ProcessExecutor exitValues(Integer... exitValues)
      Sets the allowed exit values for the process being executed.
      Parameters:
      exitValues - set of exit values or null if all exit values are allowed.
      Returns:
      This process executor.
    • exitValues

      public ProcessExecutor exitValues(int[] exitValues)
      Sets the allowed exit values for the process being executed.
      Parameters:
      exitValues - set of exit values or null if all exit values are allowed.
      Returns:
      This process executor.
    • timeout

      public ProcessExecutor timeout(long timeout, TimeUnit unit)
      Sets a timeout for the process being executed. When this timeout is reached a TimeoutException is thrown and the process is destroyed. This only applies to execute methods not start methods.
      Parameters:
      timeout - timeout for running a process.
      unit - the time unit of the timeout
      Returns:
      This process executor.
    • stopper

      public ProcessExecutor stopper(ProcessStopper stopper)
      Sets the helper for stopping the process in case of timeout or cancellation.

      By default DestroyProcessStopper is used which just invokes Process.destroy().

      Parameters:
      stopper - helper for stopping the process (null means NopProcessStopper - process is not stopped).
      Returns:
      This process executor.
    • streams

      public ExecuteStreamHandler streams()
      Returns:
      current stream handler for the process being executed.
    • streams

      public ProcessExecutor streams(ExecuteStreamHandler streams)
      Sets a stream handler for the process being executed. This will overwrite any stream redirection that was previously set to use the provided handler.
      Parameters:
      streams - the stream handler
      Returns:
      This process executor.
    • closeTimeout

      public ProcessExecutor closeTimeout(long timeout, TimeUnit unit)
      Sets a timeout for closing standard streams of the process being executed. When this timeout is reached we log a warning but consider that the process has finished. We also flush the streams so that all output read so far is available.

      This can be used on Windows in case a process exits quickly but closing the streams blocks forever.

      Closing timeout must fit into the general execution timeout (see timeout(long, TimeUnit)). By default there's no closing timeout.

      Parameters:
      timeout - timeout for closing streams of a process.
      unit - the time unit of the timeout
      Returns:
      This process executor.
    • redirectInput

      public ProcessExecutor redirectInput(InputStream input)
      Sets the input stream to redirect to the process' input stream. If this method is invoked multiple times each call overwrites the previous.
      Parameters:
      input - input stream that will be written to the process input stream (null means nothing will be written to the process input stream).
      Returns:
      This process executor.
    • redirectOutput

      public ProcessExecutor redirectOutput(OutputStream output)
      Redirects the process' output stream to given output stream. If this method is invoked multiple times each call overwrites the previous. Use redirectOutputAlsoTo(OutputStream) if you want to redirect the output to multiple streams.
      Parameters:
      output - output stream where the process output is redirected to (null means NullOutputStream which acts like a /dev/null).
      Returns:
      This process executor.
    • redirectError

      public ProcessExecutor redirectError(OutputStream output)
      Redirects the process' error stream to given output stream. If this method is invoked multiple times each call overwrites the previous. Use redirectErrorAlsoTo(OutputStream) if you want to redirect the error to multiple streams.

      Calling this method automatically disables merging the process error stream to its output stream.

      Parameters:
      output - output stream where the process error is redirected to (null means NullOutputStream which acts like a /dev/null).
      Returns:
      This process executor.
    • redirectOutputAlsoTo

      public ProcessExecutor redirectOutputAlsoTo(OutputStream output)
      Redirects the process' output stream also to a given output stream. This method can be used to redirect output to multiple streams.
      Parameters:
      output - the stream to redirect this output to
      Returns:
      This process executor.
    • redirectErrorAlsoTo

      public ProcessExecutor redirectErrorAlsoTo(OutputStream output)
      Redirects the process' error stream also to a given output stream. This method can be used to redirect error to multiple streams.

      Calling this method automatically disables merging the process error stream to its output stream.

      Parameters:
      output - the output stream to redirect the error stream to
      Returns:
      This process executor.
    • pumps

      public PumpStreamHandler pumps()
      Returns:
      current PumpStreamHandler (maybe null).
      Throws:
      IllegalStateException - if the current stream handler is not an instance of PumpStreamHandler.
      See Also:
    • redirectOutputAlsoTo

      private static PumpStreamHandler redirectOutputAlsoTo(PumpStreamHandler pumps, OutputStream output)
      Redirects the process' output stream also to a given output stream.
      Returns:
      new stream handler created.
    • redirectErrorAlsoTo

      private static PumpStreamHandler redirectErrorAlsoTo(PumpStreamHandler pumps, OutputStream output)
      Redirects the process' error stream also to a given output stream.
      Returns:
      new stream handler created.
    • readOutput

      public ProcessExecutor readOutput(boolean readOutput)
      Sets this process executor's readOutput property.

      If this property is true, the process output should be read to a buffer and returned by ProcessResult.output(). The initial value is false.

      Parameters:
      readOutput - The new property value
      Returns:
      This process executor.
    • validateStreams

      private void validateStreams(ExecuteStreamHandler streams, boolean readOutput)
      Validates that if readOutput is true the output could be read with the given ExecuteStreamHandler instance.
    • info

      public ProcessExecutor info(org.slf4j.Logger log)
      Logs the process' output to a given Logger with info level.
      Parameters:
      log - the logger to process the output to
      Returns:
      This process executor.
    • debug

      public ProcessExecutor debug(org.slf4j.Logger log)
      Logs the process' output to a given Logger with debug level.
      Parameters:
      log - the logger to process the output to
      Returns:
      This process executor.
    • info

      public ProcessExecutor info(String name)
      Logs the process' output to a Logger with given name using info level.
      Parameters:
      name - the name of the logger to process the output to
      Returns:
      This process executor.
    • debug

      public ProcessExecutor debug(String name)
      Logs the process' output to a Logger with given name using debug level.
      Parameters:
      name - the name of the logger to process the output to
      Returns:
      This process executor.
    • info

      public ProcessExecutor info()
      Logs the process' output to a Logger of the caller class using info level.
      Returns:
      This process executor.
    • debug

      public ProcessExecutor debug()
      Logs the process' output to a Logger of the caller class using debug level.
      Returns:
      This process executor.
    • redirectOutputAsInfo

      public ProcessExecutor redirectOutputAsInfo(org.slf4j.Logger log)
      Logs the process' output to a given Logger with info level.
      Parameters:
      log - the logger to output the message to
      Returns:
      This process executor.
    • redirectOutputAsDebug

      public ProcessExecutor redirectOutputAsDebug(org.slf4j.Logger log)
      Logs the process' output to a given Logger with debug level.
      Parameters:
      log - the logger to output the message to
      Returns:
      This process executor.
    • redirectOutputAsInfo

      public ProcessExecutor redirectOutputAsInfo(String name)
      Logs the process' output to a Logger with given name using info level.
      Parameters:
      name - the name of the logger to log to
      Returns:
      This process executor.
    • redirectOutputAsDebug

      public ProcessExecutor redirectOutputAsDebug(String name)
      Logs the process' output to a Logger with given name using debug level.
      Parameters:
      name - the name of the logger to process output to
      Returns:
      This process executor.
    • redirectOutputAsInfo

      public ProcessExecutor redirectOutputAsInfo()
      Logs the process' output to a Logger of the caller class using info level.
      Returns:
      This process executor.
    • redirectOutputAsDebug

      public ProcessExecutor redirectOutputAsDebug()
      Logs the process' output to a Logger of the caller class using debug level.
      Returns:
      This process executor.
    • redirectErrorAsInfo

      public ProcessExecutor redirectErrorAsInfo(org.slf4j.Logger log)
      Logs the process' error to a given Logger with info level.
      Parameters:
      log - the logger to process output to
      Returns:
      This process executor.
    • redirectErrorAsDebug

      public ProcessExecutor redirectErrorAsDebug(org.slf4j.Logger log)
      Logs the process' error to a given Logger with debug level.
      Parameters:
      log - the logger to process the error to
      Returns:
      This process executor.
    • redirectErrorAsInfo

      public ProcessExecutor redirectErrorAsInfo(String name)
      Logs the process' error to a Logger with given name using info level.
      Parameters:
      name - the name of the logger to process the error to
      Returns:
      This process executor.
    • redirectErrorAsDebug

      public ProcessExecutor redirectErrorAsDebug(String name)
      Logs the process' error to a Logger with given name using debug level.
      Parameters:
      name - the name of the logger to process the error to
      Returns:
      This process executor.
    • redirectErrorAsInfo

      public ProcessExecutor redirectErrorAsInfo()
      Logs the process' error to a Logger of the caller class using info level.
      Returns:
      This process executor.
    • redirectErrorAsDebug

      public ProcessExecutor redirectErrorAsDebug()
      Logs the process' error to a Logger of the caller class using debug level.
      Returns:
      This process executor.
    • getCallerLogger

      private org.slf4j.Logger getCallerLogger(String name)
      Creates a Logger for the ProcessExecutor's caller class.
      Parameters:
      name - name of the logger.
      Returns:
      SLF4J Logger instance.
    • addDestroyer

      public ProcessExecutor addDestroyer(ProcessDestroyer destroyer)
      Adds a process destroyer to be notified when the process starts and stops.
      Parameters:
      destroyer - helper for destroying all processes on certain event such as VM exit (not null).
      Returns:
      This process executor.
    • destroyer

      public ProcessExecutor destroyer(ProcessDestroyer destroyer)
      Sets the process destroyer to be notified when the process starts and stops.

      This methods always removes any other ProcessDestroyer registered. Use addDestroyer(ProcessDestroyer) to keep the existing ones.

      Parameters:
      destroyer - helper for destroying all processes on certain event such as VM exit (maybe null).
      Returns:
      This process executor.
    • destroyOnExit

      public ProcessExecutor destroyOnExit()
      Sets the started process to be destroyed on VM exit (shutdown hooks are executed). If this VM gets killed the started process may not get destroyed.

      To undo this command call destroyer(null).

      Returns:
      This process executor.
    • listener

      public ProcessExecutor listener(ProcessListener listener)
      Unregister all existing process event handlers and register new one.
      Parameters:
      listener - process event handler to be set (maybe null).
      Returns:
      This process executor.
    • addListener

      public ProcessExecutor addListener(ProcessListener listener)
      Register new process event handler.
      Parameters:
      listener - process event handler to be added.
      Returns:
      This process executor.
    • removeListener

      public ProcessExecutor removeListener(ProcessListener listener)
      Unregister existing process event handler.
      Parameters:
      listener - process event handler to be removed.
      Returns:
      This process executor.
    • removeListeners

      public ProcessExecutor removeListeners(Class<? extends ProcessListener> listenerType)
      Unregister existing process event handlers of given type or its sub-types.
      Parameters:
      listenerType - process event handler type.
      Returns:
      This process executor.
    • clearListeners

      public ProcessExecutor clearListeners()
      Unregister all existing process event handlers.
      Returns:
      This process executor.
    • setMessageLogger

      public ProcessExecutor setMessageLogger(MessageLogger messageLogger)
      Changes how most common messages about starting and waiting for processes are actually logged. By default MessageLoggers.DEBUG is used. However if someone is executing a process every second MessageLoggers.TRACE may be used e.g.
      Parameters:
      messageLogger - message logger for certain level.
      Returns:
      This process executor.
    • execute

      Executes the sub process. This method waits until the process exits, a timeout occurs or the caller thread gets interrupted. In the latter cases the process gets destroyed as well.
      Returns:
      exit code of the finished process.
      Throws:
      IOException - an error occurred when process was started or stopped.
      InterruptedException - this thread was interrupted.
      TimeoutException - timeout set by timeout(long, TimeUnit) was reached.
      InvalidExitValueException - if invalid exit value was returned (@see exitValues(Integer...)).
    • executeNoTimeout

      Executes the sub process. This method waits until the process exits. Value passed to timeout(long, TimeUnit) is ignored (use execute() for timeout).
      Returns:
      exit code of the finished process.
      Throws:
      IOException - an error occurred when process was started or stopped.
      InterruptedException - this thread was interrupted.
      InvalidExitValueException - if invalid exit value was returned (@see exitValues(Integer...)).
    • checkExitValue

      public void checkExitValue(ProcessResult result) throws InvalidExitValueException
      Check the exit value of given process result. This can be used by unit tests.
      Parameters:
      result - process result which maybe constructed by a unit test.
      Throws:
      InvalidExitValueException - if the given exit value was rejected.
    • start

      public StartedProcess start() throws IOException
      Start the sub process. This method does not wait until the process exits. Value passed to timeout(long, TimeUnit) is ignored. Use Future.get() to wait for the process to finish. Invoke future.cancel(true); to destroy the process.
      Returns:
      Future representing the exit value of the finished process.
      Throws:
      IOException - an error occurred when process was started.
    • startInternal

      protected final WaitForProcess startInternal() throws IOException
      Start the process and its stream handlers.
      Returns:
      process the started process.
      Throws:
      IOException - the process or its stream handlers couldn't start (in the latter case we also destroy the process).
    • getAttributes

      private ProcessAttributes getAttributes()
      Capture a snapshot of this process executor's main state.
    • invokeStart

      private Process invokeStart() throws IOException
      Throws:
      IOException
    • getExecutingLogMessage

      private String getExecutingLogMessage()
    • getExecutingErrorMessage

      private String getExecutingErrorMessage()
    • getExecutingMessageParams

      private String getExecutingMessageParams()
    • startInternal

      private WaitForProcess startInternal(Process process, ProcessAttributes attributes, ExecuteStreamHandler streams, ByteArrayOutputStream out) throws IOException
      Throws:
      IOException
    • newProcessCloser

      private ProcessCloser newProcessCloser(ExecuteStreamHandler streams)
    • waitFor

      Wait until the process stops, a timeout occurs and the caller thread gets interrupted. In the latter cases the process gets destroyed as well.
      Throws:
      IOException
      InterruptedException
      TimeoutException
    • newExecutor

      private ExecutorService newExecutor(WaitForProcess task)
    • newExecutor

      protected ExecutorService newExecutor(String processName)
    • invokeSubmit

      protected <T> Future<T> invokeSubmit(ExecutorService executor, Callable<T> task)
      Override this to customize how the waiting task is started in the background.
      Type Parameters:
      T - the type of the task
      Parameters:
      executor - the executor service to submit the task on
      task - the task to be submitted
      Returns:
      the future of the task
    • wrapTask

      protected <T> Callable<T> wrapTask(Callable<T> task)
      Override this to customize how the background task is created.
      Type Parameters:
      T - the type of the Task
      Parameters:
      task - the Task to be wrapped
      Returns:
      the wrapped task
    • newTimeoutException

      private TimeoutException newTimeoutException(long timeout, TimeUnit unit, WaitForProcess task)
    • getUnitsAsString

      private static String getUnitsAsString(long d, TimeUnit unit)
    • getExitCodeOrNull

      private static Integer getExitCodeOrNull(Process process)
    • applyEnvironment

      private void applyEnvironment()
    • fixArguments

      private static List<String> fixArguments(List<String> command)
      Fixes the command line arguments on Windows by replacing empty arguments with "". Otherwise these arguments would be just skipped.