122 lines
4.5 KiB
Java
122 lines
4.5 KiB
Java
|
|
/*
|
||
|
|
* 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); }
|
||
|
|
}
|
||
|
|
}
|