FileDocCategorySizeDatePackage
ProcessExecutor.javaAPI DocGlassfish v2 API22552Tue Jun 05 20:32:36 BST 2007com.sun.enterprise.util

ProcessExecutor

public class ProcessExecutor extends Object
author
Kedar
version
1.0

Fields Summary
public static final long
kDefaultTimeoutMillis
public static final long
kSleepTime
private static final long
DEFAULT_TIMEOUT_SEC
private static final String
NEWLINE
private long
mTimeoutMilliseconds
protected String[]
mCmdStrings
protected File
mOutFile
protected File
mErrFile
private OutputStream
mOutStream
private OutputStream
mErrStream
private File
mWorkingDir
private String[]
mEnv
private String[]
mInputLines
private int
mExitValue
private Process
mSubProcess
private boolean
mVerboseMode
private boolean
retainExecutionLogs
private String
lastExecutionOutputString
private String
lastExecutionErrorString
private static boolean
bDebug
Constructors Summary
public ProcessExecutor(String[] cmd)
Creates new ProcessExecutor


     		  	
	  
	
		this(cmd, DEFAULT_TIMEOUT_SEC, null);
	
public ProcessExecutor(String[] cmd, String[] inputLines)
Creates new ProcessExecutor

		this(cmd, DEFAULT_TIMEOUT_SEC, inputLines);
	
public ProcessExecutor(String[] cmd, long timeoutSeconds)
Creates new ProcessExecutor

		this(cmd, timeoutSeconds, null);
        
public ProcessExecutor(String[] cmd, long timeoutSeconds, String[] inputLines)

            this(cmd, timeoutSeconds, inputLines, null, null);
        
public ProcessExecutor(String[] cmd, long timeoutSeconds, String[] inputLines, String[] env, File workingDir)
Creates a new ProcessExecutor that executes the given command.

param
cmd String that has command name and its command line arguments
param
timeoutSeconds long integer timeout to be applied in seconds. After this time if the process to execute does not end, it will be destroyed.

            mCmdStrings				= cmd;
            mInputLines             = inputLines;
            mEnv                    = env;
            mWorkingDir             = workingDir;
            char fwdSlashChar       = '/";
            char backSlashChar      = '\\";
            
            if (System.getProperty("Debug") != null) {
                // turn on debug, this option was added to help developers
                // debug the their code
                bDebug=true;
            }                        
            
            for(int i=0; i<mCmdStrings.length; i++)
            {
                if (OS.isUnix())
                {
                    mCmdStrings[i] = mCmdStrings[i].replace(backSlashChar, fwdSlashChar);
                }
                else
                {
                    mCmdStrings[i] = mCmdStrings[i].replace(fwdSlashChar, backSlashChar);
                }
            }
            mTimeoutMilliseconds = (long) timeoutSeconds * 1000;
        
Methods Summary
private java.lang.Stringa2s(java.lang.String[] a)

		final StringBuffer s = new StringBuffer();
		if (a != null) {
			for (int i = 0 ; i < a.length ; i++) {
				s.append(a[i]);
				s.append(" ");
			}
		}
		return ( s.toString() );
	
private voidaddInputLinesToProcessInput(java.lang.Process subProcess)

	if(mInputLines==null)
            return;
        
        PrintWriter out = null;
        try 
        {
            out = new PrintWriter(new BufferedWriter(
                new OutputStreamWriter(subProcess.getOutputStream())));

            for(int i=0; i<mInputLines.length; i++)
            {
                if(bDebug) {
                    System.out.println("InputLine ->" + mInputLines[i] + "<-");
                }
                out.println(mInputLines[i]);
            }
            out.flush();
        }
        catch (Exception e)
        {
            throw new ExecException(e.getMessage());
        }
        finally
        {
            try
            {
                out.close();
            }
            catch (Throwable t)
            {
        }
        }
    
private static final java.lang.StringcannotCreateTempFiles()

	return "Could not create temporary files - check "
	+ System.getProperty("java.io.tmpdir")
	+ " to see if its writeable and not-full";
    
private booleandebug()

		final String td = System.getProperty("java.io.tmpdir");
		final String n = "as_debug_process_executor"; // a debug hook
		final File f = new File(td, n);
		return ( f.exists() );
	
