Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 02/14/2006
*
* ProcessRunner.java - Runs an external process as safely as possible.
* This code is a modified form of the following JavaWorld article:
* http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps_p.html
*
* This class is public domain. Use however you see fit.
*/
package org.fife.io;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Runs an external process (a program, batch file, shell script, etc.)
* as safely as possible.
*
* @author Robert Futrell
* @version 1.0
*/
public class ProcessRunner implements Runnable {
private File dir;
private String[] commandLine;
private Map envVars;
private boolean appendEnv;
private String stdout;
private String stderr;
private ProcessRunnerOutputListener outputListener;
private int rc;
private Throwable lastError;
/**
* Constructor.
*
* @param commandLine The command line to run, with each item in the
* array being a single parameter.
* @throws IllegalArgumentException If commandLine has
* length 0.
* @throws NullPointerException If commandLine is
* null.
*/
public ProcessRunner(String[] commandLine) {
setCommandLine(commandLine);
appendEnv = true;
}
/**
* Clears the stdout and stderr variables.
*/
private void clearLastOutput() {
stdout = stderr = null;
rc = Integer.MIN_VALUE;
lastError = null;
}
/**
* Creates an array of "name=value" elements, suitable for
* Runtime.getRuntime().exec().
*
* @return The array of environment variables.
*/
private String[] createEnvVarArray() {
Map env = new HashMap();
// If we want to append our environment to that of the parent process...
if (appendEnv) {
// This class works with Java 1.4+, but System.getenv() was only
// added in Java 5, so we take extra care here.
Class clazz = System.class;
try {
Method getenv = clazz.getMethod("getenv", null);
Map parentEnv = (Map)getenv.invoke(clazz, null);
env.putAll(parentEnv);
} catch (NoSuchMethodException nsme) { // Java 1.4
getEnvironmentNative(env);
} catch (RuntimeException re) {
throw re;
} catch (Exception e) {
e.printStackTrace();
getEnvironmentNative(env); // Fallback
}
}
// If we have any environment variables to append...
if (this.envVars!=null) {
env.putAll(this.envVars);
}
// Create an array of "name=value" elements.
List temp = new ArrayList(env.size());
for (Iterator i=env.entrySet().iterator(); i.hasNext(); ) {
Map.Entry entry = (Map.Entry)i.next();
temp.add(entry.getKey() + "=" + entry.getValue());
}
String[] envp = new String[temp.size()];
envp = (String[])temp.toArray(envp);
return envp;
}
/**
* Returns whether any extra environment variables defined for this process
* to run with should be appended to the parent process's environment (as
* opposed to overwriting it).
*
* @return Whether to append the parent process's environment.
* @see #getEnvironmentVars()
* @see #setEnvironmentVars(Map, boolean)
*/
public boolean getAppendEnvironmentVars() {
return appendEnv;
}
/**
* Returns the command line this external process runner will run as a
* string. Parameters are wrapped in quotes.
*
* @return The command line this object will run.
* @see #setCommandLine(String[])
*/
public String getCommandLineString() {
int count = commandLine.length;
StringBuffer sb = new StringBuffer();
for (int i=0; inull, then the process will run in the same
* directory as this Java process.
* @see #setDirectory(File)
*/
public File getDirectory() {
return dir;
}
/**
* Uses "cmd /c set" on Windows and
* "/bin/sh -c env" on *nix to determine the current
* environment. This method is used when an application is running in a
* 1.4 JVM, meaning System.getenv() is not available.
*
* @param env The map to append the environment variables to.
*/
private void getEnvironmentNative(Map env) {
String command = File.separatorChar=='\\' ?
"cmd /c set" : "/bin/sh -c env";
Process p = null;
StreamReaderThread stdoutThread = null;
Thread stderrThread = null;
String vars = null;
try {
p = Runtime.getRuntime().exec(command);
// Create threads to read the stdout and stderr of the external
// process. If we do not do it this way, the process may
// deadlock.
InputStream errStream = p.getErrorStream();
InputStream outStream = p.getInputStream();
stdoutThread = new StreamReaderThread(p, outStream, null, true);
stderrThread = new StreamReaderThread(p, errStream, null, false);
stdoutThread.start();
stderrThread.start();
rc = p.waitFor();
p = null;
// Don't interrupt reader threads;
// just wait for them to terminate normally.
//stdoutThread.interrupt();
//stderrThread.interrupt();
stdoutThread.join();
stderrThread.join();
vars = stdoutThread.getStreamOutput();
} catch (IOException ioe) {
ioe.printStackTrace();
// IOE can only happen in Runtime.exec(), so stdoutThread and
// stderrThread are always null if we get here
//stdoutThread.interrupt();
//stderrThread.interrupt();
} catch (InterruptedException ie) {
ie.printStackTrace();
if (stdoutThread!=null) {
stdoutThread.interrupt();
}
if (stderrThread!=null) {
stderrThread.interrupt();
}
} finally {
if (p!=null) {
p.destroy();
}
}
// Parse the stdout for name/value pairs.
if (vars!=null) {
BufferedReader r = new BufferedReader(new StringReader(vars));
String line = null;
try {
while ((line=r.readLine())!=null) {
int split = line.indexOf('=');
if (split>-1) { // Should always be true
String name = line.substring(0, split);
String value = line.substring(split+1);
//System.out.println("Adding var: " + name + " => " + value);
env.put(name, value);
}
}
r.close();
} catch (IOException ioe) {
ioe.printStackTrace(); // Never happens
}
}
}
/**
* Returns any extra environment variables defined for this process to run
* with.
*
* @return The environment variables.
* @see #getAppendEnvironmentVars()
* @see #setEnvironmentVars(Map, boolean)
*/
public Map getEnvironmentVars() {
Map temp = new HashMap();
if (envVars!=null) {
temp.putAll(envVars);
}
return temp;
}
/**
* Returns the last error thrown when trying to run a process, or
* null if the last process ran successfully.
*
* @return The error that the last-run process ended with, if any.
*/
public Throwable getLastError() {
return lastError;
}
/**
* Returns the return code of the last process ran.
*
* @return The return code of the last process ran.
*/
public int getReturnCode() {
return rc;
}
/**
* Returns the stderr of the process last ran.
*
* @return The stderr of the last process ran.
*/
public String getStderr() {
return stderr;
}
/**
* Returns the stdout of the process last ran.
*
* @return The stdout of the last process ran.
*/
public String getStdout() {
return stdout;
}
/**
* Runs the current external process.
*
* @throws IOException If an I/O error occurs while running the process.
* @see #getStdout()
* @see #getStderr()
*/
public void run() {
clearLastOutput(); // In case we throw an exception, clear output.
Process proc = null;
StreamReaderThread stdoutThread = null;
StreamReaderThread stderrThread = null;
try {
String[] envp = createEnvVarArray();
proc = Runtime.getRuntime().exec(commandLine, envp, dir);
// Create threads to read the stdout and stderr of the external
// process. If we do not do it this way, the process may
// deadlock.
InputStream errStream = proc.getErrorStream();
InputStream outStream = proc.getInputStream();
stdoutThread = new StreamReaderThread(proc, outStream,
outputListener, true);
stderrThread = new StreamReaderThread(proc, errStream,
outputListener, false);
stdoutThread.start();
stderrThread.start();
rc = proc.waitFor();
proc = null;
// Save the stdout and stderr. Don't interrupt reader threads;
// just wait for them to terminate normally.
//stdoutThread.interrupt();
//stderrThread.interrupt();
stdoutThread.join();
stderrThread.join();
stdout = stdoutThread.getStreamOutput();
stderr = stderrThread.getStreamOutput();
} catch (IOException ioe) {
ioe.printStackTrace();
// IOE can only happen in Runtime.exec(), so stdoutThread and
// stderrThread are always null if we get here
//stdoutThread.interrupt();
//stderrThread.interrupt();
lastError = ioe;
// TODO: ???
} catch (InterruptedException ie) {
//ie.printStackTrace();
if (stdoutThread!=null) {
stdoutThread.interrupt();
}
if (stderrThread!=null) {
stderrThread.interrupt();
}
lastError = ie;
// TODO: ???
} finally {
if (proc!=null) {
proc.destroy();
}
}
if (outputListener!=null) {
outputListener.processCompleted(proc, rc, lastError);
}
}
/**
* Sets the directory to run the process in.
*
* @param dir The directory.
* @see #getDirectory()
*/
public void setDirectory(File dir) {
this.dir = dir;
}
/**
* Sets the command line of the process to run.
*
* @param commandLine The command line parameters to run.
* @throws IllegalArgumentException If commandLine has
* length 0.
* @throws NullPointerException If commandLine is
* null.
* @see #getCommandLineString()
*/
public void setCommandLine(String[] commandLine)
throws IllegalArgumentException {
int size = commandLine.length;
if (size==0) {
throw new IllegalArgumentException(
"Must have at least 1 command line argument");
}
this.commandLine = new String[size];
System.arraycopy(commandLine,0, this.commandLine,0, size);
clearLastOutput(); // No output from this new command line yet.
}
/**
* Sets the environment variables to be set for this process.
*
* @param vars The environment variables. This may be null if
* none are to be set.
* @param append Whether this should be appended to the parent process's
* environment. If this is false, then the contents of
* vars will be the only environment variables set.
* @see #getEnvironmentVars()
*/
public void setEnvironmentVars(Map vars, boolean append) {
appendEnv = append;
if (envVars!=null) {
envVars.clear();
}
else {
envVars = new HashMap();
}
envVars.putAll(vars);
}
/**
* Sets the output listener to receive notification when stdout or
* stderr is written to. This listener will be used for all
* subsequent processes run with this ProcessRunner.
*
* @param listener The new listener. The previous listener, if any,
* will be removed. If this is null, there
* will be no output listener.
*/
public void setOutputListener(ProcessRunnerOutputListener listener) {
this.outputListener = listener;
}
/**
* A thread dedicated to reading either the stdout or stderr stream of
* an external process. These streams are read in a dedicated thread
* to ensure they are consumed appropriately to prevent deadlock. This
* idea was taken from
*
* this JavaWorld article.
*
* @author Robert Futrell
*/
static class StreamReaderThread extends Thread {
private Process p;
private BufferedReader r;
private StringBuffer buffer;
private ProcessRunnerOutputListener listener;
private boolean isStdout;
/**
* Constructor.
*
* @param p The running process.
* @param in The stream (stdout or stderr) to read from.
* @param listener A listener to send notification to as
* output is read. This can be null.
* @param isStdout Whether this thread is reading stdout (as
* opposed to stderr).
*/
public StreamReaderThread(Process p, InputStream in,
ProcessRunnerOutputListener listener,
boolean isStdout) {
this.p = p;
r = new BufferedReader(new InputStreamReader(in));
this.buffer = new StringBuffer();
this.listener = listener;
this.isStdout = isStdout;
}
/**
* Returns the output read from the stream.
*
* @return The stream's output, as a String.
*/
public String getStreamOutput() {
return buffer.toString();
}
/**
* Continually reads from the output stream until this thread is
* interrupted.
*/
public void run() {
String line;
try {
while ((line=r.readLine())!=null) {
buffer.append(line).append('\n');
if (listener!=null) {
listener.outputWritten(p, line, isStdout);
}
}
} catch (IOException ioe) {
buffer.append("IOException occurred: " + ioe.getMessage());
}
}
}
}