*/
package org.sonar.api.utils.command;
-import org.apache.commons.io.IOUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.*;
+import org.apache.commons.io.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
/**
* Synchronously execute a native command line. It's much more limited than the Apache Commons Exec library.
* For example it does not allow to get process output, to run asynchronously or to automatically quote
public int execute(Command command, long timeoutMilliseconds) {
ExecutorService executorService = null;
Process process = null;
+ StreamGobbler outputGobbler = null;
+ StreamGobbler errorGobbler = null;
try {
LoggerFactory.getLogger(getClass()).debug("Executing command: " + command);
ProcessBuilder builder = new ProcessBuilder(command.toStrings());
process = builder.start();
// consume and display the error and output streams
- StreamGobbler outputGobbler = new StreamGobbler(process.getInputStream());
- StreamGobbler errorGobbler = new StreamGobbler(process.getErrorStream());
+ outputGobbler = new StreamGobbler(process.getInputStream());
+ errorGobbler = new StreamGobbler(process.getErrorStream());
outputGobbler.start();
errorGobbler.start();
final Process finalProcess = process;
Callable<Integer> call = new Callable<Integer>() {
public Integer call() throws Exception {
- finalProcess.waitFor();
- return finalProcess.exitValue();
+ return finalProcess.waitFor();
}
};
throw new CommandException(command, e);
} finally {
+ if (outputGobbler != null) {
+ waitUntilFinish(outputGobbler);
+ }
+
+ if (errorGobbler != null) {
+ waitUntilFinish(errorGobbler);
+ }
+
+ if (process != null) {
+ closeStreams(process);
+ }
+
if (executorService != null) {
executorService.shutdown();
}
}
}
+ private void closeStreams(Process process) {
+ IOUtils.closeQuietly(process.getInputStream());
+ IOUtils.closeQuietly(process.getOutputStream());
+ IOUtils.closeQuietly(process.getErrorStream());
+ }
+
+ private void waitUntilFinish(StreamGobbler thread) {
+ try {
+ thread.join();
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+
private static class StreamGobbler extends Thread {
InputStream is;
StreamGobbler(InputStream is) {
+ super("ProcessStreamGobbler");
this.is = is;
}
+ @Override
public void run() {
Logger logger = LoggerFactory.getLogger(CommandExecutor.class);
InputStreamReader isr = new InputStreamReader(is);