blob: e5e89b44d9bcb17fca56f93a378c28cd9173c9e7 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.oodt.commons.exec;
//JDK imports
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
/**
* <p>
* This class is taken from Stephen Ostermiller's example at:
* http://ostermiller.org/utils/ExecHelper.java.html
*
* It provides some useful methods for manipulating and reading in the output of
* a {@link Process} resultant from a call to {@link Runtime#getRuntime()}
* without using the {@link Process#waitFor()} method, which apparently can hang
* on certain underlying systems.
* </p>
*
* @author mattmann
*
*/
public final class ExecHelper {
/**
* Executes the specified command and arguments in a separate process, and
* waits for the process to finish.
* <p>
* Output from the process is expected to be text in the system's default
* character set.
* <p>
* No input is passed to the process on STDIN.
*
* @param cmdarray
* array containing the command to call and its arguments.
* @return The results of the execution in an ExecHelper object.
* @throws SecurityException
* if a security manager exists and its checkExec method doesn't
* allow creation of a subprocess.
* @throws IOException -
* if an I/O error occurs
* @throws NullPointerException -
* if cmdarray is null
* @throws IndexOutOfBoundsException -
* if cmdarray is an empty array (has length 0).
*
*
*/
public static ExecHelper exec(String[] cmdarray) throws IOException {
return new ExecHelper(Runtime.getRuntime().exec(cmdarray), null);
}
/**
* Executes the specified command and arguments in a separate process, and
* waits for the process to finish.
* <p>
* Output from the process is expected to be text in the system's default
* character set.
* <p>
* No input is passed to the process on STDIN.
*
* @param cmdarray
* array containing the command to call and its arguments.
* @param envp
* array of strings, each element of which has environment
* variable settings in format name=value.
* @return The results of the execution in an ExecHelper object.
* @throws SecurityException
* if a security manager exists and its checkExec method doesn't
* allow creation of a subprocess.
* @throws IOException -
* if an I/O error occurs
* @throws NullPointerException -
* if cmdarray is null
* @throws IndexOutOfBoundsException -
* if cmdarray is an empty array (has length 0).
*
*
*/
public static ExecHelper exec(String[] cmdarray, String[] envp)
throws IOException {
return new ExecHelper(Runtime.getRuntime().exec(cmdarray, envp), null);
}
/**
* Executes the specified command and arguments in a separate process, and
* waits for the process to finish.
* <p>
* Output from the process is expected to be text in the system's default
* character set.
* <p>
* No input is passed to the process on STDIN.
*
* @param cmdarray
* array containing the command to call and its arguments.
* @param envp
* array of strings, each element of which has environment
* variable settings in format name=value.
* @param dir
* the working directory of the subprocess, or null if the
* subprocess should inherit the working directory of the current
* process.
* @return The results of the execution in an ExecHelper object.
* @throws SecurityException
* if a security manager exists and its checkExec method doesn't
* allow creation of a subprocess.
* @throws IOException -
* if an I/O error occurs
* @throws NullPointerException -
* if cmdarray is null
* @throws IndexOutOfBoundsException -
* if cmdarray is an empty array (has length 0).
*
*
*/
public static ExecHelper exec(String[] cmdarray, String[] envp, File dir)
throws IOException {
return new ExecHelper(Runtime.getRuntime().exec(cmdarray, envp, dir),
null);
}
/**
* Executes the specified command and arguments in a separate process, and
* waits for the process to finish.
* <p>
* No input is passed to the process on STDIN.
*
* @param cmdarray
* array containing the command to call and its arguments.
* @param charset
* Output from the executed command is expected to be in this
* character set.
* @return The results of the execution in an ExecHelper object.
* @throws SecurityException
* if a security manager exists and its checkExec method doesn't
* allow creation of a subprocess.
* @throws IOException -
* if an I/O error occurs
* @throws NullPointerException -
* if cmdarray is null
* @throws IndexOutOfBoundsException -
* if cmdarray is an empty array (has length 0).
*
*
*/
public static ExecHelper exec(String[] cmdarray, String charset)
throws IOException {
return new ExecHelper(Runtime.getRuntime().exec(cmdarray), charset);
}
/**
* Executes the specified command and arguments in a separate process, and
* waits for the process to finish.
* <p>
* No input is passed to the process on STDIN.
*
* @param cmdarray
* array containing the command to call and its arguments.
* @param envp
* array of strings, each element of which has environment
* variable settings in format name=value.
* @param charset
* Output from the executed command is expected to be in this
* character set.
* @return The results of the execution in an ExecHelper object.
* @throws SecurityException
* if a security manager exists and its checkExec method doesn't
* allow creation of a subprocess.
* @throws IOException -
* if an I/O error occurs
* @throws NullPointerException -
* if cmdarray is null
* @throws IndexOutOfBoundsException -
* if cmdarray is an empty array (has length 0).
*
*
*/
public static ExecHelper exec(String[] cmdarray, String[] envp,
String charset) throws IOException {
return new ExecHelper(Runtime.getRuntime().exec(cmdarray, envp),
charset);
}
/**
* Executes the specified command and arguments in a separate process, and
* waits for the process to finish.
* <p>
* No input is passed to the process on STDIN.
*
* @param cmdarray
* array containing the command to call and its arguments.
* @param envp
* array of strings, each element of which has environment
* variable settings in format name=value.
* @param dir
* the working directory of the subprocess, or null if the
* subprocess should inherit the working directory of the current
* process.
* @param charset
* Output from the executed command is expected to be in this
* character set.
* @return The results of the execution in an ExecHelper object.
* @throws SecurityException
* if a security manager exists and its checkExec method doesn't
* allow creation of a subprocess.
* @throws IOException -
* if an I/O error occurs
* @throws NullPointerException -
* if cmdarray is null
* @throws IndexOutOfBoundsException -
* if cmdarray is an empty array (has length 0).
*
*
*/
public static ExecHelper exec(String[] cmdarray, String[] envp, File dir,
String charset) throws IOException {
return new ExecHelper(Runtime.getRuntime().exec(cmdarray, envp, dir),
charset);
}
/**
* Executes the specified command using a shell. On windows uses cmd.exe or
* command.exe. On other platforms it uses /bin/sh.
* <p>
* A shell should be used to execute commands when features such as file
* redirection, pipes, argument parsing are desired.
* <p>
* Output from the process is expected to be text in the system's default
* character set.
* <p>
* No input is passed to the process on STDIN.
*
* @param command
* String containing a command to be parsed by the shell and
* executed.
* @return The results of the execution in an ExecHelper object.
* @throws SecurityException
* if a security manager exists and its checkExec method doesn't
* allow creation of a subprocess.
* @throws IOException -
* if an I/O error occurs
* @throws NullPointerException -
* if command is null
*
*
*/
public static ExecHelper execUsingShell(String command) throws IOException {
return execUsingShell(command, null);
}
/**
* Executes the specified command using a shell. On windows uses cmd.exe or
* command.exe. On other platforms it uses /bin/sh.
* <p>
* A shell should be used to execute commands when features such as file
* redirection, pipes, argument parsing are desired.
* <p>
* No input is passed to the process on STDIN.
*
* @param command
* String containing a command to be parsed by the shell and
* executed.
* @param charset
* Output from the executed command is expected to be in this
* character set.
* @return The results of the execution in an ExecHelper object.
* @throws SecurityException
* if a security manager exists and its checkExec method doesn't
* allow creation of a subprocess.
* @throws IOException -
* if an I/O error occurs
* @throws NullPointerException -
* if command is null
*
*
*/
public static ExecHelper execUsingShell(String command, String charset)
throws IOException {
if (command == null)
throw new NullPointerException();
String[] cmdarray;
String os = System.getProperty("os.name");
if (os.equals("Windows 95") || os.equals("Windows 98")
|| os.equals("Windows ME")) {
cmdarray = new String[] { "command.exe", "/C", command };
} else if (os.startsWith("Windows")) {
cmdarray = new String[] { "cmd.exe", "/C", command };
} else {
cmdarray = new String[] { "/bin/sh", "-c", command };
}
return new ExecHelper(Runtime.getRuntime().exec(cmdarray), charset);
}
/**
* Take a process, record its standard error and standard out streams, wait
* for it to finish
*
* @param process
* process to watch
* @throws SecurityException
* if a security manager exists and its checkExec method doesn't
* allow creation of a subprocess.
* @throws IOException -
* if an I/O error occurs
* @throws NullPointerException -
* if cmdarray is null
* @throws IndexOutOfBoundsException -
* if cmdarray is an empty array (has length 0).
*
*
*/
private ExecHelper(Process process, String charset) throws IOException {
try {
StringBuffer output = new StringBuffer();
StringBuffer error = new StringBuffer();
Reader stdout;
Reader stderr;
if (charset == null) {
// This is one time that the system charset is appropriate,
// don't specify a character set.
stdout = new InputStreamReader(process.getInputStream());
stderr = new InputStreamReader(process.getErrorStream());
} else {
stdout = new InputStreamReader(process.getInputStream(), charset);
stderr = new InputStreamReader(process.getErrorStream(), charset);
}
char[] buffer = new char[1024];
boolean done = false;
boolean stdoutclosed = false;
boolean stderrclosed = false;
while (!done) {
boolean readSomething = false;
// read from the process's standard output
if (!stdoutclosed && stdout.ready()) {
readSomething = true;
int read = stdout.read(buffer, 0, buffer.length);
if (read < 0) {
readSomething = true;
stdoutclosed = true;
} else if (read > 0) {
readSomething = true;
output.append(buffer, 0, read);
}
}
// read from the process's standard error
if (!stderrclosed && stderr.ready()) {
int read = stderr.read(buffer, 0, buffer.length);
if (read < 0) {
readSomething = true;
stderrclosed = true;
} else if (read > 0) {
readSomething = true;
error.append(buffer, 0, read);
}
}
// Check the exit status only we haven't read anything,
// if something has been read, the process is obviously not dead
// yet.
if (!readSomething) {
try {
this.status = process.exitValue();
done = true;
} catch (IllegalThreadStateException itx) {
// Exit status not ready yet.
// Give the process a little breathing room.
try {
Thread.sleep(100);
} catch (InterruptedException ix) {
process.destroy();
throw new IOException("Interrupted - processes killed");
}
}
}
}
this.output = output.toString();
this.error = error.toString();
}catch (Exception e) {
e.printStackTrace();
throw new IOException("Process exec failed : " + e.getMessage());
}finally {
try {
process.getErrorStream().close();
} catch (Exception e) {}
try {
process.getInputStream().close();
} catch (Exception e) {}
try {
process.getOutputStream().close();
} catch (Exception e) {}
}
}
/**
* The output of the job that ran.
*
*
*/
private String output;
/**
* Get the output of the job that ran.
*
* @return Everything the executed process wrote to its standard output as a
* String.
*
*
*/
public String getOutput() {
return output;
}
/**
* The error output of the job that ran.
*
*
*/
private String error;
/**
* Get the error output of the job that ran.
*
* @return Everything the executed process wrote to its standard error as a
* String.
*
*
*/
public String getError() {
return error;
}
/**
* The status of the job that ran.
*
*
*/
private int status;
/**
* Get the status of the job that ran.
*
* @return exit status of the executed process, by convention, the value 0
* indicates normal termination.
*
*
*/
public int getStatus() {
return status;
}
}