public class ProcessRunner
extends java.lang.Thread
Process
and consume data written to its native process'
standard output and standard error streams.
The native process must correctly die and not leave child processes running attached to the standard output and standard error streams.
This can be problematic, especially for shells. For example, the command
sh -c 'sleep 5' would not be good because some sh
implementations would start a second native process: sleep. If
the Process
is destroyed (i.e. killed), only the sh
native process would be killed; the sleep native process would
remain running. This will make ProcessRunner
unable to correctly
respond to being interrupted because the standard output and standard
error streams did not get closed when it destroyed the Process
(which killed the sh native process, but not the sleep
native process). Hence the standard output and standard error streams
will remain open since the sleep native process is attached to
them, and the standard output and standard error consumers will remain
blocked reading their streams and not die.
Better would be sh -c 'exec sleep 5' so that there is only one
native process (sleep which replaced sh), and when
Process
is destroyed, sleep will be killed and its
standard output and standard error streams will be closed, and the
standard output and standard error consumers will die.
An alternative approach would be to ensure the child process detaches
from the standard streams of its parent; this way the child process will
continue to run, but the standard streams of its parent will be closed
when the Process
is destroyed, and the standard output and
standard error consumers will die.
Examples
Here's how to run the uptime program by creating and starting an instance of me:
ProcessBuilder builder = new ProcessBuilder("uptime"); ProcessRunner runner = new ProcessRunner(builder); try { runner.start(); runner.join(); } finally { runner.interrupt(); } ProcessRunnerResult result = runner.result();
Here's how to run the same uptime program using one of my static convenience methods:
ProcessBuilder builder = new ProcessBuilder("uptime"); ProcessRunnerResult result = ProcessRunner.run(builder);
Here's how to run the same uptime program reading its standard output into an 80 byte fixed-size buffer:
ProcessBuilder builder = new ProcessBuilder("uptime"); InputStreamConsumer consumer = new FixedSizeBufferInputStreamConsumer(80); ProcessRunnerResult result = ProcessRunner.run(builder, consumer);
Constructor and Description |
---|
ProcessRunner(java.lang.ProcessBuilder builder)
Creates an instance with the specified builder.
|
ProcessRunner(java.lang.ProcessBuilder builder,
java.lang.String name)
Creates an instance with the specified builder and thread name.
|
ProcessRunner(java.lang.ProcessBuilder builder,
java.lang.ThreadGroup group,
java.lang.String name)
Creates an instance with the specified builder, thread group, and
thread name.
|
ProcessRunner(java.lang.ProcessBuilder builder,
java.lang.ThreadGroup group,
java.lang.String name,
long stackSize)
Creates an instance with the specified builder, thread group, thread
name, and thread stack size.
|
Modifier and Type | Method and Description |
---|---|
ProcessRunnerResult |
result()
Returns the result of running the process.
|
void |
run() |
static ProcessRunnerResult |
run(java.lang.ProcessBuilder builder)
Creates and runs a
ProcessRunner with the specified builder,
and with the default standard-output consumer and standard-error
consumer. |
static ProcessRunnerResult |
run(java.lang.ProcessBuilder builder,
InputStreamConsumer stdoutConsumer)
Creates and runs a
ProcessRunner with the specified builder and
standard-output consumer, and with the default standard-error consumer. |
static ProcessRunnerResult |
run(java.lang.ProcessBuilder builder,
InputStreamConsumer stdoutConsumer,
InputStreamConsumer stderrConsumer)
Creates and runs a
ProcessRunner with the specified builder,
standard-output consumer, and standard-error consumer. |
static ProcessRunnerResult |
run(java.lang.ProcessBuilder builder,
InputStreamConsumer stdoutConsumer,
InputStreamConsumer stderrConsumer,
long timeout)
Creates and runs a
ProcessRunner with the specified builder,
standard-output consumer, standard-error consumer, and timeout. |
InputStreamConsumer |
stderrConsumer()
Returns the standard-error stream consumer.
|
void |
stderrConsumer(InputStreamConsumer newConsumer)
Sets the standard-error stream consumer.
|
InputStreamConsumer |
stdoutConsumer()
Returns the standard-output stream consumer.
|
void |
stdoutConsumer(InputStreamConsumer newConsumer)
Sets the standard-output stream consumer.
|
activeCount, checkAccess, clone, countStackFrames, currentThread, destroy, dumpStack, enumerate, getAllStackTraces, getContextClassLoader, getDefaultUncaughtExceptionHandler, getId, getName, getPriority, getStackTrace, getState, getThreadGroup, getUncaughtExceptionHandler, holdsLock, interrupt, interrupted, isAlive, isDaemon, isInterrupted, join, join, join, resume, setContextClassLoader, setDaemon, setDefaultUncaughtExceptionHandler, setName, setPriority, setUncaughtExceptionHandler, sleep, sleep, start, stop, stop, suspend, toString, yield
public ProcessRunner(java.lang.ProcessBuilder builder)
super()
.builder
- used to start the process when I runpublic ProcessRunner(java.lang.ProcessBuilder builder, java.lang.String name)
super(name)
.builder
- used to start the process when I runname
- thread namepublic ProcessRunner(java.lang.ProcessBuilder builder, java.lang.ThreadGroup group, java.lang.String name)
super(group, name)
.builder
- used to start the process when I rungroup
- thread groupname
- thread namepublic ProcessRunner(java.lang.ProcessBuilder builder, java.lang.ThreadGroup group, java.lang.String name, long stackSize)
super(group, null, name, stackSize)
.builder
- used to start the process when I rungroup
- thread groupname
- thread namestackSize
- thread stack sizepublic InputStreamConsumer stdoutConsumer()
It is only safe to invoke this method before I have been started.
null
if the default
consumer is to be usedpublic void stdoutConsumer(InputStreamConsumer newConsumer)
It is only safe to invoke this method before I have been started.
newConsumer
- consumer to use as the standard-output consumer or
null
to use the default consumerstdoutConsumer()
public InputStreamConsumer stderrConsumer()
It is only safe to invoke this method before I have been started.
null
if the default consumer
is to be usedpublic void stderrConsumer(InputStreamConsumer newConsumer)
It is only safe to invoke this method before I have been started.
newConsumer
- consumer to use as the standard-error consumer or
null
to use a default consumerstderrConsumer()
public void run()
run
in interface java.lang.Runnable
run
in class java.lang.Thread
public ProcessRunnerResult result()
This method can be called safely from another thread only after
ensuring all my actions happen-before the action of calling this
method from the other thread. This is the Java memory model
happens-before relationship. For example, after I have been
started, it would be safe to call this method from another thread after
it called my join
method.
public static ProcessRunnerResult run(java.lang.ProcessBuilder builder) throws java.lang.InterruptedException
ProcessRunner
with the specified builder,
and with the default standard-output consumer and standard-error
consumer.builder
- used by the ProcessRunner
instance to start the
processProcessRunner
instancejava.lang.InterruptedException
- if the current thread is interrupted while
waiting for the ProcessRunner
to finishpublic static ProcessRunnerResult run(java.lang.ProcessBuilder builder, InputStreamConsumer stdoutConsumer) throws java.lang.InterruptedException
ProcessRunner
with the specified builder and
standard-output consumer, and with the default standard-error consumer.builder
- used by the ProcessRunner
instance to start the
processstdoutConsumer
- consumer to use as the standard-output consumer
or null
to use the default consumerProcessRunner
instancejava.lang.InterruptedException
- if the current thread is interrupted while
waiting for the ProcessRunner
to finishpublic static ProcessRunnerResult run(java.lang.ProcessBuilder builder, InputStreamConsumer stdoutConsumer, InputStreamConsumer stderrConsumer) throws java.lang.InterruptedException
ProcessRunner
with the specified builder,
standard-output consumer, and standard-error consumer.builder
- used by the ProcessRunner
instance to start the
processstdoutConsumer
- consumer to use as the standard-output consumer
or null
to use the default consumerstderrConsumer
- consumer to use as the standard-error consumer or
null
to use the default consumerProcessRunner
instancejava.lang.InterruptedException
- if the current thread is interrupted while
waiting for the ProcessRunner
to finishpublic static ProcessRunnerResult run(java.lang.ProcessBuilder builder, InputStreamConsumer stdoutConsumer, InputStreamConsumer stderrConsumer, long timeout) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException
ProcessRunner
with the specified builder,
standard-output consumer, standard-error consumer, and timeout.builder
- used by the ProcessRunner
instance to start the
processstdoutConsumer
- consumer to use as the standard-output consumer
or null
to use the default consumerstderrConsumer
- consumer to use as the standard-error consumer or
null
to use the default consumertimeout
- timeout in milliseconds to wait for
ProcessRunner
to complete; 0 means wait foreverProcessRunner
instancejava.lang.InterruptedException
- if the current thread is interrupted while
waiting for the ProcessRunner
to finishjava.util.concurrent.TimeoutException
- if the ProcessRunner
has not finished
running within the specified timeout