htsjdk.samtools.util.ProcessExecutor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of htsjdk Show documentation
Show all versions of htsjdk Show documentation
A Java API for high-throughput sequencing data (HTS) formats
/*
* The MIT License
*
* Copyright (c) 2009 The Broad Institute
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package htsjdk.samtools.util;
import htsjdk.samtools.SAMException;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
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;
/**
* 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 (dvoet at broadinstitute dot org)
*/
public class ProcessExecutor {
private static final Log log = Log.getInstance(ProcessExecutor.class);
private static final ExecutorService executorService = Executors.newCachedThreadPool(new ThreadFactory() {
@Override
public Thread newThread(final 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(final String command) {
try {
final Process process = Runtime.getRuntime().exec(command);
return readStreamsAndWaitFor(process);
} catch (Throwable t) {
throw new SAMException("Unexpected exception executing [" + htsjdk.samtools.util.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(final String[] commandParts) {
return execute(commandParts, null);
}
/**
* Executes the command via Runtime.getRuntime().exec(), writes outputStreamString
* to the process output stream if it is not null, 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(final String[] commandParts, String outputStreamString) {
try {
final Process process = Runtime.getRuntime().exec(commandParts);
if (outputStreamString != null) {
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
writer.write(outputStreamString);
writer.newLine();
writer.close();
}
return readStreamsAndWaitFor(process);
} catch (Throwable t) {
throw new SAMException("Unexpected exception executing [" + htsjdk.samtools.util.StringUtil.join(" ", commandParts) + "]", t);
}
}
public static String executeAndReturnResult(final String command) {
try {
final Process process = Runtime.getRuntime().exec(command);
final StringBuilderProcessOutputReader err = new StringBuilderProcessOutputReader(process.getErrorStream());
final Future> stderrReader = executorService.submit(err);
final StringBuilderProcessOutputReader stdout = new StringBuilderProcessOutputReader(process.getInputStream());
stdout.run();
// wait for stderr reader to be done
stderrReader.get();
final int result = process.waitFor();
return result == 0 ? stdout.getOutput() : err.getOutput();
} catch (Throwable t) {
throw new SAMException("Unexpected exception executing [" + command + "]", t);
}
}
public static class ExitStatusAndOutput {
public final int exitStatus;
public final String stdout;
/** May be null if interleaved */
public final String stderr;
public ExitStatusAndOutput(int exitStatus, String stdout, String stderr) {
this.exitStatus = exitStatus;
this.stdout = stdout;
this.stderr = stderr;
}
}
/**
* Execute the command and capture stdout and stderr.
* @return Exit status of command, and both stderr and stdout interleaved into stdout attribute.
*/
public static ExitStatusAndOutput executeAndReturnInterleavedOutput(final String command) {
try {
final Process process = Runtime.getRuntime().exec(command);
return interleaveProcessOutput(process);
} catch (Throwable t) {
throw new SAMException("Unexpected exception executing [" + command + "]", t);
}
}
/**
* Execute the command and capture stdout and stderr.
* @return Exit status of command, and both stderr and stdout interleaved into stdout attribute.
*/
public static ExitStatusAndOutput executeAndReturnInterleavedOutput(final String[] commandArray) {
try {
final Process process = Runtime.getRuntime().exec(commandArray);
return interleaveProcessOutput(process);
} catch (Throwable t) {
throw new SAMException("Unexpected exception executing [" + StringUtil.join(" ", commandArray) + "]", t);
}
}
private static ExitStatusAndOutput interleaveProcessOutput(final Process process) throws InterruptedException, IOException {
final BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
final BufferedReader stderrReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
final StringBuilder sb = new StringBuilder();
String stdoutLine = null;
String stderrLine = null;
while ((stderrLine = stderrReader.readLine()) != null ||
(stdoutLine = stdoutReader.readLine()) != null) {
if (stderrLine!= null) sb.append(stderrLine).append('\n');
if (stdoutLine!= null) sb.append(stdoutLine).append('\n');
stderrLine = null;
stdoutLine = null;
}
return new ExitStatusAndOutput(process.waitFor(), sb.toString(), null);
}
private static int readStreamsAndWaitFor(final Process process)
throws InterruptedException, ExecutionException {
final 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 final BufferedReader reader;
public ProcessOutputReader(final InputStream stream) {
reader = new BufferedReader(new InputStreamReader(stream));
}
@Override
public void run() {
try {
String line;
while ((line = reader.readLine()) != null) {
write(line);
}
} catch (IOException e) {
throw new SAMException("Unexpected exception reading from process stream", e);
}
}
protected abstract void write(String message);
}
private static class LogErrorProcessOutputReader extends ProcessOutputReader {
public LogErrorProcessOutputReader(final InputStream stream) { super(stream); }
@Override protected void write(final String message) { log.error(message); }
}
private static class LogInfoProcessOutputReader extends ProcessOutputReader {
public LogInfoProcessOutputReader(final InputStream stream) { super(stream); }
@Override protected void write(final String message) { log.info(message); }
}
private static class StringBuilderProcessOutputReader extends ProcessOutputReader {
private final StringBuilder sb = new StringBuilder();
public StringBuilderProcessOutputReader(final InputStream stream) { super(stream); }
@Override protected void write(final String message) { sb.append(message).append('\n'); }
public String getOutput() { return sb.toString(); }
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy