office-gobmx/qadevOOo/runner/helper/ProcessHandler.java

398 lines
No EOL
12 KiB
Java

/*************************************************************************
*
* $RCSfile: ProcessHandler.java,v $
*
* $Revision: 1.2 $
*
* last change: $Date: 2003-05-15 18:04:04 $
*
* The Contents of this file are made available subject to the terms of
* either of the following licenses
*
* - GNU Lesser General Public License Version 2.1
* - Sun Industry Standards Source License Version 1.1
*
* Sun Microsystems Inc., October, 2000
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2000 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*
* Sun Industry Standards Source License Version 1.1
* =================================================
* The contents of this file are subject to the Sun Industry Standards
* Source License Version 1.1 (the "License"); You may not use this file
* except in compliance with the License. You may obtain a copy of the
* License at http://www.openoffice.org/license.html.
*
* Software provided under this License is provided on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
* See the License for the specific provisions governing your rights and
* obligations concerning the Software.
*
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
*
* Copyright: 2000 by Sun Microsystems, Inc.
*
* All Rights Reserved.
*
* Contributor(s): _______________________________________
*
*
************************************************************************/
package helper;
import java.io.InputStream;
import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.io.PrintWriter;
import java.io.PrintStream;
import java.io.LineNumberReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
/**
* Class collect information from input stream in
* background (sparate thread) and outputs it to
* some log stream. I helps to avoid buffer overflow
* when output stream has small buffer size (e.g.
* in case when handling stdout from external
* <code>Process</code>)
*
* This class is currently used by ProcesHandler
* internally only.
*/
class Pump extends Thread {
private LineNumberReader reader;
private String pref ;
private Pump thread ;
private StringBuffer buf = new StringBuffer(256);
private PrintWriter log ;
/**
* Creates Pump for specified <code>InputStream</code>.
* This Pump also synchronously output text read to
* log by prefixed lines. Constructor immediately
* starts reading in a separate thread.
*
* @param is Stream which requires permanent reading.
* @param log Writer where prefixed text lines to be output
* @param outPrefix A prefix which is printed at the
* beginning of each output line.
*/
public Pump(InputStream is, PrintWriter log, String outPrefix) {
this.pref = outPrefix == null ? "" : outPrefix ;
reader = new LineNumberReader(new InputStreamReader(is));
this.log = log ;
start() ;
}
public void run() {
try {
String line = reader.readLine() ;
while (line != null) {
log.println(pref + line);
log.flush();
buf.append(line).append('\n');
line = reader.readLine() ;
}
} catch (java.io.IOException e) {
log.println(pref + "Exception occured: " + e) ;
}
}
/**
* Returns the text collected from input stream.
*/
public String getStringBuffer() {
return buf.toString();
}
}
/**
* Class provides convenient way for running external program
* handle its standard streams, control execution and check results.
* Instance of this class must be created only for a single
* execution. If you need to execute the same command again you
* should create a new instance for this.
*/
public class ProcessHandler {
private String cmdLine;
private String[] envVars = null;
private File workDir = null;
private PrintWriter log;
private int exitValue = -1;
private boolean isFinished = false;
private boolean isStarted = false;
private String stdInBuff = "";
private Pump stdout = null ;
private Pump stderr = null ;
private PrintStream stdIn = null ;
private Process proc = null ;
/**
* Creates instance with specified external command and
* log stream where debug info is printed and output
* of external command.
*/
public ProcessHandler(String cmdLine, PrintWriter log) {
this(cmdLine, log, null, null);
}
/**
* Creates instance with specified external command.
* Debug info and output
* of external commandis printed to stdout.
*/
public ProcessHandler(String cmdLine) {
this(cmdLine, null, null, null);
}
/**
* Creates instance with specified external command which
* will be executed in the some work directory and
* log stream where debug info and output
* of external command is printed .
* The specified environment variables are set for the new process.
* If log stream is null, logging is printed to stdout.
*/
public ProcessHandler(String cmdLine, PrintWriter log,
File workDir, String[] envVars) {
this.cmdLine = cmdLine ;
this.workDir = workDir;
this.log = log;
this.cmdLine = cmdLine ;
this.envVars = envVars;
if (log == null)
this.log = new PrintWriter(new OutputStreamWriter(System.out));
else
this.log = log;
}
/**
* Creates instance with specified external command which
* will be executed in the some work directory.
* Debug info and output
* of external commandis printed to stdout.
*/
public ProcessHandler(String cmdLine, File workDir) {
this(cmdLine, null, workDir, null);
}
/**
* Executes the command and returns only when the process
* exits.
*
* @return <code>true</code> if process was successfully
* started and correcly exits (exit code doesn't affect
* to this result).
*/
public boolean executeSynchronously() {
execute() ;
return waitFor() ;
}
/**
* Executes the command immediately returns. The process
* remains in running state. Control of its state should
* be made by <code>waitFor</code> methods.
*
* @return <code>true</code> if process was successfully
* started.
*/
public boolean executeAsynchronously() {
execute() ;
return isStarted() ;
}
public void kill() {
if (!isStarted()) return;
proc.destroy();
isStarted = false;
}
protected void execute() {
if (isStarted()) {
throw new RuntimeException(
"The process handler has already been executed.") ;
}
Runtime runtime = Runtime.getRuntime() ;
try {
log.println("Starting command: " + cmdLine) ;
if (workDir != null) {
proc = runtime.exec(cmdLine, envVars, workDir) ;
} else {
proc = runtime.exec(cmdLine, envVars) ;
}
isStarted = true ;
} catch (java.io.IOException e) {
log.println("The command "+cmdLine+" can't be started: " + e.getMessage());
e.printStackTrace((PrintWriter) log);
return;
}
stdout = new Pump(proc.getInputStream(), log, "out > ");
stderr = new Pump(proc.getErrorStream(), log, "err > ");
stdIn = new PrintStream(proc.getOutputStream()) ;
flushInput() ;
}
/**
* This method is useful when the process was executed
* asynchronously. Waits for process to exit and return
* its result.
*
* @return <code>true</code> if process correctly exited
* (exit code doesn't affect to this result).
*/
public boolean waitFor() {
return waitFor(0) ;
}
/**
* This method is useful when the process was executed
* asynchronously. Waits during specified time for process
* to exit and return its status.
*
* @return <code>true</code> if process correctly exited
* (exit code doesn't affect to this result).
*/
public boolean waitFor(long timeout) {
if (isFinished()) return true ;
if (!isStarted()) return false ;
if (timeout == 0) {
try {
proc.waitFor() ;
} catch (InterruptedException e) {
log.println("The process was interrupted: " + e);
}
isFinished = true ;
try {
exitValue = proc.exitValue() ;
} catch (IllegalThreadStateException e) {}
} else {
try {
while (!isFinished && timeout > 0) {
isFinished = true ;
Thread.sleep(1000);
timeout -= 1000 ;
try {
exitValue = proc.exitValue() ;
} catch (IllegalThreadStateException e) {
isFinished = false ;
}
}
} catch (InterruptedException ex) {
log.println("The process was interrupted: " + ex);
}
}
if (!isFinished) {
proc.destroy();
}
try {
stdout.join();
stderr.join();
} catch (InterruptedException e) {}
return isFinished() ;
}
protected void flushInput() {
if (stdIn == null) return ;
synchronized(stdInBuff) {
stdIn.print(stdInBuff);
stdIn.flush();
stdInBuff = "" ;
}
}
/**
* Returns the text output by external command to stdout.
*/
public String getOutputText() {
if(stdout == null)
return "";
else
return stdout.getStringBuffer();
}
/**
* Returns the text output by external command to stderr.
*/
public String getErrorText() {
if(stderr == null)
return "";
else
return stderr.getStringBuffer();
}
/**
* Prints the string specified to sdtin of external
* command. '\n' is not added so if you need you
* should terminate the string with '\n'. <p>
*
* The method can also be called before the command
* starts its execution. Then the text is buffered
* and transfered to command when it will be started.
*/
public void printInputText(String str) {
stdInBuff += str ;
flushInput();
}
/**
* Returns information about was the command started or
* not.
*
* @return <code>true</code> if the external command was
* found and successfully started.
*/
public boolean isStarted() {
return isStarted ;
}
/**
* Returns the information about the final state of command
* execution.
*
* @return <code>true</code> if the command correctly starts,
* exits and was not interrupted due to timeout.
*/
public boolean isFinished() {
return isFinished ;
}
/**
* Returns exit code of the external command.
*
* @return exit code of command if it was finished,
* -1 if not.
*/
public int getExitCode() {
return exitValue ;
}
}