org.archive.util.ProcessUtils Maven / Gradle / Ivy
/*
* This file is part of the Heritrix web crawler (crawler.archive.org).
*
* Licensed to the Internet Archive (IA) by one or more individual
* contributors.
*
* The IA 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.archive.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Class to run an external process.
* @author stack
* @version $Date$ $Revision$
*/
public class ProcessUtils {
private static final Logger LOGGER =
Logger.getLogger(ProcessUtils.class.getName());
protected ProcessUtils() {
super();
}
/**
* Thread to gobble up an output stream.
* See http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html
*/
protected class StreamGobbler extends Thread {
private final InputStream is;
private final StringBuffer sink = new StringBuffer();
protected StreamGobbler(InputStream is, String name) {
this.is = is;
setName(name);
}
public void run() {
try {
BufferedReader br =
new BufferedReader(new InputStreamReader(this.is));
for (String line = null; (line = br.readLine()) != null;) {
this.sink.append(line);
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
public String getSink() {
return this.sink.toString();
}
}
/**
* Data structure to hold result of a process exec.
* @author stack
* @version $Date$ $Revision$
*/
public class ProcessResult {
private final String [] args;
private final int result;
private final String stdout;
private final String stderr;
protected ProcessResult(String [] args, int result, String stdout,
String stderr) {
this.args = args;
this.result = result;
this.stderr = stderr;
this.stdout = stdout;
}
public int getResult() {
return this.result;
}
public String getStdout() {
return this.stdout;
}
public String getStderr() {
return this.stderr;
}
public String toString() {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < this.args.length; i++) {
sb.append(this.args[i]);
sb.append(", ");
}
return sb.toString() + " exit code: " + this.result +
((this.stderr != null && this.stderr.length() > 0)?
"\nSTDERR: " + this.stderr: "") +
((this.stdout != null && this.stdout.length() > 0)?
"\nSTDOUT: " + this.stdout: "");
}
}
/**
* Runs process.
* @param args List of process args.
* @return A ProcessResult data structure.
* @throws IOException If interrupted, we throw an IOException. If non-zero
* exit code, we throw an IOException (This may need to change).
*/
public static ProcessUtils.ProcessResult exec(String [] args)
throws IOException {
Process p = Runtime.getRuntime().exec(args);
ProcessUtils pu = new ProcessUtils();
// Gobble up any output.
StreamGobbler err = pu.new StreamGobbler(p.getErrorStream(), "stderr");
err.setDaemon(true);
err.start();
StreamGobbler out = pu.new StreamGobbler(p.getInputStream(), "stdout");
out.setDaemon(true);
out.start();
int exitVal;
try {
exitVal = p.waitFor();
} catch (InterruptedException e) {
throw new IOException("Wait on process " + Arrays.toString(args) + " interrupted: "
+ e.getMessage());
}
ProcessUtils.ProcessResult result =
pu.new ProcessResult(args, exitVal, out.getSink(), err.getSink());
if (exitVal != 0) {
throw new IOException(result.toString());
} else if (LOGGER.isLoggable(Level.INFO)) {
LOGGER.info(result.toString());
}
return result;
}
}