FileDocCategorySizeDatePackage
ProcessStreamDrainer.javaAPI DocGlassfish v2 API6681Fri May 04 22:32:14 BST 2007com.sun.enterprise.util.io

ProcessStreamDrainer

public class ProcessStreamDrainer extends Object
If you don't drain a process' stdout and stderr it will cause a deadlock after a few hundred bytes of output. At that point the Process is blocked because its stdout and/or stderr buffer is full and it is waiting for the Java caller to drain it. Meanwhile the Java program is blocked waiting on the external process. This class makes this common, but messy and tricky, procedure easier. It creates 2 threads that drain output on stdout and stderr of the external process.

Sample Code:

ProcessBuilder pb = new ProcessBuilder("ls", "-R", "c:/as");
try
{
Process p = pb.start();
ProcessStreamDrainer psd = ProcessStreamDrainer.drain("MyProcess", p);
// or
ProcessStreamDrainer psd = ProcessStreamDrainer.redirect("MyProcess", p);
psd.waitFor(); // this is optional.
}
catch (Exception ex)
{
ex.printStackTrace();
}
author
bnevins

Fields Summary
private final Process
process
private final Thread
errThread
private final Thread
outThread
private final String
processName
private final boolean
redirectStandardStreams
private static final String
ERROR_DRAINER
private static final String
OUT_DRAINER
Constructors Summary
private ProcessStreamDrainer(String processName, Process process, boolean redirect)

        if(process == null)
            throw new NullPointerException("Internal Error: null Process object");
        
        this.process = process;
        
        if(processName == null || processName.length() <= 0)
            this.processName = "UnknownProcessName";
        else
            this.processName = processName;
        
        redirectStandardStreams = redirect;

        ProcessStreamDrainerWorker worker;
        
        if(redirectStandardStreams)
            worker = new ProcessStreamDrainerWorker(process.getInputStream(), System.out);
        else
            worker = new ProcessStreamDrainerWorker(process.getInputStream());

        outThread = new Thread(worker, processName + "-" + OUT_DRAINER);
        outThread.setDaemon(true);
        
        if(redirectStandardStreams)
            worker = new ProcessStreamDrainerWorker(process.getErrorStream(), System.err);
        else
            worker = new ProcessStreamDrainerWorker(process.getErrorStream());
        
        errThread = new Thread(worker, processName + "-" + ERROR_DRAINER);
        errThread.setDaemon(true);
    
Methods Summary
public static com.sun.enterprise.util.io.ProcessStreamDrainerdrain(java.lang.String processName, java.lang.Process process)
Create an instance and drain the process' stderr and stdout

param
process The Process to drain
param
processName The name will be used to name the drainer threads

        ProcessStreamDrainer psd = new ProcessStreamDrainer(processName, process, false);
        psd.drain();
        return psd;
    
private voiddrain()
Start the draining. We start them here instead of the constructor so that "this" doesn't leak out of the constructor.

        outThread.start();
        errThread.start();
    
public static com.sun.enterprise.util.io.ProcessStreamDrainerredirect(java.lang.String processName, java.lang.Process process)
Create an instance, drain and redirect the process' stderr and stdout to System.err and System.out respectively.

param
process The Process to drain
param
processName The name will be used to name the drainer threads

        ProcessStreamDrainer psd = new ProcessStreamDrainer(processName, process, true);
        psd.drain();
        return psd;
    
public final voidwaitFor()
Wait for the drain threads to die. This is guaranteed to occur after the external process dies. Note that this may, of course, block indefinitely.

        errThread.join();
        outThread.join();