gatk-3.8/java/lib/edu/mit/broad/picard/util/ProcessExecutor.java

122 lines
4.5 KiB
Java
Raw Normal View History

/*
* The Broad Institute
* SOFTWARE COPYRIGHT NOTICE AGREEMENT
* This software and its documentation are copyright 2009 by the
* Broad Institute/Massachusetts Institute of Technology. All rights are reserved.
*
* This software is supplied without any warranty or guaranteed support whatsoever. Neither
* the Broad Institute nor MIT can be responsible for its use, misuse, or functionality.
*/
package edu.mit.broad.picard.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import edu.mit.broad.picard.PicardException;
/**
* Utility class that will execute sub processes via Runtime.getRuntime().exec(...) and read
* off the output from stderr and stdout of the sub process. This implementation uses a different
* thread to read each stream: the current thread for stdout and another, internal thread for
* stderr. This utility is able to handle concurrent executions, spawning as many threads as
* are required to handle the concurrent load.
*
* @author Doug Voet
*/
public class ProcessExecutor {
private static Log log = Log.getInstance(ProcessExecutor.class);
private static ExecutorService executorService = Executors.newCachedThreadPool(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "ProcessExecutor Thread");
}
});
/**
* Executes the command via Runtime.getRuntime().exec() then writes stderr to log.error
* and stdout to log.info and blocks until the command is complete.
*
* @see Runtime#exec(String)
*
* @param command command string
* @return return code of command
*/
public static int execute(String command) {
try {
Process process = Runtime.getRuntime().exec(command);
return readStreamsAndWaitFor(process);
} catch (Throwable t) {
throw new PicardException("Unexpected exception executing [" + StringUtil.join(" ", command) + "]", t);
}
}
/**
* Executes the command via Runtime.getRuntime().exec() then writes stderr to log.error
* and stdout to log.info and blocks until the command is complete.
*
* @see Runtime#exec(String[])
*
* @param commandParts command string
* @return return code of command
*/
public static int execute(String[] commandParts) {
try {
Process process = Runtime.getRuntime().exec(commandParts);
return readStreamsAndWaitFor(process);
} catch (Throwable t) {
throw new PicardException("Unexpected exception executing [" + StringUtil.join(" ", commandParts) + "]", t);
}
}
private static int readStreamsAndWaitFor(Process process)
throws InterruptedException, ExecutionException {
Future<?> stderrReader = executorService.submit(new LogErrorProcessOutputReader(process.getErrorStream()));
new LogInfoProcessOutputReader(process.getInputStream()).run();
// wait for stderr reader to be done
stderrReader.get();
return process.waitFor();
}
/**
* Runnable that reads off the given stream and logs it somewhere.
*/
private static abstract class ProcessOutputReader implements Runnable {
private BufferedReader reader;
public ProcessOutputReader(InputStream stream) {
reader = new BufferedReader(new InputStreamReader(stream));
}
@Override
public void run() {
try {
String line;
while ((line = reader.readLine()) != null) {
log(line);
}
} catch (IOException e) {
throw new PicardException("Unexpected exception reading from process stream", e);
}
}
protected abstract void log(String message);
}
private static class LogErrorProcessOutputReader extends ProcessOutputReader {
public LogErrorProcessOutputReader(InputStream stream) { super(stream); }
@Override protected void log(String message) { log.error(message); }
}
private static class LogInfoProcessOutputReader extends ProcessOutputReader {
public LogInfoProcessOutputReader(InputStream stream) { super(stream); }
@Override protected void log(String message) { log.info(message); }
}
}