From 3cdda99c67d3abe697c9c0b6d5b0a162b0fdab0c Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Tue, 16 Dec 2014 20:46:48 +0100 Subject: [PATCH] - closing _all_ process streams - allowing multiple accesses to stdout / stderr in O(1) --- .../ui/util/command/CommandResult.java | 66 +++++++++++-------- .../ui/util/command/CommandRunner.java | 1 - .../ui/util/mount/WindowsWebDavMounter.java | 2 +- 3 files changed, 41 insertions(+), 28 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/command/CommandResult.java b/main/ui/src/main/java/org/cryptomator/ui/util/command/CommandResult.java index a3d8cf0e5..f069a4f42 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/util/command/CommandResult.java +++ b/main/ui/src/main/java/org/cryptomator/ui/util/command/CommandResult.java @@ -10,12 +10,10 @@ package org.cryptomator.ui.util.command; import static java.lang.String.format; -import static org.apache.commons.io.IOUtils.copy; -import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.InputStream; +import org.apache.commons.io.IOUtils; import org.cryptomator.ui.util.mount.CommandFailedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,59 +23,75 @@ public final class CommandResult { private static final Logger LOG = LoggerFactory.getLogger(CommandResult.class); private final Process process; + private final String stdout; + private final String stderr; + private final CommandFailedException exception; /** + * Constructs a CommandResult from a terminated process and closes all its streams. * @param process An already finished process. */ CommandResult(Process process) { - this.process = process; + String out = null; + String err = null; + CommandFailedException ex = null; + try { + out = IOUtils.toString(process.getInputStream()); + err = IOUtils.toString(process.getErrorStream()); + } catch (IOException e) { + ex = new CommandFailedException(e); + } finally { + this.process = process; + this.stdout = out; + this.stderr = err; + this.exception = ex; + IOUtils.closeQuietly(process.getInputStream()); + IOUtils.closeQuietly(process.getOutputStream()); + IOUtils.closeQuietly(process.getErrorStream()); + logDebugInfo(); + } } /** * @return Data written to STDOUT */ - public String getOutput() throws CommandFailedException { - try (InputStream in = process.getInputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream()) { - copy(in, out); - return new String(out.toByteArray()); - } catch (IOException e) { - throw new CommandFailedException(e); - } + public String getStdOut() throws CommandFailedException { + assertNoException(); + return stdout; } /** * @return Data written to STDERR */ - public String getError() throws CommandFailedException { - try (InputStream in = process.getErrorStream(); ByteArrayOutputStream out = new ByteArrayOutputStream()) { - copy(in, out); - return new String(out.toByteArray()); - } catch (IOException e) { - throw new CommandFailedException(e); - } + public String getStdErr() throws CommandFailedException { + assertNoException(); + return stderr; } /** * @return Exit value of the process */ - public int getExitValue() throws CommandFailedException { + public int getExitValue() { return process.exitValue(); } - void logDebugInfo() { + private void logDebugInfo() { if (LOG.isDebugEnabled()) { - try { - LOG.debug("Command execution finished. Exit code: {}\n" + "Output:\n" + "{}\n" + "Error:\n" + "{}\n", process.exitValue(), getOutput(), getError()); - } catch (CommandFailedException e) { - LOG.debug("Command execution finished. Exit code: {}\n", process.exitValue()); - } + LOG.debug("Command execution finished. Exit code: {}\n" + "Output:\n" + "{}\n" + "Error:\n" + "{}\n", process.exitValue(), stdout, stderr); } } void assertOk() throws CommandFailedException { + assertNoException(); int exitValue = getExitValue(); if (exitValue != 0) { - throw new CommandFailedException(format("Command execution failed. Exit code: %d\n" + "# Output:\n" + "%s\n" + "# Error:\n" + "%s", exitValue, getOutput(), getError())); + throw new CommandFailedException(format("Command execution failed. Exit code: %d\n" + "# Output:\n" + "%s\n" + "# Error:\n" + "%s", exitValue, stdout, stderr)); + } + } + + private void assertNoException() throws CommandFailedException { + if (exception != null) { + throw exception; } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/command/CommandRunner.java b/main/ui/src/main/java/org/cryptomator/ui/util/command/CommandRunner.java index b2695cead..2c5cb69b0 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/util/command/CommandRunner.java +++ b/main/ui/src/main/java/org/cryptomator/ui/util/command/CommandRunner.java @@ -66,7 +66,6 @@ final class CommandRunner { final String[] cmds = ArrayUtils.add(determineCli(), line); final Process proc = Runtime.getRuntime().exec(cmds, env.toArray(new String[0])); result = run(proc, timeout, unit); - result.logDebugInfo(); result.assertOk(); } return result; diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/mount/WindowsWebDavMounter.java b/main/ui/src/main/java/org/cryptomator/ui/util/mount/WindowsWebDavMounter.java index 2da099274..c539a110c 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/util/mount/WindowsWebDavMounter.java +++ b/main/ui/src/main/java/org/cryptomator/ui/util/mount/WindowsWebDavMounter.java @@ -39,7 +39,7 @@ final class WindowsWebDavMounter implements WebDavMounterStrategy { public WebDavMount mount(int localPort) throws CommandFailedException { final Script mountScript = fromLines("net use * http://0--1.ipv6-literal.net:%PORT% /persistent:no").addEnv("PORT", String.valueOf(localPort)); final CommandResult mountResult = mountScript.execute(30, TimeUnit.SECONDS); - final String driveLetter = getDriveLetter(mountResult.getOutput()); + final String driveLetter = getDriveLetter(mountResult.getStdOut()); final Script unmountScript = fromLines("net use " + driveLetter + " /delete").addEnv("DRIVE_LETTER", driveLetter); return new WebDavMount() { @Override