From 4fe55966cfa022ae8b9dc3f0ca7ead7d74bc7251 Mon Sep 17 00:00:00 2001 From: Evgeny Mandrikov Date: Mon, 10 Oct 2011 21:03:06 +0400 Subject: [PATCH] SONAR-2852 CommandExecutor must explicitly close all streams --- .../api/utils/command/CommandExecutor.java | 45 +++++++++++++++---- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/command/CommandExecutor.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/command/CommandExecutor.java index 4b8e4c93e4c..1980f870c3d 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/command/CommandExecutor.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/command/CommandExecutor.java @@ -19,16 +19,16 @@ */ 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 @@ -51,6 +51,8 @@ public final class CommandExecutor { 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()); @@ -60,16 +62,15 @@ public final class CommandExecutor { 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 call = new Callable() { public Integer call() throws Exception { - finalProcess.waitFor(); - return finalProcess.exitValue(); + return finalProcess.waitFor(); } }; @@ -85,19 +86,47 @@ public final class CommandExecutor { 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); -- 2.39.5