private voiddeleteTempFiles()

        if (mOutStream != null) {
            try {
                mOutStream.flush();
                mOutStream.close();
            } catch (IOException ioe) {
                // Ignore
            }
        }
        
        if (mErrStream != null) {
            try {
                mErrStream.flush();
                mErrStream.close();
            } catch (IOException ioe) {
                // Ignore
            }
        }
	if (mOutFile != null) mOutFile.delete();
	if (mErrFile != null) mErrFile.delete();
    
public voidexecute()

        execute(false);
    
public java.lang.String[]execute(boolean bReturnOutputLines)

        return execute(bReturnOutputLines, true);
    
public java.lang.String[]execute(boolean bReturnOutputLines, boolean bStartUpTimeLimit)

            init();
            InputStream inputStream = null;
            try
            {
                
                if (bDebug) {
                    System.out.println("\n**** Executing command:");
                    for(int ii=0; ii < mCmdStrings.length; ii++) {
                        System.out.println(mCmdStrings[ii]);
                    }
                }
                
                mSubProcess = Runtime.getRuntime().exec(mCmdStrings, mEnv, mWorkingDir);
                if(mInputLines != null)
                    addInputLinesToProcessInput(mSubProcess);
                if(!bReturnOutputLines)
                    mOutStream = redirectProcessOutput(mSubProcess);
                else
                    inputStream = mSubProcess.getInputStream(); //attach to input stream for later reading
                mErrStream = redirectProcessError(mSubProcess);
                
                // see if process should startup in a limited ammount of time
                // processes used by ProcessManager don't return
                if (bStartUpTimeLimit) {
                    long	timeBefore = System.currentTimeMillis();
                    boolean timeoutReached		= false;
                    boolean isSubProcessFinished	= false;
                    boolean shouldBeDone		= false;
                    while (! shouldBeDone)
                    {
                        sleep(kSleepTime);
                        long timeAfter = System.currentTimeMillis();
                        timeoutReached = (timeAfter - timeBefore) >= mTimeoutMilliseconds;
                        try
                        {
                            mExitValue          	= mSubProcess.exitValue();
                            isSubProcessFinished	= true;
                        }
                        catch(IllegalThreadStateException itse)
                        {
                            isSubProcessFinished = false;
                            //ignore exception
                        }
                        shouldBeDone = timeoutReached || isSubProcessFinished;
                    }
                    if (!isSubProcessFinished)
                    {
                        mSubProcess.destroy();
                        mExitValue = -255;
                        throw new ExecException("Subprocess timed out after "+mTimeoutMilliseconds +"mS");
                    }
                    else
                    {
                        mExitValue = mSubProcess.exitValue();
                        if (debug()) {
                            System.out.println("Subprocess command line = " + a2s(mCmdStrings));
                            System.out.println("Subprocess exit value = " + mExitValue);
                        }
                        if (mExitValue != 0)
                        {
                            mExitValue = mSubProcess.exitValue();
                            if (mExitValue != 0)
                            {   
                                throw new ExecException(getExceptionMessage());
                            }
                        }
                    }
                }
            }
            catch(SecurityException se)
            {
                throw new ExecException(se.getMessage());
            }
            catch(IOException ioe)
            {
            	throw new ExecException(ioe.getMessage());
            }
            finally {

                // retain buffers before deleting them
                retainBuffers();

                // only delete files if the time is limited
                // for processes that don't return, the temp files will remain
                if (bStartUpTimeLimit) {
                    deleteTempFiles();
                }
            }

            if(bReturnOutputLines) {
                return getInputStrings(inputStream);
            } else {
                return null;
            }
            
        
protected java.lang.StringgetExceptionMessage()
Allows a subclass to control the error message returned when a non-zero exit code is returned from a failed execution

return

        /* read the error message from error file */
        String errorMessage = getFileBuffer(mErrFile);                                
        if (errorMessage.length() == 0) {
            errorMessage = "The Process Output: " + getLatestOutput(mOutFile);
        }
        return "abnormal subprocess termination: Detailed Message:" + errorMessage;
    
public booleangetExecutionRetentionFlag()

		return ( this.retainExecutionLogs );
	
protected java.lang.StringgetFileBuffer(java.io.File file)
Returns the contents of a file as a String. It never returns a null. If the file is empty, an empty string is returned.

param
file the file to read

        final StringBuffer sb = new StringBuffer();
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader(file));
            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
                sb.append(NEWLINE);
            }
        }
        catch(Exception e) {
            //squelch the exception
        }
        finally {
            try {
                reader.close();
            }
            catch(Exception e) {}
        }
        return ( sb.toString() );
    
private java.lang.String[]getInputStrings(java.io.InputStream inputStream)

		if(inputStream==null)
            return null;
        BufferedReader in = null;
        ArrayList list = new ArrayList();
        String    str;
        try
		{
			in = new BufferedReader( new InputStreamReader(inputStream));
			while((str=in.readLine())!=null)
                list.add(str);
            if(list.size()<1)
                return null;
            return (String[])list.toArray(new String[list.size()]); 
            
		}
		catch (Exception e)
		{
			throw new ExecException(e.getMessage());
		}
        finally
        {
            try
            {
                in.close();
            }
            catch (Throwable t)
            {
            }
        }
	
public java.lang.StringgetLastExecutionError()
Returns the last LAST_BYTES bytes in the error stream of last execution as a String, if the ProcessExecutor was configured properly. It may return null if the retentionFlag is set to false.

		return ( this.lastExecutionErrorString );
	
public java.lang.StringgetLastExecutionOutput()
Returns the last LAST_BYTES bytes in the output stream of last execution as a String, if the ProcessExecutor was configured properly. It may return null if the retentionFlag is set to false.

		return ( this.lastExecutionOutputString );
	
protected java.lang.StringgetLatestOutput(java.io.File f)

		return ( new RAFileReader(f).readLastBytesAsString() );
	
public intgetProcessExitValue()
Get the exit value of the process executed. If this method is called before process execution is complete (i.e. before execute() method has returned, it will return -1. If sub process is terminated at timeout, the method will return -255

        return mExitValue;
    
public java.lang.ProcessgetSubProcess()

        return mSubProcess;
    
private voidinit()

	  try{
		mOutFile = File.createTempFile("stdout", null);
		mOutFile.deleteOnExit();
		mErrFile = File.createTempFile("stderr", null);
		mErrFile.deleteOnExit();
	  }
	  catch (IllegalArgumentException iae){
		deleteTempFiles();
		throw new ExecException("Internal error (util.ProcessExecutor.init()): "+iae.getMessage());
	  }
	  catch (IOException ioe){
		deleteTempFiles();
		throw new ExecException(cannotCreateTempFiles());
	  }
	
public static voidmain(java.lang.String[] args)

        testProcessError();
    
private java.io.OutputStreamredirectProcessError(java.lang.Process subProcess)

                OutputStream out = null;
		try
		{
			InputStream		in	= subProcess.getErrorStream();
            // Redirect stderr for verbose mode
            if(mVerboseMode) {
                // send output to stderr
                out=System.err;
            } else {
                // send to temp file
                out=new FileOutputStream(mErrFile);
            }
			new FlusherThread(in, out).start();
		}
		catch (Exception e)
		{
			throw new ExecException(e.getMessage());
		}
                return out;
	
private java.io.OutputStreamredirectProcessOutput(java.lang.Process subProcess)

		OutputStream out = null;
                try
		{
			InputStream		in	= subProcess.getInputStream();
            // Redirect stderr for verbose mode
            if(mVerboseMode) {
                // send output to stderr
                out=System.err;
            } else {
                // send to temp file
                out=new FileOutputStream(mOutFile);
            }
            
			new FlusherThread(in, out).start();
		}
		catch (Exception e)
		{
			throw new ExecException(e.getMessage());
		}
                return out;
	
public voidretainBuffers()

		if (this.retainExecutionLogs) {
			this.lastExecutionErrorString	= this.getLatestOutput(this.mErrFile);
			this.lastExecutionOutputString	= this.getLatestOutput(this.mOutFile);
		}
	
public voidsetExecutionRetentionFlag(boolean s)
This is the setting after the fact that an instance of ProcessExecutor is created. This is to be used in case the output and error of the last execute call has to be retained for latter analysis.

param
s boolean representing whether to retain, true means the buffers will be retained, false otherwise.

		this.retainExecutionLogs = s;
	
public voidsetVerbose(boolean verbose)

        mVerboseMode=verbose;
    
private voidsleep(long millis)

		try
		{
			Thread.sleep(millis);
		}
		catch(InterruptedException ie)
		{
			//ignore exception
		}
	
private static voidtestProcessError()

        ProcessExecutor executor = new ProcessExecutor(
            new String[]{"/usr/bin/ls", "-wrongPARAMS123"});
        try {
            executor.execute();
        }
        catch (ExecException ee) {
            System.out.println(ee.getMessage());
        }