You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2023/12/13 13:32:45 UTC
(commons-exec) 01/03: Sort members
This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-exec.git
commit 26be10ba84c8eeb75e0e1f0e95cdcdaf0051c301
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Wed Dec 13 08:13:24 2023 -0500
Sort members
---
.../java/org/apache/commons/exec/CommandLine.java | 372 +++++-----
.../commons/exec/DefaultExecuteResultHandler.java | 40 +-
.../org/apache/commons/exec/DefaultExecutor.java | 346 +++++-----
.../apache/commons/exec/ExecuteStreamHandler.java | 16 +-
.../org/apache/commons/exec/ExecuteWatchdog.java | 166 ++---
.../java/org/apache/commons/exec/Executor.java | 190 +++---
.../org/apache/commons/exec/LogOutputStream.java | 92 +--
src/main/java/org/apache/commons/exec/OS.java | 72 +-
.../org/apache/commons/exec/PumpStreamHandler.java | 186 ++---
.../java/org/apache/commons/exec/StreamPumper.java | 28 +-
.../java/org/apache/commons/exec/Watchdog.java | 28 +-
.../environment/DefaultProcessingEnvironment.java | 84 +--
.../commons/exec/environment/EnvironmentUtils.java | 72 +-
.../exec/launcher/CommandLauncherFactory.java | 6 +-
.../exec/launcher/CommandLauncherProxy.java | 4 +-
.../commons/exec/launcher/VmsCommandLauncher.java | 48 +-
.../org/apache/commons/exec/util/MapUtils.java | 62 +-
.../org/apache/commons/exec/util/StringUtils.java | 176 ++---
.../org/apache/commons/exec/AbstractExecTest.java | 22 +-
.../org/apache/commons/exec/CommandLineTest.java | 470 ++++++-------
.../apache/commons/exec/DefaultExecutorTest.java | 750 ++++++++++-----------
.../apache/commons/exec/LogOutputStreamTest.java | 72 +-
.../java/org/apache/commons/exec/TestUtil.java | 30 +-
.../java/org/apache/commons/exec/TutorialTest.java | 96 +--
.../exec/environment/EnvironmentUtilsTest.java | 54 +-
.../org/apache/commons/exec/issues/Exec36Test.java | 132 ++--
.../org/apache/commons/exec/issues/Exec41Test.java | 94 +--
.../org/apache/commons/exec/issues/Exec62Test.java | 36 +-
.../org/apache/commons/exec/issues/Exec65Test.java | 32 +-
.../apache/commons/exec/util/StringUtilTest.java | 24 +-
30 files changed, 1900 insertions(+), 1900 deletions(-)
diff --git a/src/main/java/org/apache/commons/exec/CommandLine.java b/src/main/java/org/apache/commons/exec/CommandLine.java
index e3994c09..09204cb0 100644
--- a/src/main/java/org/apache/commons/exec/CommandLine.java
+++ b/src/main/java/org/apache/commons/exec/CommandLine.java
@@ -32,24 +32,26 @@ import org.apache.commons.exec.util.StringUtils;
public class CommandLine {
/**
- * The arguments of the command.
+ * Encapsulates a command line argument.
*/
- private final Vector<Argument> arguments = new Vector<>();
+ final class Argument {
- /**
- * The program to execute.
- */
- private final String executable;
+ private final String value;
+ private final boolean handleQuoting;
- /**
- * A map of name value pairs used to expand command line arguments
- */
- private Map<String, ?> substitutionMap; // N.B. This can contain values other than Strings
+ private Argument(final String value, final boolean handleQuoting) {
+ this.value = value.trim();
+ this.handleQuoting = handleQuoting;
+ }
- /**
- * Was a file being used to set the executable?
- */
- private final boolean isFile;
+ private String getValue() {
+ return value;
+ }
+
+ private boolean isHandleQuoting() {
+ return handleQuoting;
+ }
+ }
/**
* Create a command line from a string.
@@ -90,24 +92,96 @@ public class CommandLine {
}
/**
- * Create a command line without any arguments.
+ * Crack a command line.
*
- * @param executable the executable
+ * @param toProcess the command line to process
+ * @return the command line broken into strings. An empty or null toProcess parameter results in a zero sized array
*/
- public CommandLine(final String executable) {
- this.isFile = false;
- this.executable = toCleanExecutable(executable);
+ private static String[] translateCommandline(final String toProcess) {
+ if (toProcess == null || toProcess.isEmpty()) {
+ // no command? no string
+ return new String[0];
+ }
+
+ // parse with a simple finite state machine
+
+ final int normal = 0;
+ final int inQuote = 1;
+ final int inDoubleQuote = 2;
+ int state = normal;
+ final StringTokenizer tok = new StringTokenizer(toProcess, "\"\' ", true);
+ final ArrayList<String> list = new ArrayList<>();
+ StringBuilder current = new StringBuilder();
+ boolean lastTokenHasBeenQuoted = false;
+
+ while (tok.hasMoreTokens()) {
+ final String nextTok = tok.nextToken();
+ switch (state) {
+ case inQuote:
+ if ("\'".equals(nextTok)) {
+ lastTokenHasBeenQuoted = true;
+ state = normal;
+ } else {
+ current.append(nextTok);
+ }
+ break;
+ case inDoubleQuote:
+ if ("\"".equals(nextTok)) {
+ lastTokenHasBeenQuoted = true;
+ state = normal;
+ } else {
+ current.append(nextTok);
+ }
+ break;
+ default:
+ if ("\'".equals(nextTok)) {
+ state = inQuote;
+ } else if ("\"".equals(nextTok)) {
+ state = inDoubleQuote;
+ } else if (" ".equals(nextTok)) {
+ if (lastTokenHasBeenQuoted || current.length() != 0) {
+ list.add(current.toString());
+ current = new StringBuilder();
+ }
+ } else {
+ current.append(nextTok);
+ }
+ lastTokenHasBeenQuoted = false;
+ break;
+ }
+ }
+
+ if (lastTokenHasBeenQuoted || current.length() != 0) {
+ list.add(current.toString());
+ }
+
+ if (state == inQuote || state == inDoubleQuote) {
+ throw new IllegalArgumentException("Unbalanced quotes in " + toProcess);
+ }
+
+ final String[] args = new String[list.size()];
+ return list.toArray(args);
}
/**
- * Create a command line without any arguments.
- *
- * @param executable the executable file
+ * The arguments of the command.
*/
- public CommandLine(final File executable) {
- this.isFile = true;
- this.executable = toCleanExecutable(executable.getAbsolutePath());
- }
+ private final Vector<Argument> arguments = new Vector<>();
+
+ /**
+ * The program to execute.
+ */
+ private final String executable;
+
+ /**
+ * A map of name value pairs used to expand command line arguments
+ */
+ private Map<String, ?> substitutionMap; // N.B. This can contain values other than Strings
+
+ /**
+ * Was a file being used to set the executable?
+ */
+ private final boolean isFile;
/**
* Copy constructor.
@@ -125,50 +199,56 @@ public class CommandLine {
}
/**
- * Returns the executable.
+ * Create a command line without any arguments.
*
- * @return The executable
+ * @param executable the executable file
*/
- public String getExecutable() {
- // Expand the executable and replace '/' and '\\' with the platform
- // specific file separator char. This is safe here since we know
- // that this is a platform specific command.
- return StringUtils.fixFileSeparatorChar(expandArgument(executable));
+ public CommandLine(final File executable) {
+ this.isFile = true;
+ this.executable = toCleanExecutable(executable.getAbsolutePath());
}
/**
- * Was a file being used to set the executable?
+ * Create a command line without any arguments.
*
- * @return true if a file was used for setting the executable
+ * @param executable the executable
*/
- public boolean isFile() {
- return isFile;
+ public CommandLine(final String executable) {
+ this.isFile = false;
+ this.executable = toCleanExecutable(executable);
}
/**
- * Add multiple arguments. Handles parsing of quotes and whitespace.
+ * Add a single argument. Handles quoting.
*
- * @param addArguments An array of arguments
+ * @param argument The argument to add
* @return The command line itself
+ * @throws IllegalArgumentException If argument contains both single and double quotes
*/
- public CommandLine addArguments(final String[] addArguments) {
- return this.addArguments(addArguments, true);
+ public CommandLine addArgument(final String argument) {
+ return this.addArgument(argument, true);
}
/**
- * Add multiple arguments.
+ * Add a single argument.
*
- * @param addArguments An array of arguments
+ * @param argument The argument to add
* @param handleQuoting Add the argument with/without handling quoting
* @return The command line itself
*/
- public CommandLine addArguments(final String[] addArguments, final boolean handleQuoting) {
- if (addArguments != null) {
- for (final String addArgument : addArguments) {
- addArgument(addArgument, handleQuoting);
- }
+ public CommandLine addArgument(final String argument, final boolean handleQuoting) {
+
+ if (argument == null) {
+ return this;
+ }
+
+ // check if we can really quote the argument - if not throw an
+ // IllegalArgumentException
+ if (handleQuoting) {
+ StringUtils.quoteArgument(argument);
}
+ arguments.add(new Argument(argument, handleQuoting));
return this;
}
@@ -201,39 +281,43 @@ public class CommandLine {
}
/**
- * Add a single argument. Handles quoting.
+ * Add multiple arguments. Handles parsing of quotes and whitespace.
*
- * @param argument The argument to add
+ * @param addArguments An array of arguments
* @return The command line itself
- * @throws IllegalArgumentException If argument contains both single and double quotes
*/
- public CommandLine addArgument(final String argument) {
- return this.addArgument(argument, true);
+ public CommandLine addArguments(final String[] addArguments) {
+ return this.addArguments(addArguments, true);
}
/**
- * Add a single argument.
+ * Add multiple arguments.
*
- * @param argument The argument to add
+ * @param addArguments An array of arguments
* @param handleQuoting Add the argument with/without handling quoting
* @return The command line itself
*/
- public CommandLine addArgument(final String argument, final boolean handleQuoting) {
-
- if (argument == null) {
- return this;
- }
-
- // check if we can really quote the argument - if not throw an
- // IllegalArgumentException
- if (handleQuoting) {
- StringUtils.quoteArgument(argument);
+ public CommandLine addArguments(final String[] addArguments, final boolean handleQuoting) {
+ if (addArguments != null) {
+ for (final String addArgument : addArguments) {
+ addArgument(addArgument, handleQuoting);
+ }
}
- arguments.add(new Argument(argument, handleQuoting));
return this;
}
+ /**
+ * Expand variables in a command line argument.
+ *
+ * @param argument the argument
+ * @return the expanded string
+ */
+ private String expandArgument(final String argument) {
+ final StringBuffer stringBuffer = StringUtils.stringSubstitution(argument, this.getSubstitutionMap(), true);
+ return stringBuffer.toString();
+ }
+
/**
* Returns the expanded and quoted command line arguments.
*
@@ -255,127 +339,42 @@ public class CommandLine {
}
/**
- * @return the substitution map
- */
- public Map<String, ?> getSubstitutionMap() {
- return substitutionMap;
- }
-
- /**
- * Sets the substitutionMap to expand variables in the command line.
+ * Returns the executable.
*
- * @param substitutionMap the map
+ * @return The executable
*/
- public void setSubstitutionMap(final Map<String, ?> substitutionMap) {
- this.substitutionMap = substitutionMap;
+ public String getExecutable() {
+ // Expand the executable and replace '/' and '\\' with the platform
+ // specific file separator char. This is safe here since we know
+ // that this is a platform specific command.
+ return StringUtils.fixFileSeparatorChar(expandArgument(executable));
}
/**
- * Returns the command line as an array of strings.
- *
- * @return The command line as an string array
+ * @return the substitution map
*/
- public String[] toStrings() {
- final String[] result = new String[arguments.size() + 1];
- result[0] = this.getExecutable();
- System.arraycopy(getArguments(), 0, result, 1, result.length - 1);
- return result;
+ public Map<String, ?> getSubstitutionMap() {
+ return substitutionMap;
}
/**
- * Stringify operator returns the command line as a string. Parameters are correctly quoted when containing a space or left untouched if the are already
- * quoted.
+ * Was a file being used to set the executable?
*
- * @return the command line as single string
+ * @return true if a file was used for setting the executable
*/
- @Override
- public String toString() {
- return "[" + StringUtils.toString(toStrings(), ", ") + "]";
+ public boolean isFile() {
+ return isFile;
}
// --- Implementation ---------------------------------------------------
/**
- * Expand variables in a command line argument.
- *
- * @param argument the argument
- * @return the expanded string
- */
- private String expandArgument(final String argument) {
- final StringBuffer stringBuffer = StringUtils.stringSubstitution(argument, this.getSubstitutionMap(), true);
- return stringBuffer.toString();
- }
-
- /**
- * Crack a command line.
+ * Sets the substitutionMap to expand variables in the command line.
*
- * @param toProcess the command line to process
- * @return the command line broken into strings. An empty or null toProcess parameter results in a zero sized array
+ * @param substitutionMap the map
*/
- private static String[] translateCommandline(final String toProcess) {
- if (toProcess == null || toProcess.isEmpty()) {
- // no command? no string
- return new String[0];
- }
-
- // parse with a simple finite state machine
-
- final int normal = 0;
- final int inQuote = 1;
- final int inDoubleQuote = 2;
- int state = normal;
- final StringTokenizer tok = new StringTokenizer(toProcess, "\"\' ", true);
- final ArrayList<String> list = new ArrayList<>();
- StringBuilder current = new StringBuilder();
- boolean lastTokenHasBeenQuoted = false;
-
- while (tok.hasMoreTokens()) {
- final String nextTok = tok.nextToken();
- switch (state) {
- case inQuote:
- if ("\'".equals(nextTok)) {
- lastTokenHasBeenQuoted = true;
- state = normal;
- } else {
- current.append(nextTok);
- }
- break;
- case inDoubleQuote:
- if ("\"".equals(nextTok)) {
- lastTokenHasBeenQuoted = true;
- state = normal;
- } else {
- current.append(nextTok);
- }
- break;
- default:
- if ("\'".equals(nextTok)) {
- state = inQuote;
- } else if ("\"".equals(nextTok)) {
- state = inDoubleQuote;
- } else if (" ".equals(nextTok)) {
- if (lastTokenHasBeenQuoted || current.length() != 0) {
- list.add(current.toString());
- current = new StringBuilder();
- }
- } else {
- current.append(nextTok);
- }
- lastTokenHasBeenQuoted = false;
- break;
- }
- }
-
- if (lastTokenHasBeenQuoted || current.length() != 0) {
- list.add(current.toString());
- }
-
- if (state == inQuote || state == inDoubleQuote) {
- throw new IllegalArgumentException("Unbalanced quotes in " + toProcess);
- }
-
- final String[] args = new String[list.size()];
- return list.toArray(args);
+ public void setSubstitutionMap(final Map<String, ?> substitutionMap) {
+ this.substitutionMap = substitutionMap;
}
/**
@@ -395,24 +394,25 @@ public class CommandLine {
}
/**
- * Encapsulates a command line argument.
+ * Stringify operator returns the command line as a string. Parameters are correctly quoted when containing a space or left untouched if the are already
+ * quoted.
+ *
+ * @return the command line as single string
*/
- final class Argument {
-
- private final String value;
- private final boolean handleQuoting;
-
- private Argument(final String value, final boolean handleQuoting) {
- this.value = value.trim();
- this.handleQuoting = handleQuoting;
- }
-
- private String getValue() {
- return value;
- }
+ @Override
+ public String toString() {
+ return "[" + StringUtils.toString(toStrings(), ", ") + "]";
+ }
- private boolean isHandleQuoting() {
- return handleQuoting;
- }
+ /**
+ * Returns the command line as an array of strings.
+ *
+ * @return The command line as an string array
+ */
+ public String[] toStrings() {
+ final String[] result = new String[arguments.size() + 1];
+ result[0] = this.getExecutable();
+ System.arraycopy(getArguments(), 0, result, 1, result.length - 1);
+ return result;
}
}
diff --git a/src/main/java/org/apache/commons/exec/DefaultExecuteResultHandler.java b/src/main/java/org/apache/commons/exec/DefaultExecuteResultHandler.java
index 08294efc..9414c221 100644
--- a/src/main/java/org/apache/commons/exec/DefaultExecuteResultHandler.java
+++ b/src/main/java/org/apache/commons/exec/DefaultExecuteResultHandler.java
@@ -43,26 +43,6 @@ public class DefaultExecuteResultHandler implements ExecuteResultHandler {
this.exitValue = Executor.INVALID_EXITVALUE;
}
- /**
- * @see org.apache.commons.exec.ExecuteResultHandler#onProcessComplete(int)
- */
- @Override
- public void onProcessComplete(final int exitValue) {
- this.exitValue = exitValue;
- this.exception = null;
- this.hasResult = true;
- }
-
- /**
- * @see org.apache.commons.exec.ExecuteResultHandler#onProcessFailed(org.apache.commons.exec.ExecuteException)
- */
- @Override
- public void onProcessFailed(final ExecuteException e) {
- this.exitValue = e.getExitValue();
- this.exception = e;
- this.hasResult = true;
- }
-
/**
* Gets the {@code exception} causing the process execution to fail.
*
@@ -102,6 +82,26 @@ public class DefaultExecuteResultHandler implements ExecuteResultHandler {
return hasResult;
}
+ /**
+ * @see org.apache.commons.exec.ExecuteResultHandler#onProcessComplete(int)
+ */
+ @Override
+ public void onProcessComplete(final int exitValue) {
+ this.exitValue = exitValue;
+ this.exception = null;
+ this.hasResult = true;
+ }
+
+ /**
+ * @see org.apache.commons.exec.ExecuteResultHandler#onProcessFailed(org.apache.commons.exec.ExecuteException)
+ */
+ @Override
+ public void onProcessFailed(final ExecuteException e) {
+ this.exitValue = e.getExitValue();
+ this.exception = e;
+ this.hasResult = true;
+ }
+
/**
* Causes the current thread to wait, if necessary, until the
* process has terminated. This method returns immediately if
diff --git a/src/main/java/org/apache/commons/exec/DefaultExecutor.java b/src/main/java/org/apache/commons/exec/DefaultExecutor.java
index 6b257ca1..851d7307 100644
--- a/src/main/java/org/apache/commons/exec/DefaultExecutor.java
+++ b/src/main/java/org/apache/commons/exec/DefaultExecutor.java
@@ -88,76 +88,63 @@ public class DefaultExecutor implements Executor {
}
/**
- * @see org.apache.commons.exec.Executor#getStreamHandler()
- */
- @Override
- public ExecuteStreamHandler getStreamHandler() {
- return streamHandler;
- }
-
- /**
- * @see org.apache.commons.exec.Executor#setStreamHandler(org.apache.commons.exec.ExecuteStreamHandler)
- */
- @Override
- public void setStreamHandler(final ExecuteStreamHandler streamHandler) {
- this.streamHandler = streamHandler;
- }
-
- /**
- * @see org.apache.commons.exec.Executor#getWatchdog()
+ * Close the streams belonging to the given Process.
+ *
+ * @param process the <CODE>Process</CODE>.
*/
- @Override
- public ExecuteWatchdog getWatchdog() {
- return watchdog;
- }
+ private void closeProcessStreams(final Process process) {
- /**
- * @see org.apache.commons.exec.Executor#setWatchdog(org.apache.commons.exec.ExecuteWatchdog)
- */
- @Override
- public void setWatchdog(final ExecuteWatchdog watchDog) {
- this.watchdog = watchDog;
- }
+ try {
+ process.getInputStream().close();
+ }
+ catch (final IOException e) {
+ setExceptionCaught(e);
+ }
- /**
- * @see org.apache.commons.exec.Executor#getProcessDestroyer()
- */
- @Override
- public ProcessDestroyer getProcessDestroyer() {
- return this.processDestroyer;
- }
+ try {
+ process.getOutputStream().close();
+ }
+ catch (final IOException e) {
+ setExceptionCaught(e);
+ }
- /**
- * @see org.apache.commons.exec.Executor#setProcessDestroyer(ProcessDestroyer)
- */
- @Override
- public void setProcessDestroyer(final ProcessDestroyer processDestroyer) {
- this.processDestroyer = processDestroyer;
+ try {
+ process.getErrorStream().close();
+ }
+ catch (final IOException e) {
+ setExceptionCaught(e);
+ }
}
/**
- * @see org.apache.commons.exec.Executor#getWorkingDirectory()
+ * Factory method to create a thread waiting for the result of an
+ * asynchronous execution.
+ *
+ * @param runnable the runnable passed to the thread
+ * @param name the name of the thread
+ * @return the thread
*/
- @Override
- public File getWorkingDirectory() {
- return workingDirectory;
+ protected Thread createThread(final Runnable runnable, final String name) {
+ return new Thread(runnable, name);
}
/**
- * @see org.apache.commons.exec.Executor#setWorkingDirectory(java.io.File)
+ * @see org.apache.commons.exec.Executor#execute(CommandLine)
*/
@Override
- public void setWorkingDirectory(final File dir) {
- this.workingDirectory = dir;
+ public int execute(final CommandLine command) throws ExecuteException,
+ IOException {
+ return execute(command, (Map<String, String>) null);
}
/**
- * @see org.apache.commons.exec.Executor#execute(CommandLine)
+ * @see org.apache.commons.exec.Executor#execute(CommandLine,
+ * org.apache.commons.exec.ExecuteResultHandler)
*/
@Override
- public int execute(final CommandLine command) throws ExecuteException,
- IOException {
- return execute(command, (Map<String, String>) null);
+ public void execute(final CommandLine command, final ExecuteResultHandler handler)
+ throws ExecuteException, IOException {
+ execute(command, null, handler);
}
/**
@@ -175,16 +162,6 @@ public class DefaultExecutor implements Executor {
}
- /**
- * @see org.apache.commons.exec.Executor#execute(CommandLine,
- * org.apache.commons.exec.ExecuteResultHandler)
- */
- @Override
- public void execute(final CommandLine command, final ExecuteResultHandler handler)
- throws ExecuteException, IOException {
- execute(command, null, handler);
- }
-
/**
* @see org.apache.commons.exec.Executor#execute(CommandLine,
* java.util.Map, org.apache.commons.exec.ExecuteResultHandler)
@@ -215,112 +192,6 @@ public class DefaultExecutor implements Executor {
getExecutorThread().start();
}
- /** @see org.apache.commons.exec.Executor#setExitValue(int) */
- @Override
- public void setExitValue(final int value) {
- this.setExitValues(new int[] {value});
- }
-
- /** @see org.apache.commons.exec.Executor#setExitValues(int[]) */
- @Override
- public void setExitValues(final int[] values) {
- this.exitValues = values == null ? null : (int[]) values.clone();
- }
-
- /** @see org.apache.commons.exec.Executor#isFailure(int) */
- @Override
- public boolean isFailure(final int exitValue) {
-
- if (this.exitValues == null) {
- return false;
- }
- if (this.exitValues.length == 0) {
- return this.launcher.isFailure(exitValue);
- }
- for (final int exitValue2 : this.exitValues) {
- if (exitValue2 == exitValue) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Factory method to create a thread waiting for the result of an
- * asynchronous execution.
- *
- * @param runnable the runnable passed to the thread
- * @param name the name of the thread
- * @return the thread
- */
- protected Thread createThread(final Runnable runnable, final String name) {
- return new Thread(runnable, name);
- }
-
- /**
- * Creates a process that runs a command.
- *
- * @param command
- * the command to run
- * @param env
- * the environment for the command
- * @param dir
- * the working directory for the command
- * @return the process started
- * @throws IOException
- * forwarded from the particular launcher used
- */
- protected Process launch(final CommandLine command, final Map<String, String> env,
- final File dir) throws IOException {
-
- if (this.launcher == null) {
- throw new IllegalStateException("CommandLauncher can not be null");
- }
-
- if (dir != null && !dir.exists()) {
- throw new IOException(dir + " doesn't exist.");
- }
- return this.launcher.exec(command, env, dir);
- }
-
- /**
- * Gets the worker thread being used for asynchronous execution.
- *
- * @return the worker thread
- */
- protected Thread getExecutorThread() {
- return executorThread;
- }
-
- /**
- * Close the streams belonging to the given Process.
- *
- * @param process the <CODE>Process</CODE>.
- */
- private void closeProcessStreams(final Process process) {
-
- try {
- process.getInputStream().close();
- }
- catch (final IOException e) {
- setExceptionCaught(e);
- }
-
- try {
- process.getOutputStream().close();
- }
- catch (final IOException e) {
- setExceptionCaught(e);
- }
-
- try {
- process.getErrorStream().close();
- }
- catch (final IOException e) {
- setExceptionCaught(e);
- }
- }
-
/**
* Execute an internal process. If the executing thread is interrupted while waiting for the
* child process to return the child process will be killed.
@@ -432,6 +303,100 @@ public class DefaultExecutor implements Executor {
}
}
+ /**
+ * Gets the first IOException being thrown.
+ *
+ * @return the first IOException being caught
+ */
+ private IOException getExceptionCaught() {
+ return this.exceptionCaught;
+ }
+
+ /**
+ * Gets the worker thread being used for asynchronous execution.
+ *
+ * @return the worker thread
+ */
+ protected Thread getExecutorThread() {
+ return executorThread;
+ }
+
+ /**
+ * @see org.apache.commons.exec.Executor#getProcessDestroyer()
+ */
+ @Override
+ public ProcessDestroyer getProcessDestroyer() {
+ return this.processDestroyer;
+ }
+
+ /**
+ * @see org.apache.commons.exec.Executor#getStreamHandler()
+ */
+ @Override
+ public ExecuteStreamHandler getStreamHandler() {
+ return streamHandler;
+ }
+
+ /**
+ * @see org.apache.commons.exec.Executor#getWatchdog()
+ */
+ @Override
+ public ExecuteWatchdog getWatchdog() {
+ return watchdog;
+ }
+
+ /**
+ * @see org.apache.commons.exec.Executor#getWorkingDirectory()
+ */
+ @Override
+ public File getWorkingDirectory() {
+ return workingDirectory;
+ }
+
+ /** @see org.apache.commons.exec.Executor#isFailure(int) */
+ @Override
+ public boolean isFailure(final int exitValue) {
+
+ if (this.exitValues == null) {
+ return false;
+ }
+ if (this.exitValues.length == 0) {
+ return this.launcher.isFailure(exitValue);
+ }
+ for (final int exitValue2 : this.exitValues) {
+ if (exitValue2 == exitValue) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Creates a process that runs a command.
+ *
+ * @param command
+ * the command to run
+ * @param env
+ * the environment for the command
+ * @param dir
+ * the working directory for the command
+ * @return the process started
+ * @throws IOException
+ * forwarded from the particular launcher used
+ */
+ protected Process launch(final CommandLine command, final Map<String, String> env,
+ final File dir) throws IOException {
+
+ if (this.launcher == null) {
+ throw new IllegalStateException("CommandLauncher can not be null");
+ }
+
+ if (dir != null && !dir.exists()) {
+ throw new IOException(dir + " doesn't exist.");
+ }
+ return this.launcher.exec(command, env, dir);
+ }
+
/**
* Keep track of the first IOException being thrown.
*
@@ -443,13 +408,48 @@ public class DefaultExecutor implements Executor {
}
}
+ /** @see org.apache.commons.exec.Executor#setExitValue(int) */
+ @Override
+ public void setExitValue(final int value) {
+ this.setExitValues(new int[] {value});
+ }
+
+ /** @see org.apache.commons.exec.Executor#setExitValues(int[]) */
+ @Override
+ public void setExitValues(final int[] values) {
+ this.exitValues = values == null ? null : (int[]) values.clone();
+ }
+
/**
- * Gets the first IOException being thrown.
- *
- * @return the first IOException being caught
+ * @see org.apache.commons.exec.Executor#setProcessDestroyer(ProcessDestroyer)
*/
- private IOException getExceptionCaught() {
- return this.exceptionCaught;
+ @Override
+ public void setProcessDestroyer(final ProcessDestroyer processDestroyer) {
+ this.processDestroyer = processDestroyer;
+ }
+
+ /**
+ * @see org.apache.commons.exec.Executor#setStreamHandler(org.apache.commons.exec.ExecuteStreamHandler)
+ */
+ @Override
+ public void setStreamHandler(final ExecuteStreamHandler streamHandler) {
+ this.streamHandler = streamHandler;
+ }
+
+ /**
+ * @see org.apache.commons.exec.Executor#setWatchdog(org.apache.commons.exec.ExecuteWatchdog)
+ */
+ @Override
+ public void setWatchdog(final ExecuteWatchdog watchDog) {
+ this.watchdog = watchDog;
+ }
+
+ /**
+ * @see org.apache.commons.exec.Executor#setWorkingDirectory(java.io.File)
+ */
+ @Override
+ public void setWorkingDirectory(final File dir) {
+ this.workingDirectory = dir;
}
}
diff --git a/src/main/java/org/apache/commons/exec/ExecuteStreamHandler.java b/src/main/java/org/apache/commons/exec/ExecuteStreamHandler.java
index b82a2044..95f45958 100644
--- a/src/main/java/org/apache/commons/exec/ExecuteStreamHandler.java
+++ b/src/main/java/org/apache/commons/exec/ExecuteStreamHandler.java
@@ -28,24 +28,24 @@ import java.io.OutputStream;
public interface ExecuteStreamHandler {
/**
- * Install a handler for the input stream of the subprocess.
+ * Install a handler for the error stream of the subprocess.
*
- * @param os
- * output stream to write to the standard input stream of the subprocess
+ * @param is
+ * input stream to read from the error stream from the subprocess
* @throws IOException
* thrown when an I/O exception occurs.
*/
- void setProcessInputStream(OutputStream os) throws IOException;
+ void setProcessErrorStream(InputStream is) throws IOException;
/**
- * Install a handler for the error stream of the subprocess.
+ * Install a handler for the input stream of the subprocess.
*
- * @param is
- * input stream to read from the error stream from the subprocess
+ * @param os
+ * output stream to write to the standard input stream of the subprocess
* @throws IOException
* thrown when an I/O exception occurs.
*/
- void setProcessErrorStream(InputStream is) throws IOException;
+ void setProcessInputStream(OutputStream os) throws IOException;
/**
* Install a handler for the output stream of the subprocess.
diff --git a/src/main/java/org/apache/commons/exec/ExecuteWatchdog.java b/src/main/java/org/apache/commons/exec/ExecuteWatchdog.java
index 43dacb17..6a15cd08 100644
--- a/src/main/java/org/apache/commons/exec/ExecuteWatchdog.java
+++ b/src/main/java/org/apache/commons/exec/ExecuteWatchdog.java
@@ -95,50 +95,25 @@ public class ExecuteWatchdog implements TimeoutObserver {
}
/**
- * Watches the given process and terminates it, if it runs for too long. All
- * information from the previous run are reset.
+ * This method will rethrow the exception that was possibly caught during
+ * the run of the process. It will only remains valid once the process has
+ * been terminated either by 'error', timeout or manual intervention.
+ * Information will be discarded once a new process is ran.
*
- * @param processToMonitor
- * the process to monitor. It cannot be {@code null}
- * @throws IllegalStateException
- * if a process is still being monitored.
+ * @throws Exception
+ * a wrapped exception over the one that was silently swallowed
+ * and stored during the process run.
*/
- public synchronized void start(final Process processToMonitor) {
- Objects.requireNonNull(processToMonitor, "processToMonitor");
- if (this.process != null) {
- throw new IllegalStateException("Already running.");
- }
- this.caught = null;
- this.killedProcess = false;
- this.watch = true;
- this.process = processToMonitor;
- this.processStarted = true;
- this.notifyAll();
- if (this.hasWatchdog) {
- watchdog.start();
+ public synchronized void checkException() throws Exception {
+ if (caught != null) {
+ throw caught;
}
}
/**
- * Notification that starting the process failed.
- *
- * @param e the offending exception
- *
- */
- public synchronized void failedToStart(final Exception e) {
- this.processStarted = true;
- this.caught = e;
- this.notifyAll();
- }
-
- /**
- * Stops the watcher. It will notify all threads possibly waiting on this
- * object.
+ * reset the monitor flag and the process.
*/
- public synchronized void stop() {
- if (hasWatchdog) {
- watchdog.stop();
- }
+ protected synchronized void cleanUp() {
watch = false;
process = null;
}
@@ -153,47 +128,30 @@ public class ExecuteWatchdog implements TimeoutObserver {
}
/**
- * Called after watchdog has finished.
+ * Ensures that the process is started or not already terminated
+ * so we do not race with asynch executionor hang forever. The
+ * caller of this method must be holding the lock on this
*/
- @Override
- public synchronized void timeoutOccured(final Watchdog w) {
- try {
+ private void ensureStarted() {
+ while (!processStarted && caught == null) {
try {
- // We must check if the process was not stopped
- // before being here
- if (process != null) {
- process.exitValue();
- }
- } catch (final IllegalThreadStateException itse) {
- // the process is not terminated, if this is really
- // a timeout and not a manual stop then destroy it.
- if (watch) {
- killedProcess = true;
- process.destroy();
- }
+ this.wait();
+ } catch (final InterruptedException e) {
+ throw new IllegalStateException(e.getMessage(), e);
}
- } catch (final Exception e) {
- caught = e;
- DebugUtils.handleException("Getting the exit value of the process failed", e);
- } finally {
- cleanUp();
}
}
/**
- * This method will rethrow the exception that was possibly caught during
- * the run of the process. It will only remains valid once the process has
- * been terminated either by 'error', timeout or manual intervention.
- * Information will be discarded once a new process is ran.
+ * Notification that starting the process failed.
+ *
+ * @param e the offending exception
*
- * @throws Exception
- * a wrapped exception over the one that was silently swallowed
- * and stored during the process run.
*/
- public synchronized void checkException() throws Exception {
- if (caught != null) {
- throw caught;
- }
+ public synchronized void failedToStart(final Exception e) {
+ this.processStarted = true;
+ this.caught = e;
+ this.notifyAll();
}
/**
@@ -217,30 +175,72 @@ public class ExecuteWatchdog implements TimeoutObserver {
return killedProcess;
}
+ void setProcessNotStarted() {
+ processStarted = false;
+ }
+
/**
- * reset the monitor flag and the process.
+ * Watches the given process and terminates it, if it runs for too long. All
+ * information from the previous run are reset.
+ *
+ * @param processToMonitor
+ * the process to monitor. It cannot be {@code null}
+ * @throws IllegalStateException
+ * if a process is still being monitored.
*/
- protected synchronized void cleanUp() {
- watch = false;
- process = null;
+ public synchronized void start(final Process processToMonitor) {
+ Objects.requireNonNull(processToMonitor, "processToMonitor");
+ if (this.process != null) {
+ throw new IllegalStateException("Already running.");
+ }
+ this.caught = null;
+ this.killedProcess = false;
+ this.watch = true;
+ this.process = processToMonitor;
+ this.processStarted = true;
+ this.notifyAll();
+ if (this.hasWatchdog) {
+ watchdog.start();
+ }
}
- void setProcessNotStarted() {
- processStarted = false;
+ /**
+ * Stops the watcher. It will notify all threads possibly waiting on this
+ * object.
+ */
+ public synchronized void stop() {
+ if (hasWatchdog) {
+ watchdog.stop();
+ }
+ watch = false;
+ process = null;
}
/**
- * Ensures that the process is started or not already terminated
- * so we do not race with asynch executionor hang forever. The
- * caller of this method must be holding the lock on this
+ * Called after watchdog has finished.
*/
- private void ensureStarted() {
- while (!processStarted && caught == null) {
+ @Override
+ public synchronized void timeoutOccured(final Watchdog w) {
+ try {
try {
- this.wait();
- } catch (final InterruptedException e) {
- throw new IllegalStateException(e.getMessage(), e);
+ // We must check if the process was not stopped
+ // before being here
+ if (process != null) {
+ process.exitValue();
+ }
+ } catch (final IllegalThreadStateException itse) {
+ // the process is not terminated, if this is really
+ // a timeout and not a manual stop then destroy it.
+ if (watch) {
+ killedProcess = true;
+ process.destroy();
+ }
}
+ } catch (final Exception e) {
+ caught = e;
+ DebugUtils.handleException("Getting the exit value of the process failed", e);
+ } finally {
+ cleanUp();
}
}
}
diff --git a/src/main/java/org/apache/commons/exec/Executor.java b/src/main/java/org/apache/commons/exec/Executor.java
index 359bd5df..23484037 100644
--- a/src/main/java/org/apache/commons/exec/Executor.java
+++ b/src/main/java/org/apache/commons/exec/Executor.java
@@ -49,61 +49,73 @@ public interface Executor {
int INVALID_EXITVALUE = 0xdeadbeef;
/**
- * Define the {@code exitValue} of the process to be considered
- * successful. If a different exit value is returned by
- * the process then {@link org.apache.commons.exec.Executor#execute(CommandLine)}
- * will throw an {@link org.apache.commons.exec.ExecuteException}
+ * Methods for starting synchronous execution. The child process inherits
+ * all environment variables of the parent process.
*
- * @param value the exit code representing successful execution
+ * @param command the command to execute
+ * @return process exit value
+ * @throws ExecuteException execution of subprocess failed or the
+ * subprocess returned a exit value indicating a failure
+ * {@link Executor#setExitValue(int)}.
*/
- void setExitValue(final int value);
+ int execute(CommandLine command)
+ throws ExecuteException, IOException;
/**
- * Define a list of {@code exitValue} of the process to be considered
- * successful. The caller can pass one of the following values
- * <ul>
- * <li>an array of exit values to be considered successful</li>
- * <li>an empty array for auto-detect of successful exit codes relying on {@link org.apache.commons.exec.Executor#isFailure(int)}</li>
- * <li>null to indicate to skip checking of exit codes</li>
- * </ul>
+ * Methods for starting asynchronous execution. The child process inherits
+ * all environment variables of the parent process. Result provided to
+ * callback handler.
*
- * If an undefined exit value is returned by the process then
- * {@link org.apache.commons.exec.Executor#execute(CommandLine)} will
- * throw an {@link org.apache.commons.exec.ExecuteException}.
+ * @param command the command to execute
+ * @param handler capture process termination and exit code
+ * @throws ExecuteException execution of subprocess failed
+ */
+ void execute(CommandLine command, ExecuteResultHandler handler)
+ throws ExecuteException, IOException;
+
+ /**
+ * Methods for starting synchronous execution.
*
- * @param values a list of the exit codes
+ * @param command the command to execute
+ * @param environment The environment for the new process. If null, the
+ * environment of the current process is used.
+ * @return process exit value
+ * @throws ExecuteException execution of subprocess failed or the
+ * subprocess returned a exit value indicating a failure
+ * {@link Executor#setExitValue(int)}.
*/
- void setExitValues(final int[] values);
+ int execute(CommandLine command, Map<String, String> environment)
+ throws ExecuteException, IOException;
/**
- * Checks whether {@code exitValue} signals a failure. If no
- * exit values are set than the default conventions of the OS is
- * used. e.g. most OS regard an exit code of '0' as successful
- * execution and everything else as failure.
+ * Methods for starting asynchronous execution. The child process inherits
+ * all environment variables of the parent process. Result provided to
+ * callback handler.
*
- * @param exitValue the exit value (return code) to be checked
- * @return {@code true} if {@code exitValue} signals a failure
+ * @param command the command to execute
+ * @param environment The environment for the new process. If null, the
+ * environment of the current process is used.
+ * @param handler capture process termination and exit code
+ * @throws ExecuteException execution of subprocess failed
*/
- boolean isFailure(final int exitValue);
+ void execute(CommandLine command, Map<String, String> environment, ExecuteResultHandler handler)
+ throws ExecuteException, IOException;
/**
- * Gets the StreamHandler used for providing input and
- * retrieving the output.
+ * Sets the handler for cleanup of started processes if the main process
+ * is going to terminate.
*
- * @return the StreamHandler
+ * @return the ProcessDestroyer
*/
- ExecuteStreamHandler getStreamHandler();
+ ProcessDestroyer getProcessDestroyer();
/**
- * Sets a custom the StreamHandler used for providing
- * input and retrieving the output. If you don't provide
- * a proper stream handler the executed process might block
- * when writing to stdout and/or stderr (see
- * {@link Process Process}).
+ * Gets the StreamHandler used for providing input and
+ * retrieving the output.
*
- * @param streamHandler the stream handler
+ * @return the StreamHandler
*/
- void setStreamHandler(ExecuteStreamHandler streamHandler);
+ ExecuteStreamHandler getStreamHandler();
/**
* Gets the watchdog used to kill of processes running,
@@ -114,94 +126,82 @@ public interface Executor {
ExecuteWatchdog getWatchdog();
/**
- * Sets the watchdog used to kill of processes running,
- * typically, too long time.
+ * Gets the working directory of the created process.
*
- * @param watchDog the watchdog
+ * @return the working directory
*/
- void setWatchdog(ExecuteWatchdog watchDog);
+ File getWorkingDirectory();
/**
- * Sets the handler for cleanup of started processes if the main process
- * is going to terminate.
+ * Checks whether {@code exitValue} signals a failure. If no
+ * exit values are set than the default conventions of the OS is
+ * used. e.g. most OS regard an exit code of '0' as successful
+ * execution and everything else as failure.
*
- * @return the ProcessDestroyer
+ * @param exitValue the exit value (return code) to be checked
+ * @return {@code true} if {@code exitValue} signals a failure
*/
- ProcessDestroyer getProcessDestroyer();
+ boolean isFailure(final int exitValue);
/**
- * Gets the handler for cleanup of started processes if the main process
- * is going to terminate.
+ * Define the {@code exitValue} of the process to be considered
+ * successful. If a different exit value is returned by
+ * the process then {@link org.apache.commons.exec.Executor#execute(CommandLine)}
+ * will throw an {@link org.apache.commons.exec.ExecuteException}
*
- * @param processDestroyer the ProcessDestroyer
+ * @param value the exit code representing successful execution
*/
- void setProcessDestroyer(ProcessDestroyer processDestroyer);
+ void setExitValue(final int value);
/**
- * Gets the working directory of the created process.
+ * Define a list of {@code exitValue} of the process to be considered
+ * successful. The caller can pass one of the following values
+ * <ul>
+ * <li>an array of exit values to be considered successful</li>
+ * <li>an empty array for auto-detect of successful exit codes relying on {@link org.apache.commons.exec.Executor#isFailure(int)}</li>
+ * <li>null to indicate to skip checking of exit codes</li>
+ * </ul>
*
- * @return the working directory
- */
- File getWorkingDirectory();
-
- /**
- * Sets the working directory of the created process. The
- * working directory must exist when you start the process.
+ * If an undefined exit value is returned by the process then
+ * {@link org.apache.commons.exec.Executor#execute(CommandLine)} will
+ * throw an {@link org.apache.commons.exec.ExecuteException}.
*
- * @param dir the working directory
+ * @param values a list of the exit codes
*/
- void setWorkingDirectory(File dir);
+ void setExitValues(final int[] values);
/**
- * Methods for starting synchronous execution. The child process inherits
- * all environment variables of the parent process.
+ * Gets the handler for cleanup of started processes if the main process
+ * is going to terminate.
*
- * @param command the command to execute
- * @return process exit value
- * @throws ExecuteException execution of subprocess failed or the
- * subprocess returned a exit value indicating a failure
- * {@link Executor#setExitValue(int)}.
+ * @param processDestroyer the ProcessDestroyer
*/
- int execute(CommandLine command)
- throws ExecuteException, IOException;
+ void setProcessDestroyer(ProcessDestroyer processDestroyer);
/**
- * Methods for starting synchronous execution.
+ * Sets a custom the StreamHandler used for providing
+ * input and retrieving the output. If you don't provide
+ * a proper stream handler the executed process might block
+ * when writing to stdout and/or stderr (see
+ * {@link Process Process}).
*
- * @param command the command to execute
- * @param environment The environment for the new process. If null, the
- * environment of the current process is used.
- * @return process exit value
- * @throws ExecuteException execution of subprocess failed or the
- * subprocess returned a exit value indicating a failure
- * {@link Executor#setExitValue(int)}.
+ * @param streamHandler the stream handler
*/
- int execute(CommandLine command, Map<String, String> environment)
- throws ExecuteException, IOException;
+ void setStreamHandler(ExecuteStreamHandler streamHandler);
/**
- * Methods for starting asynchronous execution. The child process inherits
- * all environment variables of the parent process. Result provided to
- * callback handler.
+ * Sets the watchdog used to kill of processes running,
+ * typically, too long time.
*
- * @param command the command to execute
- * @param handler capture process termination and exit code
- * @throws ExecuteException execution of subprocess failed
+ * @param watchDog the watchdog
*/
- void execute(CommandLine command, ExecuteResultHandler handler)
- throws ExecuteException, IOException;
+ void setWatchdog(ExecuteWatchdog watchDog);
/**
- * Methods for starting asynchronous execution. The child process inherits
- * all environment variables of the parent process. Result provided to
- * callback handler.
+ * Sets the working directory of the created process. The
+ * working directory must exist when you start the process.
*
- * @param command the command to execute
- * @param environment The environment for the new process. If null, the
- * environment of the current process is used.
- * @param handler capture process termination and exit code
- * @throws ExecuteException execution of subprocess failed
+ * @param dir the working directory
*/
- void execute(CommandLine command, Map<String, String> environment, ExecuteResultHandler handler)
- throws ExecuteException, IOException;
+ void setWorkingDirectory(File dir);
}
diff --git a/src/main/java/org/apache/commons/exec/LogOutputStream.java b/src/main/java/org/apache/commons/exec/LogOutputStream.java
index 641ba080..35077564 100644
--- a/src/main/java/org/apache/commons/exec/LogOutputStream.java
+++ b/src/main/java/org/apache/commons/exec/LogOutputStream.java
@@ -89,23 +89,16 @@ public abstract class LogOutputStream
}
/**
- * Write the data to the buffer and flush the buffer, if a line separator is
- * detected.
+ * Writes all remaining data from the buffer.
*
- * @param cc data to log (byte).
- * @see java.io.OutputStream#write(int)
+ * @see java.io.OutputStream#close()
*/
@Override
- public void write(final int cc) throws IOException {
- final byte c = (byte) cc;
- if (c == '\n' || c == '\r') {
- if (!skip) {
- processBuffer();
- }
- } else {
- buffer.write(cc);
+ public void close() throws IOException {
+ if (buffer.size() > 0) {
+ processBuffer();
}
- skip = c == '\r';
+ super.close();
}
/**
@@ -121,25 +114,38 @@ public abstract class LogOutputStream
}
/**
- * Writes all remaining data from the buffer.
- *
- * @see java.io.OutputStream#close()
+ * @return the trace level of the log system
*/
- @Override
- public void close() throws IOException {
- if (buffer.size() > 0) {
- processBuffer();
- }
- super.close();
+ public int getMessageLevel() {
+ return level;
}
/**
- * @return the trace level of the log system
+ * Converts the buffer to a string and sends it to {@code processLine}.
*/
- public int getMessageLevel() {
- return level;
+ protected void processBuffer() {
+ processLine(buffer.toString(charset));
+ buffer.reset();
+ }
+
+ /**
+ * Logs a line to the log system of the user.
+ *
+ * @param line
+ * the line to log.
+ */
+ protected void processLine(final String line) {
+ processLine(line, level);
}
+ /**
+ * Logs a line to the log system of the user.
+ *
+ * @param line the line to log.
+ * @param logLevel the log level to use
+ */
+ protected abstract void processLine(final String line, final int logLevel);
+
/**
* Write a block of characters to the output stream
*
@@ -176,28 +182,22 @@ public abstract class LogOutputStream
}
/**
- * Converts the buffer to a string and sends it to {@code processLine}.
- */
- protected void processBuffer() {
- processLine(buffer.toString(charset));
- buffer.reset();
- }
-
- /**
- * Logs a line to the log system of the user.
+ * Write the data to the buffer and flush the buffer, if a line separator is
+ * detected.
*
- * @param line
- * the line to log.
+ * @param cc data to log (byte).
+ * @see java.io.OutputStream#write(int)
*/
- protected void processLine(final String line) {
- processLine(line, level);
+ @Override
+ public void write(final int cc) throws IOException {
+ final byte c = (byte) cc;
+ if (c == '\n' || c == '\r') {
+ if (!skip) {
+ processBuffer();
+ }
+ } else {
+ buffer.write(cc);
+ }
+ skip = c == '\r';
}
-
- /**
- * Logs a line to the log system of the user.
- *
- * @param line the line to log.
- * @param logLevel the log level to use
- */
- protected abstract void processLine(final String line, final int logLevel);
}
diff --git a/src/main/java/org/apache/commons/exec/OS.java b/src/main/java/org/apache/commons/exec/OS.java
index 3e0e8519..9023e3ea 100644
--- a/src/main/java/org/apache/commons/exec/OS.java
+++ b/src/main/java/org/apache/commons/exec/OS.java
@@ -83,9 +83,14 @@ public final class OS {
private static final String PATH_SEP = File.pathSeparator;
/**
- * Default constructor
+ * Determines if the OS on which commons-exec is executing matches
+ * the given OS architecture.
+ *
+ * @param arch the OS architecture to check for
+ * @return true if the OS matches
*/
- private OS() {
+ public static boolean isArch(final String arch) {
+ return isOs(null, null, arch, null);
}
/**
@@ -111,10 +116,18 @@ public final class OS {
return isFamily(FAMILY_NETWARE);
}
+ public static boolean isFamilyOpenVms() {
+ return isFamily(FAMILY_VMS);
+ }
+
public static boolean isFamilyOS2() {
return isFamily(FAMILY_OS2);
}
+ public static boolean isFamilyOS400() {
+ return isFamily(FAMILY_OS400);
+ }
+
public static boolean isFamilyTandem() {
return isFamily(FAMILY_TANDEM);
}
@@ -123,14 +136,14 @@ public final class OS {
return isFamily(FAMILY_UNIX);
}
- public static boolean isFamilyWindows() {
- return isFamily(FAMILY_WINDOWS);
- }
-
public static boolean isFamilyWin9x() {
return isFamily(FAMILY_9X);
}
+ public static boolean isFamilyWindows() {
+ return isFamily(FAMILY_WINDOWS);
+ }
+
public static boolean isFamilyWinNT() {
return isFamily(FAMILY_NT);
}
@@ -139,14 +152,6 @@ public final class OS {
return isFamily(FAMILY_ZOS);
}
- public static boolean isFamilyOS400() {
- return isFamily(FAMILY_OS400);
- }
-
- public static boolean isFamilyOpenVms() {
- return isFamily(FAMILY_VMS);
- }
-
/**
* Determines if the OS on which commons-exec is executing matches
* the given OS name.
@@ -158,28 +163,6 @@ public final class OS {
return isOs(null, name, null, null);
}
- /**
- * Determines if the OS on which commons-exec is executing matches
- * the given OS architecture.
- *
- * @param arch the OS architecture to check for
- * @return true if the OS matches
- */
- public static boolean isArch(final String arch) {
- return isOs(null, null, arch, null);
- }
-
- /**
- * Determines if the OS on which commonss-exec is executing matches
- * the given OS version.
- *
- * @param version the OS version to check for
- * @return true if the OS matches
- */
- public static boolean isVersion(final String version) {
- return isOs(null, null, null, version);
- }
-
/**
* Determines if the OS on which commons-exec is executing matches the
* given OS family, name, architecture and version.
@@ -265,4 +248,21 @@ public final class OS {
}
return retValue;
}
+
+ /**
+ * Determines if the OS on which commonss-exec is executing matches
+ * the given OS version.
+ *
+ * @param version the OS version to check for
+ * @return true if the OS matches
+ */
+ public static boolean isVersion(final String version) {
+ return isOs(null, null, null, version);
+ }
+
+ /**
+ * Default constructor
+ */
+ private OS() {
+ }
}
diff --git a/src/main/java/org/apache/commons/exec/PumpStreamHandler.java b/src/main/java/org/apache/commons/exec/PumpStreamHandler.java
index 19e38080..aa3e8e4e 100644
--- a/src/main/java/org/apache/commons/exec/PumpStreamHandler.java
+++ b/src/main/java/org/apache/commons/exec/PumpStreamHandler.java
@@ -93,26 +93,84 @@ public class PumpStreamHandler implements ExecuteStreamHandler {
}
/**
- * Sets maximum time to wait until output streams are exchausted
- * when {@link #stop()} was called.
+ * Create the pump to handle error output.
*
- * @param timeout timeout in milliseconds or zero to wait forever (default)
+ * @param is the <CODE>InputStream</CODE>.
+ * @param os the <CODE>OutputStream</CODE>.
*/
- public void setStopTimeout(final long timeout) {
- this.stopTimeout = timeout;
+ protected void createProcessErrorPump(final InputStream is, final OutputStream os) {
+ errorThread = createPump(is, os);
}
/**
- * Sets the <CODE>InputStream</CODE> from which to read the standard output
- * of the process.
+ * Create the pump to handle process output.
*
* @param is the <CODE>InputStream</CODE>.
+ * @param os the <CODE>OutputStream</CODE>.
*/
- @Override
- public void setProcessOutputStream(final InputStream is) {
- if (out != null) {
- createProcessOutputPump(is, out);
- }
+ protected void createProcessOutputPump(final InputStream is, final OutputStream os) {
+ outputThread = createPump(is, os);
+ }
+
+ /**
+ * Creates a stream pumper to copy the given input stream to the given
+ * output stream. When the 'os' is an PipedOutputStream we are closing
+ * 'os' afterwards to avoid an IOException ("Write end dead").
+ *
+ * @param is the input stream to copy from
+ * @param os the output stream to copy into
+ * @return the stream pumper thread
+ */
+ protected Thread createPump(final InputStream is, final OutputStream os) {
+ return createPump(is, os, os instanceof PipedOutputStream);
+ }
+
+ /**
+ * Creates a stream pumper to copy the given input stream to the given
+ * output stream.
+ *
+ * @param is the input stream to copy from
+ * @param os the output stream to copy into
+ * @param closeWhenExhausted close the output stream when the input stream is exhausted
+ * @return the stream pumper thread
+ */
+ protected Thread createPump(final InputStream is, final OutputStream os, final boolean closeWhenExhausted) {
+ final Thread result = new Thread(new StreamPumper(is, os, closeWhenExhausted), "Exec Stream Pumper");
+ result.setDaemon(true);
+ return result;
+ }
+
+ /**
+ * Creates a stream pumper to copy the given input stream to the given
+ * output stream.
+ *
+ * @param is the System.in input stream to copy from
+ * @param os the output stream to copy into
+ * @return the stream pumper thread
+ */
+ private Thread createSystemInPump(final InputStream is, final OutputStream os) {
+ inputStreamPumper = new InputStreamPumper(is, os);
+ final Thread result = new Thread(inputStreamPumper, "Exec Input Stream Pumper");
+ result.setDaemon(true);
+ return result;
+ }
+
+ /**
+ * Gets the error stream.
+ *
+ * @return <CODE>OutputStream</CODE>.
+ */
+ protected OutputStream getErr() {
+ return err;
+ }
+
+ /**
+ * Gets the output stream.
+ *
+ * @return <CODE>OutputStream</CODE>.
+ */
+ protected OutputStream getOut() {
+ return out;
}
/**
@@ -152,6 +210,29 @@ public class PumpStreamHandler implements ExecuteStreamHandler {
}
}
+ /**
+ * Sets the <CODE>InputStream</CODE> from which to read the standard output
+ * of the process.
+ *
+ * @param is the <CODE>InputStream</CODE>.
+ */
+ @Override
+ public void setProcessOutputStream(final InputStream is) {
+ if (out != null) {
+ createProcessOutputPump(is, out);
+ }
+ }
+
+ /**
+ * Sets maximum time to wait until output streams are exchausted
+ * when {@link #stop()} was called.
+ *
+ * @param timeout timeout in milliseconds or zero to wait forever (default)
+ */
+ public void setStopTimeout(final long timeout) {
+ this.stopTimeout = timeout;
+ }
+
/**
* Start the <CODE>Thread</CODE>s.
*/
@@ -206,72 +287,6 @@ public class PumpStreamHandler implements ExecuteStreamHandler {
}
}
- /**
- * Gets the error stream.
- *
- * @return <CODE>OutputStream</CODE>.
- */
- protected OutputStream getErr() {
- return err;
- }
-
- /**
- * Gets the output stream.
- *
- * @return <CODE>OutputStream</CODE>.
- */
- protected OutputStream getOut() {
- return out;
- }
-
- /**
- * Create the pump to handle process output.
- *
- * @param is the <CODE>InputStream</CODE>.
- * @param os the <CODE>OutputStream</CODE>.
- */
- protected void createProcessOutputPump(final InputStream is, final OutputStream os) {
- outputThread = createPump(is, os);
- }
-
- /**
- * Create the pump to handle error output.
- *
- * @param is the <CODE>InputStream</CODE>.
- * @param os the <CODE>OutputStream</CODE>.
- */
- protected void createProcessErrorPump(final InputStream is, final OutputStream os) {
- errorThread = createPump(is, os);
- }
-
- /**
- * Creates a stream pumper to copy the given input stream to the given
- * output stream. When the 'os' is an PipedOutputStream we are closing
- * 'os' afterwards to avoid an IOException ("Write end dead").
- *
- * @param is the input stream to copy from
- * @param os the output stream to copy into
- * @return the stream pumper thread
- */
- protected Thread createPump(final InputStream is, final OutputStream os) {
- return createPump(is, os, os instanceof PipedOutputStream);
- }
-
- /**
- * Creates a stream pumper to copy the given input stream to the given
- * output stream.
- *
- * @param is the input stream to copy from
- * @param os the output stream to copy into
- * @param closeWhenExhausted close the output stream when the input stream is exhausted
- * @return the stream pumper thread
- */
- protected Thread createPump(final InputStream is, final OutputStream os, final boolean closeWhenExhausted) {
- final Thread result = new Thread(new StreamPumper(is, os, closeWhenExhausted), "Exec Stream Pumper");
- result.setDaemon(true);
- return result;
- }
-
/**
* Stopping a pumper thread. The implementation actually waits
* longer than specified in 'timeout' to detect if the timeout
@@ -301,19 +316,4 @@ public class PumpStreamHandler implements ExecuteStreamHandler {
}
}
}
-
- /**
- * Creates a stream pumper to copy the given input stream to the given
- * output stream.
- *
- * @param is the System.in input stream to copy from
- * @param os the output stream to copy into
- * @return the stream pumper thread
- */
- private Thread createSystemInPump(final InputStream is, final OutputStream os) {
- inputStreamPumper = new InputStreamPumper(is, os);
- final Thread result = new Thread(inputStreamPumper, "Exec Input Stream Pumper");
- result.setDaemon(true);
- return result;
- }
}
diff --git a/src/main/java/org/apache/commons/exec/StreamPumper.java b/src/main/java/org/apache/commons/exec/StreamPumper.java
index 8a4ee161..505f5828 100644
--- a/src/main/java/org/apache/commons/exec/StreamPumper.java
+++ b/src/main/java/org/apache/commons/exec/StreamPumper.java
@@ -46,6 +46,16 @@ public class StreamPumper implements Runnable {
/** close the output stream when exhausted */
private final boolean closeWhenExhausted;
+ /**
+ * Create a new stream pumper.
+ *
+ * @param is input stream to read data from
+ * @param os output stream to write data to.
+ */
+ public StreamPumper(final InputStream is, final OutputStream os) {
+ this(is, os, false);
+ }
+
/**
* Create a new stream pumper.
*
@@ -78,13 +88,12 @@ public class StreamPumper implements Runnable {
}
/**
- * Create a new stream pumper.
+ * Tells whether the end of the stream has been reached.
*
- * @param is input stream to read data from
- * @param os output stream to write data to.
+ * @return true is the stream has been exhausted.
*/
- public StreamPumper(final InputStream is, final OutputStream os) {
- this(is, os, false);
+ public synchronized boolean isFinished() {
+ return finished;
}
/**
@@ -123,15 +132,6 @@ public class StreamPumper implements Runnable {
}
}
- /**
- * Tells whether the end of the stream has been reached.
- *
- * @return true is the stream has been exhausted.
- */
- public synchronized boolean isFinished() {
- return finished;
- }
-
/**
* This method blocks until the stream pumper finishes.
*
diff --git a/src/main/java/org/apache/commons/exec/Watchdog.java b/src/main/java/org/apache/commons/exec/Watchdog.java
index 978e6246..dc892307 100644
--- a/src/main/java/org/apache/commons/exec/Watchdog.java
+++ b/src/main/java/org/apache/commons/exec/Watchdog.java
@@ -44,10 +44,6 @@ public class Watchdog implements Runnable {
observers.addElement(to);
}
- public void removeTimeoutObserver(final TimeoutObserver to) {
- observers.removeElement(to);
- }
-
protected final void fireTimeoutOccured() {
final Enumeration<TimeoutObserver> e = observers.elements();
while (e.hasMoreElements()) {
@@ -55,16 +51,8 @@ public class Watchdog implements Runnable {
}
}
- public synchronized void start() {
- stopped = false;
- final Thread t = new Thread(this, "WATCHDOG");
- t.setDaemon(true);
- t.start();
- }
-
- public synchronized void stop() {
- stopped = true;
- notifyAll();
+ public void removeTimeoutObserver(final TimeoutObserver to) {
+ observers.removeElement(to);
}
@Override
@@ -90,4 +78,16 @@ public class Watchdog implements Runnable {
}
}
+ public synchronized void start() {
+ stopped = false;
+ final Thread t = new Thread(this, "WATCHDOG");
+ t.setDaemon(true);
+ t.start();
+ }
+
+ public synchronized void stop() {
+ stopped = true;
+ notifyAll();
+ }
+
}
diff --git a/src/main/java/org/apache/commons/exec/environment/DefaultProcessingEnvironment.java b/src/main/java/org/apache/commons/exec/environment/DefaultProcessingEnvironment.java
index 08111ff7..a09fc262 100644
--- a/src/main/java/org/apache/commons/exec/environment/DefaultProcessingEnvironment.java
+++ b/src/main/java/org/apache/commons/exec/environment/DefaultProcessingEnvironment.java
@@ -42,23 +42,18 @@ public class DefaultProcessingEnvironment {
protected Map<String, String> procEnvironment;
/**
- * Find the list of environment variables for this process.
+ * Creates a map that obeys the casing rules of the current platform for key
+ * lookup. E.g. on a Windows platform, the map keys will be
+ * case-insensitive.
*
- * @return a map containing the environment variables
- * @throws IOException obtaining the environment variables failed
+ * @return The map for storage of environment variables, never
+ * {@code null}.
*/
- public synchronized Map<String, String> getProcEnvironment() throws IOException {
-
- if (procEnvironment == null) {
- procEnvironment = this.createProcEnvironment();
+ private Map<String, String> createEnvironmentMap() {
+ if (OS.isFamilyWindows()) {
+ return new TreeMap<>(String::compareToIgnoreCase);
}
-
- // create a copy of the map just in case that
- // anyone is going to modifiy it, e.g. removing
- // or setting an evironment variable
- final Map<String, String> copy = createEnvironmentMap();
- copy.putAll(procEnvironment);
- return copy;
+ return new HashMap<>();
}
/**
@@ -106,24 +101,6 @@ public class DefaultProcessingEnvironment {
return procEnvironment;
}
- /**
- * Start a process to list the environment variables.
- *
- * @return a reader containing the output of the process
- * @throws IOException starting the process failed
- * @deprecated No longer needed
- */
- @Deprecated
- protected BufferedReader runProcEnvCommand() throws IOException {
-// final ByteArrayOutputStream out = new ByteArrayOutputStream();
-// final Executor exe = new DefaultExecutor();
-// exe.setStreamHandler(new PumpStreamHandler(out));
-// // ignore the exit value - Just try to use what we got
-// exe.execute(getProcEnvCommand());
-// return new BufferedReader(new StringReader(toString(out)));
- return null;
- }
-
/**
* Determine the OS specific command line to get a list of environment
* variables.
@@ -178,6 +155,26 @@ public class DefaultProcessingEnvironment {
return commandLine;
}
+ /**
+ * Find the list of environment variables for this process.
+ *
+ * @return a map containing the environment variables
+ * @throws IOException obtaining the environment variables failed
+ */
+ public synchronized Map<String, String> getProcEnvironment() throws IOException {
+
+ if (procEnvironment == null) {
+ procEnvironment = this.createProcEnvironment();
+ }
+
+ // create a copy of the map just in case that
+ // anyone is going to modifiy it, e.g. removing
+ // or setting an evironment variable
+ final Map<String, String> copy = createEnvironmentMap();
+ copy.putAll(procEnvironment);
+ return copy;
+ }
+
// /**
// * ByteArrayOutputStream#toString doesn't seem to work reliably on OS/390,
// * at least not the way we use it in the execution context.
@@ -205,18 +202,21 @@ public class DefaultProcessingEnvironment {
// }
/**
- * Creates a map that obeys the casing rules of the current platform for key
- * lookup. E.g. on a Windows platform, the map keys will be
- * case-insensitive.
+ * Start a process to list the environment variables.
*
- * @return The map for storage of environment variables, never
- * {@code null}.
+ * @return a reader containing the output of the process
+ * @throws IOException starting the process failed
+ * @deprecated No longer needed
*/
- private Map<String, String> createEnvironmentMap() {
- if (OS.isFamilyWindows()) {
- return new TreeMap<>(String::compareToIgnoreCase);
- }
- return new HashMap<>();
+ @Deprecated
+ protected BufferedReader runProcEnvCommand() throws IOException {
+// final ByteArrayOutputStream out = new ByteArrayOutputStream();
+// final Executor exe = new DefaultExecutor();
+// exe.setStreamHandler(new PumpStreamHandler(out));
+// // ignore the exit value - Just try to use what we got
+// exe.execute(getProcEnvCommand());
+// return new BufferedReader(new StringReader(toString(out)));
+ return null;
}
}
diff --git a/src/main/java/org/apache/commons/exec/environment/EnvironmentUtils.java b/src/main/java/org/apache/commons/exec/environment/EnvironmentUtils.java
index edb26023..e0dda196 100644
--- a/src/main/java/org/apache/commons/exec/environment/EnvironmentUtils.java
+++ b/src/main/java/org/apache/commons/exec/environment/EnvironmentUtils.java
@@ -40,32 +40,15 @@ public class EnvironmentUtils
}
/**
- * Disable constructor.
- */
- private EnvironmentUtils() {
-
- }
-
- /**
- * Gets the variable list as an array.
+ * Add a key/value pair to the given environment.
+ * If the key matches an existing key, the previous setting is replaced.
*
- * @param environment the environment to use, may be {@code null}
- * @return array of key=value assignment strings or {@code null} if and only if
- * the input map was {@code null}
+ * @param environment the current environment
+ * @param keyAndValue the key/value pair
*/
- public static String[] toStrings(final Map<String, String> environment) {
- if (environment == null) {
- return null;
- }
- final String[] result = new String[environment.size()];
- int i = 0;
- for (final Entry<String, String> entry : environment.entrySet()) {
- final String key = entry.getKey() == null ? "" : entry.getKey().toString();
- final String value = entry.getValue() == null ? "" : entry.getValue().toString();
- result[i] = key + "=" + value;
- i++;
- }
- return result;
+ public static void addVariableToEnvironment(final Map<String, String> environment, final String keyAndValue) {
+ final String[] parsedVariable = parseEnvironmentVariable(keyAndValue);
+ environment.put(parsedVariable[0], parsedVariable[1]);
}
/**
@@ -81,18 +64,6 @@ public class EnvironmentUtils
return PROCESSING_ENVIRONMENT_IMPLEMENTATION.getProcEnvironment();
}
- /**
- * Add a key/value pair to the given environment.
- * If the key matches an existing key, the previous setting is replaced.
- *
- * @param environment the current environment
- * @param keyAndValue the key/value pair
- */
- public static void addVariableToEnvironment(final Map<String, String> environment, final String keyAndValue) {
- final String[] parsedVariable = parseEnvironmentVariable(keyAndValue);
- environment.put(parsedVariable[0], parsedVariable[1]);
- }
-
/**
* Split a key/value pair into a String[]. It is assumed
* that the ky/value pair contains a '=' character.
@@ -115,4 +86,33 @@ public class EnvironmentUtils
return result;
}
+ /**
+ * Gets the variable list as an array.
+ *
+ * @param environment the environment to use, may be {@code null}
+ * @return array of key=value assignment strings or {@code null} if and only if
+ * the input map was {@code null}
+ */
+ public static String[] toStrings(final Map<String, String> environment) {
+ if (environment == null) {
+ return null;
+ }
+ final String[] result = new String[environment.size()];
+ int i = 0;
+ for (final Entry<String, String> entry : environment.entrySet()) {
+ final String key = entry.getKey() == null ? "" : entry.getKey().toString();
+ final String value = entry.getValue() == null ? "" : entry.getValue().toString();
+ result[i] = key + "=" + value;
+ i++;
+ }
+ return result;
+ }
+
+ /**
+ * Disable constructor.
+ */
+ private EnvironmentUtils() {
+
+ }
+
}
diff --git a/src/main/java/org/apache/commons/exec/launcher/CommandLauncherFactory.java b/src/main/java/org/apache/commons/exec/launcher/CommandLauncherFactory.java
index 5befe80c..9f2bf34e 100644
--- a/src/main/java/org/apache/commons/exec/launcher/CommandLauncherFactory.java
+++ b/src/main/java/org/apache/commons/exec/launcher/CommandLauncherFactory.java
@@ -24,9 +24,6 @@ import org.apache.commons.exec.OS;
*/
public final class CommandLauncherFactory {
- private CommandLauncherFactory() {
- }
-
/**
* Factory method to create an appropriate launcher.
*
@@ -44,4 +41,7 @@ public final class CommandLauncherFactory {
return launcher;
}
+
+ private CommandLauncherFactory() {
+ }
}
diff --git a/src/main/java/org/apache/commons/exec/launcher/CommandLauncherProxy.java b/src/main/java/org/apache/commons/exec/launcher/CommandLauncherProxy.java
index 9370149e..caf9b52e 100644
--- a/src/main/java/org/apache/commons/exec/launcher/CommandLauncherProxy.java
+++ b/src/main/java/org/apache/commons/exec/launcher/CommandLauncherProxy.java
@@ -28,12 +28,12 @@ import org.apache.commons.exec.CommandLine;
*/
public abstract class CommandLauncherProxy extends CommandLauncherImpl {
+ private final CommandLauncher myLauncher;
+
public CommandLauncherProxy(final CommandLauncher launcher) {
myLauncher = launcher;
}
- private final CommandLauncher myLauncher;
-
/**
* Launches the given command in a new process. Delegates this method to the
* proxied launcher
diff --git a/src/main/java/org/apache/commons/exec/launcher/VmsCommandLauncher.java b/src/main/java/org/apache/commons/exec/launcher/VmsCommandLauncher.java
index bf8f47b0..3f844ca3 100644
--- a/src/main/java/org/apache/commons/exec/launcher/VmsCommandLauncher.java
+++ b/src/main/java/org/apache/commons/exec/launcher/VmsCommandLauncher.java
@@ -37,30 +37,6 @@ import org.apache.commons.exec.util.StringUtils;
*/
public class VmsCommandLauncher extends Java13CommandLauncher {
- /**
- * Launches the given command in a new process.
- */
- @Override
- public Process exec(final CommandLine cmd, final Map<String, String> env) throws IOException {
- return super.exec(new CommandLine(createCommandFile(cmd, env).getPath()), env);
- }
-
- /**
- * Launches the given command in a new process, in the given working directory. Note that under Java 1.3.1, 1.4.0 and 1.4.1 on VMS this method only works if
- * {@code workingDir} is null or the logical JAVA$FORK_SUPPORT_CHDIR needs to be set to TRUE.
- */
- @Override
- public Process exec(final CommandLine cmd, final Map<String, String> env, final File workingDir) throws IOException {
- return super.exec(new CommandLine(createCommandFile(cmd, env).getPath()), env, workingDir);
- }
-
- /** @see org.apache.commons.exec.launcher.CommandLauncher#isFailure(int) */
- @Override
- public boolean isFailure(final int exitValue) {
- // even exit value signals failure
- return exitValue % 2 == 0;
- }
-
/*
* Writes the command into a temporary DCL script and returns the
* corresponding File object. The script will be deleted on exit.
@@ -126,4 +102,28 @@ public class VmsCommandLauncher extends Java13CommandLauncher {
}
return script;
}
+
+ /**
+ * Launches the given command in a new process.
+ */
+ @Override
+ public Process exec(final CommandLine cmd, final Map<String, String> env) throws IOException {
+ return super.exec(new CommandLine(createCommandFile(cmd, env).getPath()), env);
+ }
+
+ /**
+ * Launches the given command in a new process, in the given working directory. Note that under Java 1.3.1, 1.4.0 and 1.4.1 on VMS this method only works if
+ * {@code workingDir} is null or the logical JAVA$FORK_SUPPORT_CHDIR needs to be set to TRUE.
+ */
+ @Override
+ public Process exec(final CommandLine cmd, final Map<String, String> env, final File workingDir) throws IOException {
+ return super.exec(new CommandLine(createCommandFile(cmd, env).getPath()), env, workingDir);
+ }
+
+ /** @see org.apache.commons.exec.launcher.CommandLauncher#isFailure(int) */
+ @Override
+ public boolean isFailure(final int exitValue) {
+ // even exit value signals failure
+ return exitValue % 2 == 0;
+ }
}
diff --git a/src/main/java/org/apache/commons/exec/util/MapUtils.java b/src/main/java/org/apache/commons/exec/util/MapUtils.java
index eab30778..77e53bbb 100644
--- a/src/main/java/org/apache/commons/exec/util/MapUtils.java
+++ b/src/main/java/org/apache/commons/exec/util/MapUtils.java
@@ -41,37 +41,6 @@ public class MapUtils
return source == null ? null : new HashMap<>(source);
}
- /**
- * Clones a map and prefixes the keys in the clone, e.g. for mapping "JAVA_HOME" to "env.JAVA_HOME" to simulate the
- * behavior of Ant.
- *
- * @param source
- * the source map
- * @param prefix
- * the prefix used for all names
- * @param <K>
- * the map key type
- * @param <V>
- * the map value type
- * @return the clone of the source map
- */
- public static <K, V> Map<String, V> prefix(final Map<K, V> source, final String prefix) {
-
- if (source == null) {
- return null;
- }
-
- final Map<String, V> result = new HashMap<>();
-
- for (final Map.Entry<K, V> entry : source.entrySet()) {
- final K key = entry.getKey();
- final V value = entry.getValue();
- result.put(prefix + '.' + key.toString(), value);
- }
-
- return result;
- }
-
/**
* Clones the lhs map and add all things from the rhs map.
*
@@ -102,4 +71,35 @@ public class MapUtils
return result;
}
+
+ /**
+ * Clones a map and prefixes the keys in the clone, e.g. for mapping "JAVA_HOME" to "env.JAVA_HOME" to simulate the
+ * behavior of Ant.
+ *
+ * @param source
+ * the source map
+ * @param prefix
+ * the prefix used for all names
+ * @param <K>
+ * the map key type
+ * @param <V>
+ * the map value type
+ * @return the clone of the source map
+ */
+ public static <K, V> Map<String, V> prefix(final Map<K, V> source, final String prefix) {
+
+ if (source == null) {
+ return null;
+ }
+
+ final Map<String, V> result = new HashMap<>();
+
+ for (final Map.Entry<K, V> entry : source.entrySet()) {
+ final K key = entry.getKey();
+ final V value = entry.getValue();
+ result.put(prefix + '.' + key.toString(), value);
+ }
+
+ return result;
+ }
}
diff --git a/src/main/java/org/apache/commons/exec/util/StringUtils.java b/src/main/java/org/apache/commons/exec/util/StringUtils.java
index 9bcb8134..a3a8be2d 100644
--- a/src/main/java/org/apache/commons/exec/util/StringUtils.java
+++ b/src/main/java/org/apache/commons/exec/util/StringUtils.java
@@ -39,6 +39,94 @@ public class StringUtils {
private static final char SLASH_CHAR = '/';
private static final char BACKSLASH_CHAR = '\\';
+ /**
+ * Fixes the file separator char for the target platform
+ * using the following replacement.
+ *
+ * <ul>
+ * <li>'/' → File.separatorChar</li>
+ * <li>'\\' → File.separatorChar</li>
+ * </ul>
+ *
+ * @param arg the argument to fix
+ * @return the transformed argument
+ */
+ public static String fixFileSeparatorChar(final String arg) {
+ return arg.replace(SLASH_CHAR, File.separatorChar).replace(
+ BACKSLASH_CHAR, File.separatorChar);
+ }
+
+ /**
+ * Determines if this is a quoted argument - either single or
+ * double quoted.
+ *
+ * @param argument the argument to check
+ * @return true when the argument is quoted
+ */
+ public static boolean isQuoted(final String argument) {
+ return argument.startsWith(SINGLE_QUOTE) && argument.endsWith(SINGLE_QUOTE)
+ || argument.startsWith(DOUBLE_QUOTE) && argument.endsWith(DOUBLE_QUOTE);
+ }
+
+ /**
+ * Put quotes around the given String if necessary.
+ * <p>
+ * If the argument doesn't include spaces or quotes, return it as is. If it
+ * contains double quotes, use single quotes - else surround the argument by
+ * double quotes.
+ * </p>
+ *
+ * @param argument the argument to be quoted
+ * @return the quoted argument
+ * @throws IllegalArgumentException If argument contains both types of quotes
+ */
+ public static String quoteArgument(final String argument) {
+
+ String cleanedArgument = argument.trim();
+
+ // strip the quotes from both ends
+ while (cleanedArgument.startsWith(SINGLE_QUOTE) || cleanedArgument.startsWith(DOUBLE_QUOTE)) {
+ cleanedArgument = cleanedArgument.substring(1);
+ }
+
+ while (cleanedArgument.endsWith(SINGLE_QUOTE) || cleanedArgument.endsWith(DOUBLE_QUOTE)) {
+ cleanedArgument = cleanedArgument.substring(0, cleanedArgument.length() - 1);
+ }
+
+ final StringBuilder buf = new StringBuilder();
+ if (cleanedArgument.indexOf(DOUBLE_QUOTE) > -1) {
+ if (cleanedArgument.indexOf(SINGLE_QUOTE) > -1) {
+ throw new IllegalArgumentException(
+ "Can't handle single and double quotes in same argument");
+ }
+ return buf.append(SINGLE_QUOTE).append(cleanedArgument).append(
+ SINGLE_QUOTE).toString();
+ }
+ if (cleanedArgument.indexOf(SINGLE_QUOTE) > -1
+ || cleanedArgument.indexOf(" ") > -1) {
+ return buf.append(DOUBLE_QUOTE).append(cleanedArgument).append(
+ DOUBLE_QUOTE).toString();
+ }
+ return cleanedArgument;
+ }
+
+ /**
+ * Split a string into an array of strings based
+ * on a separator.
+ *
+ * @param input what to split
+ * @param splitChar what to split on
+ * @return the array of strings
+ */
+ public static String[] split(final String input, final String splitChar) {
+ final StringTokenizer tokens = new StringTokenizer(input, splitChar);
+ final List<String> strList = new ArrayList<>();
+ while (tokens.hasMoreTokens()) {
+ strList.add(tokens.nextToken());
+ }
+ return strList.toArray(EMPTY_STRING_ARRAY);
+ }
+
/**
* Perform a series of substitutions.
* <p>
@@ -147,40 +235,6 @@ public class StringUtils {
return argBuf;
}
- /**
- * Split a string into an array of strings based
- * on a separator.
- *
- * @param input what to split
- * @param splitChar what to split on
- * @return the array of strings
- */
- public static String[] split(final String input, final String splitChar) {
- final StringTokenizer tokens = new StringTokenizer(input, splitChar);
- final List<String> strList = new ArrayList<>();
- while (tokens.hasMoreTokens()) {
- strList.add(tokens.nextToken());
- }
- return strList.toArray(EMPTY_STRING_ARRAY);
- }
-
- /**
- * Fixes the file separator char for the target platform
- * using the following replacement.
- *
- * <ul>
- * <li>'/' → File.separatorChar</li>
- * <li>'\\' → File.separatorChar</li>
- * </ul>
- *
- * @param arg the argument to fix
- * @return the transformed argument
- */
- public static String fixFileSeparatorChar(final String arg) {
- return arg.replace(SLASH_CHAR, File.separatorChar).replace(
- BACKSLASH_CHAR, File.separatorChar);
- }
-
/**
* Concatenates an array of string using a separator.
*
@@ -198,58 +252,4 @@ public class StringUtils {
}
return sb.toString();
}
-
- /**
- * Put quotes around the given String if necessary.
- * <p>
- * If the argument doesn't include spaces or quotes, return it as is. If it
- * contains double quotes, use single quotes - else surround the argument by
- * double quotes.
- * </p>
- *
- * @param argument the argument to be quoted
- * @return the quoted argument
- * @throws IllegalArgumentException If argument contains both types of quotes
- */
- public static String quoteArgument(final String argument) {
-
- String cleanedArgument = argument.trim();
-
- // strip the quotes from both ends
- while (cleanedArgument.startsWith(SINGLE_QUOTE) || cleanedArgument.startsWith(DOUBLE_QUOTE)) {
- cleanedArgument = cleanedArgument.substring(1);
- }
-
- while (cleanedArgument.endsWith(SINGLE_QUOTE) || cleanedArgument.endsWith(DOUBLE_QUOTE)) {
- cleanedArgument = cleanedArgument.substring(0, cleanedArgument.length() - 1);
- }
-
- final StringBuilder buf = new StringBuilder();
- if (cleanedArgument.indexOf(DOUBLE_QUOTE) > -1) {
- if (cleanedArgument.indexOf(SINGLE_QUOTE) > -1) {
- throw new IllegalArgumentException(
- "Can't handle single and double quotes in same argument");
- }
- return buf.append(SINGLE_QUOTE).append(cleanedArgument).append(
- SINGLE_QUOTE).toString();
- }
- if (cleanedArgument.indexOf(SINGLE_QUOTE) > -1
- || cleanedArgument.indexOf(" ") > -1) {
- return buf.append(DOUBLE_QUOTE).append(cleanedArgument).append(
- DOUBLE_QUOTE).toString();
- }
- return cleanedArgument;
- }
-
- /**
- * Determines if this is a quoted argument - either single or
- * double quoted.
- *
- * @param argument the argument to check
- * @return true when the argument is quoted
- */
- public static boolean isQuoted(final String argument) {
- return argument.startsWith(SINGLE_QUOTE) && argument.endsWith(SINGLE_QUOTE)
- || argument.startsWith(DOUBLE_QUOTE) && argument.endsWith(DOUBLE_QUOTE);
- }
}
\ No newline at end of file
diff --git a/src/test/java/org/apache/commons/exec/AbstractExecTest.java b/src/test/java/org/apache/commons/exec/AbstractExecTest.java
index 75aceac8..bf417375 100644
--- a/src/test/java/org/apache/commons/exec/AbstractExecTest.java
+++ b/src/test/java/org/apache/commons/exec/AbstractExecTest.java
@@ -33,6 +33,13 @@ public abstract class AbstractExecTest {
@Rule public TestName name = new TestName();
+ /**
+ * Gets the name of the currently executed test.
+ */
+ protected String getName() {
+ return name.getMethodName();
+ }
+
/**
* Resolve the OS-specific test file to execute.
*/
@@ -55,11 +62,10 @@ public abstract class AbstractExecTest {
return result;
}
- /**
- * Gets the name of the currently executed test.
- */
- protected String getName() {
- return name.getMethodName();
+ protected String testIsBrokenForCurrentOperatingSystem() {
+ final String msg = String.format("The test '%s' is broken for OS : %s", name.getMethodName(), OS_NAME);
+ System.err.println(msg);
+ return msg;
}
protected String testNotSupportedForCurrentOperatingSystem() {
@@ -68,10 +74,4 @@ public abstract class AbstractExecTest {
return msg;
}
- protected String testIsBrokenForCurrentOperatingSystem() {
- final String msg = String.format("The test '%s' is broken for OS : %s", name.getMethodName(), OS_NAME);
- System.err.println(msg);
- return msg;
- }
-
}
diff --git a/src/test/java/org/apache/commons/exec/CommandLineTest.java b/src/test/java/org/apache/commons/exec/CommandLineTest.java
index c016b6ab..c0505819 100644
--- a/src/test/java/org/apache/commons/exec/CommandLineTest.java
+++ b/src/test/java/org/apache/commons/exec/CommandLineTest.java
@@ -34,70 +34,66 @@ import org.junit.Test;
public class CommandLineTest {
@Test
- public void testExecutable() {
+ public void testAddArgument() {
final CommandLine cmdl = new CommandLine("test");
- assertEquals("[test]", cmdl.toString());
- assertArrayEquals(new String[]{"test"}, cmdl.toStrings());
- assertEquals("test", cmdl.getExecutable());
- assertTrue(cmdl.getArguments().length == 0);
+
+ cmdl.addArgument("foo");
+ cmdl.addArgument("bar");
+ assertEquals("[test, foo, bar]", cmdl.toString());
+ assertArrayEquals(new String[]{"test", "foo", "bar"}, cmdl.toStrings());
}
@Test
- public void testExecutableZeroLengthString() {
- try {
- new CommandLine("");
- fail("Must throw IllegalArgumentException");
- } catch (final IllegalArgumentException e) {
- // Expected
- }
+ public void testAddArguments() {
+ final CommandLine cmdl = new CommandLine("test");
+ cmdl.addArguments("foo bar");
+ assertEquals("[test, foo, bar]", cmdl.toString());
+ assertArrayEquals(new String[]{"test", "foo", "bar"}, cmdl.toStrings());
}
@Test
- public void testExecutableWhitespaceString() {
- try {
- new CommandLine(" ");
- fail("Must throw IllegalArgumentException");
- } catch (final IllegalArgumentException e) {
- // Expected
- }
+ public void testAddArgumentsArray() {
+ final CommandLine cmdl = new CommandLine("test");
+ cmdl.addArguments(new String[] {"foo", "bar"});
+ assertEquals("[test, foo, bar]", cmdl.toString());
+ assertArrayEquals(new String[]{"test", "foo", "bar"}, cmdl.toStrings());
}
@Test
- public void testNullExecutable() {
- try {
- new CommandLine((String)null);
- fail("Must throw IllegalArgumentException");
- } catch (final IllegalArgumentException e) {
- // Expected
- }
+ public void testAddArgumentsArrayNull() {
+ final CommandLine cmdl = new CommandLine("test");
+ cmdl.addArguments((String[]) null);
+ assertEquals("[test]", cmdl.toString());
+ assertArrayEquals(new String[]{"test"}, cmdl.toStrings());
}
@Test
- public void testAddArgument() {
+ public void testAddArgumentsWithQuotes() {
final CommandLine cmdl = new CommandLine("test");
-
- cmdl.addArgument("foo");
- cmdl.addArgument("bar");
+ cmdl.addArguments("'foo' \"bar\"");
assertEquals("[test, foo, bar]", cmdl.toString());
assertArrayEquals(new String[]{"test", "foo", "bar"}, cmdl.toStrings());
}
@Test
- public void testAddNullArgument() {
+ public void testAddArgumentsWithQuotesAndSpaces() {
final CommandLine cmdl = new CommandLine("test");
-
- cmdl.addArgument(null);
- assertEquals("[test]", cmdl.toString());
- assertArrayEquals(new String[]{"test"}, cmdl.toStrings());
+ cmdl.addArguments("'fo o' \"ba r\"");
+ assertEquals("[test, \"fo o\", \"ba r\"]", cmdl.toString());
+ assertArrayEquals(new String[]{"test", "\"fo o\"", "\"ba r\""}, cmdl
+ .toStrings());
}
@Test
- public void testAddArgumentWithSpace() {
+ public void testAddArgumentWithBothQuotes() {
final CommandLine cmdl = new CommandLine("test");
- cmdl.addArgument("foo");
- cmdl.addArgument("ba r");
- assertEquals("[test, foo, \"ba r\"]", cmdl.toString());
- assertArrayEquals(new String[]{"test", "foo", "\"ba r\""}, cmdl.toStrings());
+
+ try {
+ cmdl.addArgument("b\"a'r");
+ fail("IllegalArgumentException should be thrown");
+ } catch (final IllegalArgumentException e) {
+ // OK, expected
+ }
}
@Test
@@ -131,54 +127,19 @@ public class CommandLineTest {
}
@Test
- public void testAddArgumentWithBothQuotes() {
- final CommandLine cmdl = new CommandLine("test");
-
- try {
- cmdl.addArgument("b\"a'r");
- fail("IllegalArgumentException should be thrown");
- } catch (final IllegalArgumentException e) {
- // OK, expected
- }
- }
-
- @Test
- public void testAddArguments() {
- final CommandLine cmdl = new CommandLine("test");
- cmdl.addArguments("foo bar");
- assertEquals("[test, foo, bar]", cmdl.toString());
- assertArrayEquals(new String[]{"test", "foo", "bar"}, cmdl.toStrings());
- }
-
- @Test
- public void testAddArgumentsWithQuotes() {
- final CommandLine cmdl = new CommandLine("test");
- cmdl.addArguments("'foo' \"bar\"");
- assertEquals("[test, foo, bar]", cmdl.toString());
- assertArrayEquals(new String[]{"test", "foo", "bar"}, cmdl.toStrings());
- }
-
- @Test
- public void testAddArgumentsWithQuotesAndSpaces() {
+ public void testAddArgumentWithSpace() {
final CommandLine cmdl = new CommandLine("test");
- cmdl.addArguments("'fo o' \"ba r\"");
- assertEquals("[test, \"fo o\", \"ba r\"]", cmdl.toString());
- assertArrayEquals(new String[]{"test", "\"fo o\"", "\"ba r\""}, cmdl
- .toStrings());
+ cmdl.addArgument("foo");
+ cmdl.addArgument("ba r");
+ assertEquals("[test, foo, \"ba r\"]", cmdl.toString());
+ assertArrayEquals(new String[]{"test", "foo", "\"ba r\""}, cmdl.toStrings());
}
@Test
- public void testAddArgumentsArray() {
+ public void testAddNullArgument() {
final CommandLine cmdl = new CommandLine("test");
- cmdl.addArguments(new String[] {"foo", "bar"});
- assertEquals("[test, foo, bar]", cmdl.toString());
- assertArrayEquals(new String[]{"test", "foo", "bar"}, cmdl.toStrings());
- }
- @Test
- public void testAddArgumentsArrayNull() {
- final CommandLine cmdl = new CommandLine("test");
- cmdl.addArguments((String[]) null);
+ cmdl.addArgument(null);
assertEquals("[test]", cmdl.toString());
assertArrayEquals(new String[]{"test"}, cmdl.toStrings());
}
@@ -203,142 +164,6 @@ public class CommandLineTest {
assertEquals(userAddCL1.toString(), userAddCL2.toString());
}
- @Test
- public void testParseCommandLine() {
- final CommandLine cmdl = CommandLine.parse("test foo bar");
- assertEquals("[test, foo, bar]", cmdl.toString());
- assertArrayEquals(new String[]{"test", "foo", "bar"}, cmdl.toStrings());
- }
-
- @Test
- public void testParseCommandLineWithQuotes() {
- final CommandLine cmdl = CommandLine.parse("test \"foo\" \'ba r\'");
- assertEquals("[test, foo, \"ba r\"]", cmdl.toString());
- assertArrayEquals(new String[]{"test", "foo", "\"ba r\""}, cmdl.toStrings());
- }
-
- @Test
- public void testParseCommandLineWithUnevenQuotes() {
- try {
- CommandLine.parse("test \"foo bar");
- fail("IllegalArgumentException must be thrown due to uneven quotes");
- } catch (final IllegalArgumentException e) {
- // Expected
- }
- }
-
- @Test
- public void testParseCommandLineWithNull() {
- try {
- CommandLine.parse(null);
- fail("IllegalArgumentException must be thrown due to incorrect command line");
- } catch (final IllegalArgumentException e) {
- // Expected
- }
- }
-
- @Test
- public void testParseCommandLineWithOnlyWhitespace() {
- try {
- CommandLine.parse(" ");
- fail("IllegalArgumentException must be thrown due to incorrect command line");
- } catch (final IllegalArgumentException e) {
- // Expected
- }
- }
-
- /**
- * A command line parsing puzzle from Tino Schoellhorn - ImageMagix expects
- * a "500x>" parameter (including quotes) and it is simply not possible to
- * do that without adding a space, e.g. "500x> ".
- */
- @Test
- public void testParseComplexCommandLine1() {
- final HashMap<String, String> substitutionMap =
- new HashMap<>();
- substitutionMap.put("in", "source.jpg");
- substitutionMap.put("out", "target.jpg");
- final CommandLine cmdl = CommandLine.parse("cmd /C convert ${in} -resize \"\'500x> \'\" ${out}", substitutionMap);
- assertEquals("[cmd, /C, convert, source.jpg, -resize, \"500x> \", target.jpg]", cmdl.toString());
- }
-
- /**
- * Another command line parsing puzzle from Kai Hu - as
- * far as I understand it there is no way to express that
- * in a one-line command string.
- */
- @Test
- public void testParseComplexCommandLine2() {
-
- final String commandline = "./script/jrake cruise:publish_installers "
- + "INSTALLER_VERSION=unstable_2_1 "
- + "INSTALLER_PATH=\"/var/lib/ cruise-agent/installers\" "
- + "INSTALLER_DOWNLOAD_SERVER=\'something\' "
- + "WITHOUT_HELP_DOC=true";
-
- final CommandLine cmdl = CommandLine.parse(commandline);
- final String[] args = cmdl.getArguments();
- assertEquals(args[0], "cruise:publish_installers");
- assertEquals(args[1], "INSTALLER_VERSION=unstable_2_1");
- // assertEquals(args[2], "INSTALLER_PATH=\"/var/lib/ cruise-agent/installers\"");
- // assertEquals(args[3], "INSTALLER_DOWNLOAD_SERVER='something'");
- assertEquals(args[4], "WITHOUT_HELP_DOC=true");
- }
-
- /**
- * Test the following command line
- *
- * cmd.exe /C c:\was51\Web Sphere\AppServer\bin\versionInfo.bat
- */
- @Test
- public void testParseRealLifeCommandLine_1() {
-
- final String commandline = "cmd.exe /C \"c:\\was51\\Web Sphere\\AppServer\\bin\\versionInfo.bat\"";
-
- final CommandLine cmdl = CommandLine.parse(commandline);
- final String[] args = cmdl.getArguments();
- assertEquals("/C", args[0]);
- assertEquals("\"c:\\was51\\Web Sphere\\AppServer\\bin\\versionInfo.bat\"", args[1]);
- }
-
- /**
- * Create a command line with pre-quoted strings to test SANDBOX-192,
- * e.g. "runMemorySud.cmd", "10", "30", "-XX:+UseParallelGC", "\"-XX:ParallelGCThreads=2\""
- */
- @Test
- public void testComplexAddArgument() {
- final CommandLine cmdl = new CommandLine("runMemorySud.cmd");
- cmdl.addArgument("10", false);
- cmdl.addArgument("30", false);
- cmdl.addArgument("-XX:+UseParallelGC", false);
- cmdl.addArgument("\"-XX:ParallelGCThreads=2\"", false);
- assertArrayEquals(new String[]{"runMemorySud.cmd", "10", "30", "-XX:+UseParallelGC", "\"-XX:ParallelGCThreads=2\""}, cmdl.toStrings());
- }
-
- /**
- * Create a command line with pre-quoted strings to test SANDBOX-192,
- * e.g. "runMemorySud.cmd", "10", "30", "-XX:+UseParallelGC", "\"-XX:ParallelGCThreads=2\""
- */
- @Test
- public void testComplexAddArguments1() {
- final CommandLine cmdl = new CommandLine("runMemorySud.cmd");
- cmdl.addArguments(new String[] {"10", "30", "-XX:+UseParallelGC", "\"-XX:ParallelGCThreads=2\""}, false);
- assertArrayEquals(new String[]{"runMemorySud.cmd", "10", "30", "-XX:+UseParallelGC", "\"-XX:ParallelGCThreads=2\""}, cmdl.toStrings());
- }
-
- /**
- * Create a command line with pre-quoted strings to test SANDBOX-192,
- * e.g. "runMemorySud.cmd", "10", "30", "-XX:+UseParallelGC", "\"-XX:ParallelGCThreads=2\""
- * Please not that we re forced to add additional single quotes to get the test working -
- * don't know if this is a bug or a feature.
- */
- @Test
- public void testComplexAddArguments2() {
- final CommandLine cmdl = new CommandLine("runMemorySud.cmd");
- cmdl.addArguments("10 30 -XX:+UseParallelGC '\"-XX:ParallelGCThreads=2\"'", false);
- assertArrayEquals(new String[]{"runMemorySud.cmd", "10", "30", "-XX:+UseParallelGC", "\"-XX:ParallelGCThreads=2\""}, cmdl.toStrings());
- }
-
/**
* Test expanding the command line based on a user-supplied map.
*/
@@ -455,6 +280,198 @@ public class CommandLineTest {
assertEquals("C:\\Document And Settings\\documents\\432432.pdf", result[3]);
}
+
+ /**
+ * Create a command line with pre-quoted strings to test SANDBOX-192,
+ * e.g. "runMemorySud.cmd", "10", "30", "-XX:+UseParallelGC", "\"-XX:ParallelGCThreads=2\""
+ */
+ @Test
+ public void testComplexAddArgument() {
+ final CommandLine cmdl = new CommandLine("runMemorySud.cmd");
+ cmdl.addArgument("10", false);
+ cmdl.addArgument("30", false);
+ cmdl.addArgument("-XX:+UseParallelGC", false);
+ cmdl.addArgument("\"-XX:ParallelGCThreads=2\"", false);
+ assertArrayEquals(new String[]{"runMemorySud.cmd", "10", "30", "-XX:+UseParallelGC", "\"-XX:ParallelGCThreads=2\""}, cmdl.toStrings());
+ }
+
+ /**
+ * Create a command line with pre-quoted strings to test SANDBOX-192,
+ * e.g. "runMemorySud.cmd", "10", "30", "-XX:+UseParallelGC", "\"-XX:ParallelGCThreads=2\""
+ */
+ @Test
+ public void testComplexAddArguments1() {
+ final CommandLine cmdl = new CommandLine("runMemorySud.cmd");
+ cmdl.addArguments(new String[] {"10", "30", "-XX:+UseParallelGC", "\"-XX:ParallelGCThreads=2\""}, false);
+ assertArrayEquals(new String[]{"runMemorySud.cmd", "10", "30", "-XX:+UseParallelGC", "\"-XX:ParallelGCThreads=2\""}, cmdl.toStrings());
+ }
+
+ /**
+ * Create a command line with pre-quoted strings to test SANDBOX-192,
+ * e.g. "runMemorySud.cmd", "10", "30", "-XX:+UseParallelGC", "\"-XX:ParallelGCThreads=2\""
+ * Please not that we re forced to add additional single quotes to get the test working -
+ * don't know if this is a bug or a feature.
+ */
+ @Test
+ public void testComplexAddArguments2() {
+ final CommandLine cmdl = new CommandLine("runMemorySud.cmd");
+ cmdl.addArguments("10 30 -XX:+UseParallelGC '\"-XX:ParallelGCThreads=2\"'", false);
+ assertArrayEquals(new String[]{"runMemorySud.cmd", "10", "30", "-XX:+UseParallelGC", "\"-XX:ParallelGCThreads=2\""}, cmdl.toStrings());
+ }
+
+ @Test
+ public void testCopyConstructor()
+ {
+ final Map<String, String> map = new HashMap<>();
+ map.put("bar", "bar");
+ final CommandLine other = new CommandLine("test");
+ other.addArgument("foo");
+ other.setSubstitutionMap(map);
+
+ final CommandLine cmdl = new CommandLine(other);
+ assertEquals(other.getExecutable(), cmdl.getExecutable());
+ assertArrayEquals(other.getArguments(), cmdl.getArguments());
+ assertEquals(other.isFile(), cmdl.isFile());
+ assertEquals(other.getSubstitutionMap(), cmdl.getSubstitutionMap());
+
+ }
+
+ @Test
+ public void testExecutable() {
+ final CommandLine cmdl = new CommandLine("test");
+ assertEquals("[test]", cmdl.toString());
+ assertArrayEquals(new String[]{"test"}, cmdl.toStrings());
+ assertEquals("test", cmdl.getExecutable());
+ assertTrue(cmdl.getArguments().length == 0);
+ }
+
+ @Test
+ public void testExecutableWhitespaceString() {
+ try {
+ new CommandLine(" ");
+ fail("Must throw IllegalArgumentException");
+ } catch (final IllegalArgumentException e) {
+ // Expected
+ }
+ }
+
+ @Test
+ public void testExecutableZeroLengthString() {
+ try {
+ new CommandLine("");
+ fail("Must throw IllegalArgumentException");
+ } catch (final IllegalArgumentException e) {
+ // Expected
+ }
+ }
+
+ @Test
+ public void testNullExecutable() {
+ try {
+ new CommandLine((String)null);
+ fail("Must throw IllegalArgumentException");
+ } catch (final IllegalArgumentException e) {
+ // Expected
+ }
+ }
+
+ @Test
+ public void testParseCommandLine() {
+ final CommandLine cmdl = CommandLine.parse("test foo bar");
+ assertEquals("[test, foo, bar]", cmdl.toString());
+ assertArrayEquals(new String[]{"test", "foo", "bar"}, cmdl.toStrings());
+ }
+
+ @Test
+public void testParseCommandLineWithNull() {
+ try {
+ CommandLine.parse(null);
+ fail("IllegalArgumentException must be thrown due to incorrect command line");
+ } catch (final IllegalArgumentException e) {
+ // Expected
+ }
+}
+
+ @Test
+ public void testParseCommandLineWithOnlyWhitespace() {
+ try {
+ CommandLine.parse(" ");
+ fail("IllegalArgumentException must be thrown due to incorrect command line");
+ } catch (final IllegalArgumentException e) {
+ // Expected
+ }
+ }
+
+ @Test
+ public void testParseCommandLineWithQuotes() {
+ final CommandLine cmdl = CommandLine.parse("test \"foo\" \'ba r\'");
+ assertEquals("[test, foo, \"ba r\"]", cmdl.toString());
+ assertArrayEquals(new String[]{"test", "foo", "\"ba r\""}, cmdl.toStrings());
+ }
+
+ @Test
+ public void testParseCommandLineWithUnevenQuotes() {
+ try {
+ CommandLine.parse("test \"foo bar");
+ fail("IllegalArgumentException must be thrown due to uneven quotes");
+ } catch (final IllegalArgumentException e) {
+ // Expected
+ }
+ }
+
+ /**
+ * A command line parsing puzzle from Tino Schoellhorn - ImageMagix expects
+ * a "500x>" parameter (including quotes) and it is simply not possible to
+ * do that without adding a space, e.g. "500x> ".
+ */
+ @Test
+ public void testParseComplexCommandLine1() {
+ final HashMap<String, String> substitutionMap =
+ new HashMap<>();
+ substitutionMap.put("in", "source.jpg");
+ substitutionMap.put("out", "target.jpg");
+ final CommandLine cmdl = CommandLine.parse("cmd /C convert ${in} -resize \"\'500x> \'\" ${out}", substitutionMap);
+ assertEquals("[cmd, /C, convert, source.jpg, -resize, \"500x> \", target.jpg]", cmdl.toString());
+ }
+
+ /**
+ * Another command line parsing puzzle from Kai Hu - as
+ * far as I understand it there is no way to express that
+ * in a one-line command string.
+ */
+ @Test
+ public void testParseComplexCommandLine2() {
+
+ final String commandline = "./script/jrake cruise:publish_installers "
+ + "INSTALLER_VERSION=unstable_2_1 "
+ + "INSTALLER_PATH=\"/var/lib/ cruise-agent/installers\" "
+ + "INSTALLER_DOWNLOAD_SERVER=\'something\' "
+ + "WITHOUT_HELP_DOC=true";
+
+ final CommandLine cmdl = CommandLine.parse(commandline);
+ final String[] args = cmdl.getArguments();
+ assertEquals(args[0], "cruise:publish_installers");
+ assertEquals(args[1], "INSTALLER_VERSION=unstable_2_1");
+ // assertEquals(args[2], "INSTALLER_PATH=\"/var/lib/ cruise-agent/installers\"");
+ // assertEquals(args[3], "INSTALLER_DOWNLOAD_SERVER='something'");
+ assertEquals(args[4], "WITHOUT_HELP_DOC=true");
+ }
+ /**
+ * Test the following command line
+ *
+ * cmd.exe /C c:\was51\Web Sphere\AppServer\bin\versionInfo.bat
+ */
+ @Test
+ public void testParseRealLifeCommandLine_1() {
+
+ final String commandline = "cmd.exe /C \"c:\\was51\\Web Sphere\\AppServer\\bin\\versionInfo.bat\"";
+
+ final CommandLine cmdl = CommandLine.parse(commandline);
+ final String[] args = cmdl.getArguments();
+ assertEquals("/C", args[0]);
+ assertEquals("\"c:\\was51\\Web Sphere\\AppServer\\bin\\versionInfo.bat\"", args[1]);
+ }
+
/**
* Test the toString() method.
*
@@ -501,21 +518,4 @@ public class CommandLineTest {
!cmd1.toString().equals(cmd2.toString()));
}
- @Test
- public void testCopyConstructor()
- {
- final Map<String, String> map = new HashMap<>();
- map.put("bar", "bar");
- final CommandLine other = new CommandLine("test");
- other.addArgument("foo");
- other.setSubstitutionMap(map);
-
- final CommandLine cmdl = new CommandLine(other);
- assertEquals(other.getExecutable(), cmdl.getExecutable());
- assertArrayEquals(other.getArguments(), cmdl.getArguments());
- assertEquals(other.isFile(), cmdl.isFile());
- assertEquals(other.getSubstitutionMap(), cmdl.getSubstitutionMap());
-
- }
-
}
diff --git a/src/test/java/org/apache/commons/exec/DefaultExecutorTest.java b/src/test/java/org/apache/commons/exec/DefaultExecutorTest.java
index 3fc955d0..96aaac31 100644
--- a/src/test/java/org/apache/commons/exec/DefaultExecutorTest.java
+++ b/src/test/java/org/apache/commons/exec/DefaultExecutorTest.java
@@ -52,36 +52,103 @@ public class DefaultExecutorTest {
/** Maximum time to wait (15s) */
private static final int WAITFOR_TIMEOUT = 15000;
+ // Get suitable exit codes for the OS
+ private static int SUCCESS_STATUS; // test script successful exit code
+ private static int ERROR_STATUS; // test script error exit code
+ @BeforeClass
+ public static void classSetUp() {
+
+ final int[] statuses = TestUtil.getTestScriptCodesForOS();
+ SUCCESS_STATUS=statuses[0];
+ ERROR_STATUS=statuses[1];
+
+ // turn on debug mode and throw an exception for each encountered problem
+ System.setProperty("org.apache.commons.exec.lenient", "false");
+ System.setProperty("org.apache.commons.exec.debug", "true");
+ }
private final Executor exec = new DefaultExecutor();
+
private final File testDir = new File("src/test/scripts");
private final File foreverOutputFile = new File("./target/forever.txt");
private ByteArrayOutputStream baos;
-
private final File testScript = TestUtil.resolveScriptForOS(testDir + "/test");
private final File errorTestScript = TestUtil.resolveScriptForOS(testDir + "/error");
private final File foreverTestScript = TestUtil.resolveScriptForOS(testDir + "/forever");
- private final File nonExistingTestScript = TestUtil.resolveScriptForOS(testDir + "/grmpffffff");
+private final File nonExistingTestScript = TestUtil.resolveScriptForOS(testDir + "/grmpffffff");
private final File redirectScript = TestUtil.resolveScriptForOS(testDir + "/redirect");
+
private final File printArgsScript = TestUtil.resolveScriptForOS(testDir + "/printargs");
-// private final File acroRd32Script = TestUtil.resolveScriptForOS(testDir + "/acrord32");
+ // private final File acroRd32Script = TestUtil.resolveScriptForOS(testDir + "/acrord32");
private final File stdinSript = TestUtil.resolveScriptForOS(testDir + "/stdin");
+
private final File environmentSript = TestUtil.resolveScriptForOS(testDir + "/environment");
// private final File wrapperScript = TestUtil.resolveScriptForOS(testDir + "/wrapper");
- // Get suitable exit codes for the OS
- private static int SUCCESS_STATUS; // test script successful exit code
- private static int ERROR_STATUS; // test script error exit code
+ /**
+ * Start any processes in a loop to make sure that we do
+ * not leave any handles/resources open.
+ *
+ * @throws Exception the test failed
+ */
+ @Test
+ @Ignore
+ public void _testExecuteStability() throws Exception {
- @BeforeClass
- public static void classSetUp() {
+ // make a plain-vanilla test
+ for (int i = 0; i < 100; i++) {
+ final Map<String, String> env = new HashMap<>();
+ env.put("TEST_ENV_VAR", Integer.toString(i));
+ final CommandLine cl = new CommandLine(testScript);
+ final int exitValue = exec.execute(cl, env);
+ assertFalse(exec.isFailure(exitValue));
+ assertEquals("FOO." + i + ".", baos.toString().trim());
+ baos.reset();
+ }
- final int[] statuses = TestUtil.getTestScriptCodesForOS();
- SUCCESS_STATUS=statuses[0];
- ERROR_STATUS=statuses[1];
+ // now be nasty and use the watchdog to kill out sub-processes
+ for (int i = 0; i < 100; i++) {
+ final Map<String, String> env = new HashMap<>();
+ env.put("TEST_ENV_VAR", Integer.toString(i));
+ final DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();
+ final CommandLine cl = new CommandLine(foreverTestScript);
+ final ExecuteWatchdog watchdog = new ExecuteWatchdog(500);
+ exec.setWatchdog(watchdog);
+ exec.execute(cl, env, resultHandler);
+ resultHandler.waitFor(WAITFOR_TIMEOUT);
+ assertTrue("ResultHandler received a result", resultHandler.hasResult());
+ assertNotNull(resultHandler.getException());
+ baos.reset();
+ }
+ }
- // turn on debug mode and throw an exception for each encountered problem
- System.setProperty("org.apache.commons.exec.lenient", "false");
- System.setProperty("org.apache.commons.exec.debug", "true");
+ private int getOccurrences(final String data, final char c) {
+
+ int result = 0;
+
+ for (int i=0; i<data.length(); i++) {
+ if (data.charAt(i) == c) {
+ result++;
+ }
+ }
+
+ return result;
+ }
+
+ // ======================================================================
+ // Start of regression tests
+ // ======================================================================
+
+ private String readFile(final File file) throws Exception {
+
+ String text;
+ final StringBuilder contents = new StringBuilder();
+ final BufferedReader reader = new BufferedReader(new FileReader(file));
+
+ while ((text = reader.readLine()) != null) {
+ contents.append(text).append(System.getProperty("line.separator"));
+ }
+ reader.close();
+ return contents.toString();
}
@Before
@@ -104,83 +171,61 @@ public class DefaultExecutorTest {
foreverOutputFile.delete();
}
- // ======================================================================
- // Start of regression tests
- // ======================================================================
+ @Test
+ public void testAddEnvironmentVariableEmbeddedQuote() throws Exception {
+ final Map<String, String> myEnvVars = new HashMap<>(EnvironmentUtils.getProcEnvironment());
+ final String name = "NEW_VAR";
+ final String value = "NEW_\"_VAL";
+ myEnvVars.put(name, value);
+ exec.execute(new CommandLine(environmentSript), myEnvVars);
+ final String environment = baos.toString().trim();
+ assertTrue("Expecting " + name + " in " + environment, environment.indexOf(name) >= 0);
+ assertTrue("Expecting " + value + " in " + environment, environment.indexOf(value) >= 0);
+ }
/**
- * The simplest possible test - start a script and
- * check that the output was pumped into our
- * {@code ByteArrayOutputStream}.
+ * Call a script to dump the environment variables of the subprocess
+ * after adding a custom environment variable.
*
* @throws Exception the test failed
*/
@Test
- public void testExecute() throws Exception {
- final CommandLine cl = new CommandLine(testScript);
- final int exitValue = exec.execute(cl);
- assertEquals("FOO..", baos.toString().trim());
- assertFalse(exec.isFailure(exitValue));
- assertEquals(new File("."), exec.getWorkingDirectory());
- }
-
- @Test
- public void testExecuteWithWorkingDirectory() throws Exception {
- final File workingDir = new File("./target");
- final CommandLine cl = new CommandLine(testScript);
- exec.setWorkingDirectory(workingDir);
- final int exitValue = exec.execute(cl);
- assertEquals("FOO..", baos.toString().trim());
- assertFalse(exec.isFailure(exitValue));
- assertEquals(exec.getWorkingDirectory(), workingDir);
- }
-
- @Test
- public void testExecuteWithInvalidWorkingDirectory() throws Exception {
- final File workingDir = new File("/foo/bar");
- final CommandLine cl = new CommandLine(testScript);
- exec.setWorkingDirectory(workingDir);
-
- assertThrows(IOException.class, () -> exec.execute(cl));
- }
-
- @Test
- public void testExecuteWithError() throws Exception {
- final CommandLine cl = new CommandLine(errorTestScript);
-
- try{
- exec.execute(cl);
- fail("Must throw ExecuteException");
- } catch (final ExecuteException e) {
- assertTrue(exec.isFailure(e.getExitValue()));
- }
+ public void testAddEnvironmentVariables() throws Exception {
+ final Map<String, String> myEnvVars = new HashMap<>(EnvironmentUtils.getProcEnvironment());
+ myEnvVars.put("NEW_VAR", "NEW_VAL");
+ exec.execute(new CommandLine(environmentSript), myEnvVars);
+ final String environment = baos.toString().trim();
+ assertTrue("Expecting NEW_VAR in " + environment, environment.indexOf("NEW_VAR") >= 0);
+ assertTrue("Expecting NEW_VAL in " + environment, environment.indexOf("NEW_VAL") >= 0);
}
+ /**
+ * Call a script to dump the environment variables of the subprocess.
+ *
+ * @throws Exception the test failed
+ */
@Test
- public void testExecuteWithArg() throws Exception {
- final CommandLine cl = new CommandLine(testScript);
- cl.addArgument("BAR");
- final int exitValue = exec.execute(cl);
-
- assertEquals("FOO..BAR", baos.toString().trim());
- assertFalse(exec.isFailure(exitValue));
+ public void testEnvironmentVariables() throws Exception {
+ exec.execute(new CommandLine(environmentSript));
+ final String environment = baos.toString().trim();
+ assertFalse("Found no environment variables", environment.isEmpty());
+ assertFalse(environment.indexOf("NEW_VAR") >= 0);
}
/**
- * Execute the test script and pass a environment containing
- * 'TEST_ENV_VAR'.
+ * The simplest possible test - start a script and
+ * check that the output was pumped into our
+ * {@code ByteArrayOutputStream}.
+ *
+ * @throws Exception the test failed
*/
@Test
- public void testExecuteWithSingleEnvironmentVariable() throws Exception {
- final Map<String, String> env = new HashMap<>();
- env.put("TEST_ENV_VAR", "XYZ");
-
+ public void testExecute() throws Exception {
final CommandLine cl = new CommandLine(testScript);
-
- final int exitValue = exec.execute(cl, env);
-
- assertEquals("FOO.XYZ.", baos.toString().trim());
+ final int exitValue = exec.execute(cl);
+ assertEquals("FOO..", baos.toString().trim());
assertFalse(exec.isFailure(exitValue));
+ assertEquals(new File("."), exec.getWorkingDirectory());
}
/**
@@ -201,6 +246,53 @@ public class DefaultExecutorTest {
assertEquals("FOO..", baos.toString().trim());
}
+ /**
+ * Try to start an non-existing application where the exception is caught/processed
+ * by the result handler.
+ */
+ @Test
+ public void testExecuteAsyncNonExistingApplication() throws Exception {
+ final CommandLine cl = new CommandLine(nonExistingTestScript);
+ final DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();
+ final DefaultExecutor executor = new DefaultExecutor();
+
+ executor.execute(cl, resultHandler);
+ resultHandler.waitFor();
+
+ assertTrue(executor.isFailure(resultHandler.getExitValue()));
+ assertNotNull(resultHandler.getException());
+ }
+
+ /**
+ * Try to start an non-existing application where the exception is caught/processed
+ * by the result handler. The watchdog in notified to avoid waiting for the
+ * process infinitely.
+ *
+ * @see <a href="https://issues.apache.org/jira/browse/EXEC-71">EXEC-71</a>
+ */
+ @Test
+ public void testExecuteAsyncNonExistingApplicationWithWatchdog() throws Exception {
+ final CommandLine cl = new CommandLine(nonExistingTestScript);
+ final DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler() {
+ @Override
+ public void onProcessFailed(final ExecuteException e) {
+ System.out.println("Process did not stop gracefully, had exception '" + e.getMessage() + "' while executing process");
+ super.onProcessFailed(e);
+ }
+ };
+ final DefaultExecutor executor = new DefaultExecutor();
+ executor.setWatchdog(new ExecuteWatchdog(ExecuteWatchdog.INFINITE_TIMEOUT));
+
+ executor.execute(cl, resultHandler);
+ resultHandler.waitFor();
+
+ assertTrue(executor.isFailure(resultHandler.getExitValue()));
+ assertNotNull(resultHandler.getException());
+ assertFalse(executor.getWatchdog().isWatching());
+ assertFalse(executor.getWatchdog().killedProcess());
+ executor.getWatchdog().destroyProcess();
+ }
+
/**
* Start a asynchronous process which returns an error
* exit value.
@@ -219,6 +311,47 @@ public class DefaultExecutorTest {
assertEquals("FOO..", baos.toString().trim());
}
+ /**
+ * Test the proper handling of ProcessDestroyer for an asynchronous process.
+ * Since we do not terminate the process it will be terminated in the
+ * ShutdownHookProcessDestroyer implementation.
+ *
+ * @throws Exception the test failed
+ */
+ @Test
+ public void testExecuteAsyncWithProcessDestroyer() throws Exception {
+
+ final CommandLine cl = new CommandLine(foreverTestScript);
+ final DefaultExecuteResultHandler handler = new DefaultExecuteResultHandler();
+ final ShutdownHookProcessDestroyer processDestroyer = new ShutdownHookProcessDestroyer();
+ final ExecuteWatchdog watchdog = new ExecuteWatchdog(Integer.MAX_VALUE);
+
+ assertNull(exec.getProcessDestroyer());
+ assertTrue(processDestroyer.isEmpty());
+ assertFalse(processDestroyer.isAddedAsShutdownHook());
+
+ exec.setWatchdog(watchdog);
+ exec.setProcessDestroyer(processDestroyer);
+ exec.execute(cl, handler);
+
+ // wait for script to start
+ Thread.sleep(2000);
+
+ // our process destroyer should be initialized now
+ assertNotNull("Process destroyer should exist", exec.getProcessDestroyer());
+ assertEquals("Process destroyer size should be 1", 1, processDestroyer.size());
+ assertTrue("Process destroyer should exist as shutdown hook", processDestroyer.isAddedAsShutdownHook());
+
+ // terminate it and the process destroyer is detached
+ watchdog.destroyProcess();
+ assertTrue(watchdog.killedProcess());
+ handler.waitFor(WAITFOR_TIMEOUT);
+ assertTrue("ResultHandler received a result", handler.hasResult());
+ assertNotNull(handler.getException());
+ assertEquals("Processor Destroyer size should be 0", 0, processDestroyer.size());
+ assertFalse("Process destroyer should not exist as shutdown hook", processDestroyer.isAddedAsShutdownHook());
+ }
+
/**
* Start a asynchronous process and terminate it manually before the
* watchdog timeout occurs.
@@ -272,6 +405,62 @@ public class DefaultExecutorTest {
assertNotNull("ResultHandler received an exception as result", handler.getException());
}
+ /**
+ * Try to start an non-existing application which should result
+ * in an exception.
+ */
+ @Test
+ public void testExecuteNonExistingApplication() throws Exception {
+ final CommandLine cl = new CommandLine(nonExistingTestScript);
+ final DefaultExecutor executor = new DefaultExecutor();
+
+ assertThrows(IOException.class, () -> executor.execute(cl));
+ }
+
+ /**
+ * Try to start an non-existing application which should result
+ * in an exception.
+ */
+ @Test
+ public void testExecuteNonExistingApplicationWithWatchDog() throws Exception {
+ final CommandLine cl = new CommandLine(nonExistingTestScript);
+ final DefaultExecutor executor = new DefaultExecutor();
+ executor.setWatchdog(new ExecuteWatchdog(ExecuteWatchdog.INFINITE_TIMEOUT));
+
+ assertThrows(IOException.class, () -> executor.execute(cl));
+ }
+
+ /**
+ * Start a script looping forever (asynchronously) and check if the
+ * ExecuteWatchdog kicks in killing the run away process. To make killing
+ * a process more testable the "forever" scripts write each second a '.'
+ * into "./target/forever.txt" (a marker file). After a test run
+ * we should have a few dots in there.
+ *
+ * @throws Exception the test failed
+ */
+ @Test
+ public void testExecuteWatchdogAsync() throws Exception {
+
+ final long timeout = 10000;
+
+ final CommandLine cl = new CommandLine(foreverTestScript);
+ final DefaultExecuteResultHandler handler = new DefaultExecuteResultHandler();
+ final DefaultExecutor executor = new DefaultExecutor();
+ executor.setWorkingDirectory(new File("."));
+ executor.setWatchdog(new ExecuteWatchdog(timeout));
+
+ executor.execute(cl, handler);
+ handler.waitFor(WAITFOR_TIMEOUT);
+
+ assertTrue("Killed process should be true", executor.getWatchdog().killedProcess() );
+ assertTrue("ResultHandler received a result", handler.hasResult());
+ assertNotNull("ResultHandler received an exception as result", handler.getException());
+
+ final int nrOfInvocations = getOccurrences(readFile(this.foreverOutputFile), '.');
+ assertTrue("Killing the process did not work : " + nrOfInvocations, nrOfInvocations > 5 && nrOfInvocations <= 11);
+ }
+
/**
* Start a script looping forever (synchronously) and check if the ExecuteWatchdog
* kicks in killing the run away process. To make killing a process
@@ -317,37 +506,6 @@ public class DefaultExecutorTest {
fail("Process did not create ExecuteException when killed");
}
- /**
- * Start a script looping forever (asynchronously) and check if the
- * ExecuteWatchdog kicks in killing the run away process. To make killing
- * a process more testable the "forever" scripts write each second a '.'
- * into "./target/forever.txt" (a marker file). After a test run
- * we should have a few dots in there.
- *
- * @throws Exception the test failed
- */
- @Test
- public void testExecuteWatchdogAsync() throws Exception {
-
- final long timeout = 10000;
-
- final CommandLine cl = new CommandLine(foreverTestScript);
- final DefaultExecuteResultHandler handler = new DefaultExecuteResultHandler();
- final DefaultExecutor executor = new DefaultExecutor();
- executor.setWorkingDirectory(new File("."));
- executor.setWatchdog(new ExecuteWatchdog(timeout));
-
- executor.execute(cl, handler);
- handler.waitFor(WAITFOR_TIMEOUT);
-
- assertTrue("Killed process should be true", executor.getWatchdog().killedProcess() );
- assertTrue("ResultHandler received a result", handler.hasResult());
- assertNotNull("ResultHandler received an exception as result", handler.getException());
-
- final int nrOfInvocations = getOccurrences(readFile(this.foreverOutputFile), '.');
- assertTrue("Killing the process did not work : " + nrOfInvocations, nrOfInvocations > 5 && nrOfInvocations <= 11);
- }
-
/**
* [EXEC-68] Synchronously starts a short script with a Watchdog attached with an extremely large timeout. Checks
* to see if the script terminated naturally or if it was killed by the Watchdog. Fail if killed by Watchdog.
@@ -374,77 +532,31 @@ public class DefaultExecutorTest {
}
}
- /**
- * Try to start an non-existing application which should result
- * in an exception.
- */
- @Test
- public void testExecuteNonExistingApplication() throws Exception {
- final CommandLine cl = new CommandLine(nonExistingTestScript);
- final DefaultExecutor executor = new DefaultExecutor();
-
- assertThrows(IOException.class, () -> executor.execute(cl));
- }
-
- /**
- * Try to start an non-existing application which should result
- * in an exception.
- */
@Test
- public void testExecuteNonExistingApplicationWithWatchDog() throws Exception {
- final CommandLine cl = new CommandLine(nonExistingTestScript);
- final DefaultExecutor executor = new DefaultExecutor();
- executor.setWatchdog(new ExecuteWatchdog(ExecuteWatchdog.INFINITE_TIMEOUT));
-
- assertThrows(IOException.class, () -> executor.execute(cl));
- }
-
- /**
- * Try to start an non-existing application where the exception is caught/processed
- * by the result handler.
- */
- @Test
- public void testExecuteAsyncNonExistingApplication() throws Exception {
- final CommandLine cl = new CommandLine(nonExistingTestScript);
- final DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();
- final DefaultExecutor executor = new DefaultExecutor();
-
- executor.execute(cl, resultHandler);
- resultHandler.waitFor();
+ public void testExecuteWithArg() throws Exception {
+ final CommandLine cl = new CommandLine(testScript);
+ cl.addArgument("BAR");
+ final int exitValue = exec.execute(cl);
- assertTrue(executor.isFailure(resultHandler.getExitValue()));
- assertNotNull(resultHandler.getException());
+ assertEquals("FOO..BAR", baos.toString().trim());
+ assertFalse(exec.isFailure(exitValue));
}
/**
- * Try to start an non-existing application where the exception is caught/processed
- * by the result handler. The watchdog in notified to avoid waiting for the
- * process infinitely.
+ * A generic test case to print the command line arguments to 'printargs' script to solve
+ * even more command line puzzles.
*
- * @see <a href="https://issues.apache.org/jira/browse/EXEC-71">EXEC-71</a>
+ * @throws Exception the test failed
*/
@Test
- public void testExecuteAsyncNonExistingApplicationWithWatchdog() throws Exception {
- final CommandLine cl = new CommandLine(nonExistingTestScript);
- final DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler() {
- @Override
- public void onProcessFailed(final ExecuteException e) {
- System.out.println("Process did not stop gracefully, had exception '" + e.getMessage() + "' while executing process");
- super.onProcessFailed(e);
- }
- };
+ public void testExecuteWithComplexArguments() throws Exception {
+ final CommandLine cl = new CommandLine(printArgsScript);
+ cl.addArgument("gdal_translate");
+ cl.addArgument("HDF5:\"/home/kk/grass/data/4404.he5\"://HDFEOS/GRIDS/OMI_Column_Amount_O3/Data_Fields/ColumnAmountO3/home/kk/4.tif", false);
final DefaultExecutor executor = new DefaultExecutor();
- executor.setWatchdog(new ExecuteWatchdog(ExecuteWatchdog.INFINITE_TIMEOUT));
-
- executor.execute(cl, resultHandler);
- resultHandler.waitFor();
-
- assertTrue(executor.isFailure(resultHandler.getExitValue()));
- assertNotNull(resultHandler.getException());
- assertFalse(executor.getWatchdog().isWatching());
- assertFalse(executor.getWatchdog().killedProcess());
- executor.getWatchdog().destroyProcess();
- }
+ final int exitValue = executor.execute(cl);
+ assertFalse(exec.isFailure(exitValue));
+ }
/**
* Invoke the error script but define that the ERROR_STATUS is a good
@@ -477,6 +589,57 @@ public class DefaultExecutorTest {
}
}
+ @Test
+ public void testExecuteWithError() throws Exception {
+ final CommandLine cl = new CommandLine(errorTestScript);
+
+ try{
+ exec.execute(cl);
+ fail("Must throw ExecuteException");
+ } catch (final ExecuteException e) {
+ assertTrue(exec.isFailure(e.getExitValue()));
+ }
+ }
+
+ /**
+ * Invoke the test using some fancy arguments.
+ *
+ * @throws Exception the test failed
+ */
+ @Test
+ public void testExecuteWithFancyArg() throws Exception {
+ final CommandLine cl = new CommandLine(testScript);
+ cl.addArgument("test $;`(0)[1]{2}");
+ final int exitValue = exec.execute(cl);
+ assertTrue(baos.toString().trim().indexOf("test $;`(0)[1]{2}") > 0);
+ assertFalse(exec.isFailure(exitValue));
+ }
+
+ @Test
+ public void testExecuteWithInvalidWorkingDirectory() throws Exception {
+ final File workingDir = new File("/foo/bar");
+ final CommandLine cl = new CommandLine(testScript);
+ exec.setWorkingDirectory(workingDir);
+
+ assertThrows(IOException.class, () -> exec.execute(cl));
+ }
+
+ /**
+ * Start a process and connect it to no stream.
+ *
+ * @throws Exception
+ * the test failed
+ */
+ @Test
+ public void testExecuteWithNullOutErr() throws Exception {
+ final CommandLine cl = new CommandLine(testScript);
+ final PumpStreamHandler pumpStreamHandler = new PumpStreamHandler(null, null);
+ final DefaultExecutor executor = new DefaultExecutor();
+ executor.setStreamHandler(pumpStreamHandler);
+ final int exitValue = executor.execute(cl);
+ assertFalse(exec.isFailure(exitValue));
+ }
+
/**
* Test the proper handling of ProcessDestroyer for an synchronous process.
*
@@ -500,61 +663,6 @@ public class DefaultExecutorTest {
assertFalse(processDestroyer.isAddedAsShutdownHook());
}
- /**
- * Test the proper handling of ProcessDestroyer for an asynchronous process.
- * Since we do not terminate the process it will be terminated in the
- * ShutdownHookProcessDestroyer implementation.
- *
- * @throws Exception the test failed
- */
- @Test
- public void testExecuteAsyncWithProcessDestroyer() throws Exception {
-
- final CommandLine cl = new CommandLine(foreverTestScript);
- final DefaultExecuteResultHandler handler = new DefaultExecuteResultHandler();
- final ShutdownHookProcessDestroyer processDestroyer = new ShutdownHookProcessDestroyer();
- final ExecuteWatchdog watchdog = new ExecuteWatchdog(Integer.MAX_VALUE);
-
- assertNull(exec.getProcessDestroyer());
- assertTrue(processDestroyer.isEmpty());
- assertFalse(processDestroyer.isAddedAsShutdownHook());
-
- exec.setWatchdog(watchdog);
- exec.setProcessDestroyer(processDestroyer);
- exec.execute(cl, handler);
-
- // wait for script to start
- Thread.sleep(2000);
-
- // our process destroyer should be initialized now
- assertNotNull("Process destroyer should exist", exec.getProcessDestroyer());
- assertEquals("Process destroyer size should be 1", 1, processDestroyer.size());
- assertTrue("Process destroyer should exist as shutdown hook", processDestroyer.isAddedAsShutdownHook());
-
- // terminate it and the process destroyer is detached
- watchdog.destroyProcess();
- assertTrue(watchdog.killedProcess());
- handler.waitFor(WAITFOR_TIMEOUT);
- assertTrue("ResultHandler received a result", handler.hasResult());
- assertNotNull(handler.getException());
- assertEquals("Processor Destroyer size should be 0", 0, processDestroyer.size());
- assertFalse("Process destroyer should not exist as shutdown hook", processDestroyer.isAddedAsShutdownHook());
- }
-
- /**
- * Invoke the test using some fancy arguments.
- *
- * @throws Exception the test failed
- */
- @Test
- public void testExecuteWithFancyArg() throws Exception {
- final CommandLine cl = new CommandLine(testScript);
- cl.addArgument("test $;`(0)[1]{2}");
- final int exitValue = exec.execute(cl);
- assertTrue(baos.toString().trim().indexOf("test $;`(0)[1]{2}") > 0);
- assertFalse(exec.isFailure(exitValue));
- }
-
/**
* Start a process with redirected streams - stdin of the newly
* created process is connected to a FileInputStream whereas
@@ -588,38 +696,7 @@ public class DefaultExecutorTest {
}
}
- /**
- * Start a process and connect stdout and stderr.
- *
- * @throws Exception the test failed
- */
- @Test
- public void testExecuteWithStdOutErr() throws Exception {
- final CommandLine cl = new CommandLine(testScript);
- final PumpStreamHandler pumpStreamHandler = new PumpStreamHandler(System.out, System.err);
- final DefaultExecutor executor = new DefaultExecutor();
- executor.setStreamHandler(pumpStreamHandler);
- final int exitValue = executor.execute(cl);
- assertFalse(exec.isFailure(exitValue));
- }
-
/**
- * Start a process and connect it to no stream.
- *
- * @throws Exception
- * the test failed
- */
- @Test
- public void testExecuteWithNullOutErr() throws Exception {
- final CommandLine cl = new CommandLine(testScript);
- final PumpStreamHandler pumpStreamHandler = new PumpStreamHandler(null, null);
- final DefaultExecutor executor = new DefaultExecutor();
- executor.setStreamHandler(pumpStreamHandler);
- final int exitValue = executor.execute(cl);
- assertFalse(exec.isFailure(exitValue));
- }
-
- /**
* Start a process and connect out and err to a file.
*
* @throws Exception the test failed
@@ -641,20 +718,55 @@ public class DefaultExecutorTest {
}
/**
- * A generic test case to print the command line arguments to 'printargs' script to solve
- * even more command line puzzles.
- *
- * @throws Exception the test failed
+ * Execute the test script and pass a environment containing
+ * 'TEST_ENV_VAR'.
*/
@Test
- public void testExecuteWithComplexArguments() throws Exception {
- final CommandLine cl = new CommandLine(printArgsScript);
- cl.addArgument("gdal_translate");
- cl.addArgument("HDF5:\"/home/kk/grass/data/4404.he5\"://HDFEOS/GRIDS/OMI_Column_Amount_O3/Data_Fields/ColumnAmountO3/home/kk/4.tif", false);
+ public void testExecuteWithSingleEnvironmentVariable() throws Exception {
+ final Map<String, String> env = new HashMap<>();
+ env.put("TEST_ENV_VAR", "XYZ");
+
+ final CommandLine cl = new CommandLine(testScript);
+
+ final int exitValue = exec.execute(cl, env);
+
+ assertEquals("FOO.XYZ.", baos.toString().trim());
+ assertFalse(exec.isFailure(exitValue));
+ }
+
+ // ======================================================================
+ // === Long running tests
+ // ======================================================================
+
+ /**
+ * Start a process and connect stdout and stderr.
+ *
+ * @throws Exception the test failed
+ */
+ @Test
+ public void testExecuteWithStdOutErr() throws Exception {
+ final CommandLine cl = new CommandLine(testScript);
+ final PumpStreamHandler pumpStreamHandler = new PumpStreamHandler(System.out, System.err);
final DefaultExecutor executor = new DefaultExecutor();
+ executor.setStreamHandler(pumpStreamHandler);
final int exitValue = executor.execute(cl);
assertFalse(exec.isFailure(exitValue));
- }
+ }
+
+ // ======================================================================
+ // === Helper methods
+ // ======================================================================
+
+ @Test
+ public void testExecuteWithWorkingDirectory() throws Exception {
+ final File workingDir = new File("./target");
+ final CommandLine cl = new CommandLine(testScript);
+ exec.setWorkingDirectory(workingDir);
+ final int exitValue = exec.execute(cl);
+ assertEquals("FOO..", baos.toString().trim());
+ assertFalse(exec.isFailure(exitValue));
+ assertEquals(exec.getWorkingDirectory(), workingDir);
+ }
/**
* The test script reads an argument from {@code stdin} and prints
@@ -681,116 +793,4 @@ public class DefaultExecutorTest {
final String result = baos.toString();
assertTrue("Result '" + result + "' should contain 'Hello Foo!'", result.indexOf("Hello Foo!") >= 0);
}
-
- /**
- * Call a script to dump the environment variables of the subprocess.
- *
- * @throws Exception the test failed
- */
- @Test
- public void testEnvironmentVariables() throws Exception {
- exec.execute(new CommandLine(environmentSript));
- final String environment = baos.toString().trim();
- assertFalse("Found no environment variables", environment.isEmpty());
- assertFalse(environment.indexOf("NEW_VAR") >= 0);
- }
-
- /**
- * Call a script to dump the environment variables of the subprocess
- * after adding a custom environment variable.
- *
- * @throws Exception the test failed
- */
- @Test
- public void testAddEnvironmentVariables() throws Exception {
- final Map<String, String> myEnvVars = new HashMap<>(EnvironmentUtils.getProcEnvironment());
- myEnvVars.put("NEW_VAR", "NEW_VAL");
- exec.execute(new CommandLine(environmentSript), myEnvVars);
- final String environment = baos.toString().trim();
- assertTrue("Expecting NEW_VAR in " + environment, environment.indexOf("NEW_VAR") >= 0);
- assertTrue("Expecting NEW_VAL in " + environment, environment.indexOf("NEW_VAL") >= 0);
- }
-
- @Test
- public void testAddEnvironmentVariableEmbeddedQuote() throws Exception {
- final Map<String, String> myEnvVars = new HashMap<>(EnvironmentUtils.getProcEnvironment());
- final String name = "NEW_VAR";
- final String value = "NEW_\"_VAL";
- myEnvVars.put(name, value);
- exec.execute(new CommandLine(environmentSript), myEnvVars);
- final String environment = baos.toString().trim();
- assertTrue("Expecting " + name + " in " + environment, environment.indexOf(name) >= 0);
- assertTrue("Expecting " + value + " in " + environment, environment.indexOf(value) >= 0);
- }
-
- // ======================================================================
- // === Long running tests
- // ======================================================================
-
- /**
- * Start any processes in a loop to make sure that we do
- * not leave any handles/resources open.
- *
- * @throws Exception the test failed
- */
- @Test
- @Ignore
- public void _testExecuteStability() throws Exception {
-
- // make a plain-vanilla test
- for (int i = 0; i < 100; i++) {
- final Map<String, String> env = new HashMap<>();
- env.put("TEST_ENV_VAR", Integer.toString(i));
- final CommandLine cl = new CommandLine(testScript);
- final int exitValue = exec.execute(cl, env);
- assertFalse(exec.isFailure(exitValue));
- assertEquals("FOO." + i + ".", baos.toString().trim());
- baos.reset();
- }
-
- // now be nasty and use the watchdog to kill out sub-processes
- for (int i = 0; i < 100; i++) {
- final Map<String, String> env = new HashMap<>();
- env.put("TEST_ENV_VAR", Integer.toString(i));
- final DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler();
- final CommandLine cl = new CommandLine(foreverTestScript);
- final ExecuteWatchdog watchdog = new ExecuteWatchdog(500);
- exec.setWatchdog(watchdog);
- exec.execute(cl, env, resultHandler);
- resultHandler.waitFor(WAITFOR_TIMEOUT);
- assertTrue("ResultHandler received a result", resultHandler.hasResult());
- assertNotNull(resultHandler.getException());
- baos.reset();
- }
- }
-
- // ======================================================================
- // === Helper methods
- // ======================================================================
-
- private String readFile(final File file) throws Exception {
-
- String text;
- final StringBuilder contents = new StringBuilder();
- final BufferedReader reader = new BufferedReader(new FileReader(file));
-
- while ((text = reader.readLine()) != null) {
- contents.append(text).append(System.getProperty("line.separator"));
- }
- reader.close();
- return contents.toString();
- }
-
- private int getOccurrences(final String data, final char c) {
-
- int result = 0;
-
- for (int i=0; i<data.length(); i++) {
- if (data.charAt(i) == c) {
- result++;
- }
- }
-
- return result;
- }
}
diff --git a/src/test/java/org/apache/commons/exec/LogOutputStreamTest.java b/src/test/java/org/apache/commons/exec/LogOutputStreamTest.java
index e5c6fd9d..74596570 100644
--- a/src/test/java/org/apache/commons/exec/LogOutputStreamTest.java
+++ b/src/test/java/org/apache/commons/exec/LogOutputStreamTest.java
@@ -35,24 +35,51 @@ import org.junit.Test;
*/
public class LogOutputStreamTest {
- private final Executor exec = new DefaultExecutor();
- private final File testDir = new File("src/test/scripts");
- private OutputStream systemOut;
- private final File environmentScript = TestUtil.resolveScriptForOS(testDir + "/environment");
- private final File utf8CharacterScript = TestUtil.resolveScriptForOS(testDir + "/utf8Characters");
+ private final class SystemLogOutputStream extends LogOutputStream {
+
+ StringBuffer output = new StringBuffer();
+
+ private SystemLogOutputStream(final int level) {
+ super(level);
+ }
+
+ private SystemLogOutputStream(final int level, final Charset charset) {
+ super(level, charset);
+ }
+
+ private String getOutput() {
+ return output.toString();
+ }
+ @Override
+ protected void processLine(final String line, final int level) {
+ System.out.println(line);
+ output.append(line);
+ }
+ }
@BeforeClass
public static void classSetUp() {
// turn on debug mode and throw an exception for each encountered problem
System.setProperty("org.apache.commons.exec.lenient", "false");
System.setProperty("org.apache.commons.exec.debug", "true");
}
+ private final Executor exec = new DefaultExecutor();
+ private final File testDir = new File("src/test/scripts");
+ private OutputStream systemOut;
+
+ private final File environmentScript = TestUtil.resolveScriptForOS(testDir + "/environment");
+
+ private final File utf8CharacterScript = TestUtil.resolveScriptForOS(testDir + "/utf8Characters");
@Before
public void setUp() throws Exception {
}
+ // ======================================================================
+ // Start of regression tests
+ // ======================================================================
+
@After
public void tearDown() throws Exception {
if (this.systemOut != null) {
@@ -60,10 +87,6 @@ public class LogOutputStreamTest {
}
}
- // ======================================================================
- // Start of regression tests
- // ======================================================================
-
@Test
public void testStdout() throws Exception {
this.systemOut = new SystemLogOutputStream(1);
@@ -74,6 +97,10 @@ public class LogOutputStreamTest {
assertFalse(exec.isFailure(exitValue));
}
+ // ======================================================================
+ // Helper classes
+ // ======================================================================
+
@Test
@Ignore("The file utf8CharacterScript is missing from the repository and is not in its history")
public void testStdoutWithUTF8Characters() throws Exception {
@@ -86,31 +113,4 @@ public class LogOutputStreamTest {
assertEquals("This string contains UTF-8 characters like the see no evil monkey \uD83D\uDE48 and the right single quotation mark \u2019", ((SystemLogOutputStream) systemOut).getOutput());
}
- // ======================================================================
- // Helper classes
- // ======================================================================
-
- private final class SystemLogOutputStream extends LogOutputStream {
-
- StringBuffer output = new StringBuffer();
-
- private SystemLogOutputStream(final int level) {
- super(level);
- }
-
- private SystemLogOutputStream(final int level, final Charset charset) {
- super(level, charset);
- }
-
- @Override
- protected void processLine(final String line, final int level) {
- System.out.println(line);
- output.append(line);
- }
-
- private String getOutput() {
- return output.toString();
- }
- }
-
}
diff --git a/src/test/java/org/apache/commons/exec/TestUtil.java b/src/test/java/org/apache/commons/exec/TestUtil.java
index ec168563..024e8a2e 100644
--- a/src/test/java/org/apache/commons/exec/TestUtil.java
+++ b/src/test/java/org/apache/commons/exec/TestUtil.java
@@ -25,37 +25,37 @@ import junit.framework.AssertionFailedError;
*/
public final class TestUtil {
- private TestUtil() {
- }
-
- public static File resolveScriptForOS(final String script) {
+ /**
+ * Gets success and fail return codes used by the test scripts
+ * @return int array[2] = {ok, success}
+ */
+ public static int[] getTestScriptCodesForOS() {
if (OS.isFamilyWindows()) {
- return new File(script + ".bat");
+ return new int[]{0,1};
}
if (OS.isFamilyUnix()) {
- return new File(script + ".sh");
+ return new int[]{0,1};
}
if (OS.isFamilyOpenVms()) {
- return new File(script + ".dcl");
+ return new int[]{1,2};
}
throw new AssertionFailedError("Test not supported for this OS");
}
- /**
- * Gets success and fail return codes used by the test scripts
- * @return int array[2] = {ok, success}
- */
- public static int[] getTestScriptCodesForOS() {
+ public static File resolveScriptForOS(final String script) {
if (OS.isFamilyWindows()) {
- return new int[]{0,1};
+ return new File(script + ".bat");
}
if (OS.isFamilyUnix()) {
- return new int[]{0,1};
+ return new File(script + ".sh");
}
if (OS.isFamilyOpenVms()) {
- return new int[]{1,2};
+ return new File(script + ".dcl");
}
throw new AssertionFailedError("Test not supported for this OS");
}
+ private TestUtil() {
+ }
+
}
diff --git a/src/test/java/org/apache/commons/exec/TutorialTest.java b/src/test/java/org/apache/commons/exec/TutorialTest.java
index 7961bf95..b36f157e 100644
--- a/src/test/java/org/apache/commons/exec/TutorialTest.java
+++ b/src/test/java/org/apache/commons/exec/TutorialTest.java
@@ -36,39 +36,43 @@ import org.junit.Test;
*/
public class TutorialTest {
- /** the directory to pick up the test scripts */
- private final File testDir = new File("src/test/scripts");
-
- /** simulates a PDF print job */
- private final File acroRd32Script = TestUtil.resolveScriptForOS(testDir + "/acrord32");
-
- @Test
- public void testTutorialExample() throws Exception {
+ private final class PrintResultHandler extends DefaultExecuteResultHandler {
- final long printJobTimeout = 15000;
- final boolean printInBackground = false;
- final File pdfFile = new File("/Documents and Settings/foo.pdf");
+ private ExecuteWatchdog watchdog;
- PrintResultHandler printResult;
+ public PrintResultHandler(final ExecuteWatchdog watchdog)
+ {
+ this.watchdog = watchdog;
+ }
- try {
- // printing takes around 10 seconds
- System.out.println("[main] Preparing print job ...");
- printResult = print(pdfFile, printJobTimeout, printInBackground);
- System.out.println("[main] Successfully sent the print job ...");
+ public PrintResultHandler(final int exitValue) {
+ super.onProcessComplete(exitValue);
}
- catch (final Exception e) {
- e.printStackTrace();
- fail("[main] Printing of the following document failed : " + pdfFile.getAbsolutePath());
- throw e;
+
+ @Override
+ public void onProcessComplete(final int exitValue) {
+ super.onProcessComplete(exitValue);
+ System.out.println("[resultHandler] The document was successfully printed ...");
}
- // come back to check the print result
- System.out.println("[main] Test is exiting but waiting for the print job to finish...");
- printResult.waitFor();
- System.out.println("[main] The print job has finished ...");
+ @Override
+ public void onProcessFailed(final ExecuteException e) {
+ super.onProcessFailed(e);
+ if (watchdog != null && watchdog.killedProcess()) {
+ System.err.println("[resultHandler] The print process timed out");
+ }
+ else {
+ System.err.println("[resultHandler] The print process failed to do : " + e.getMessage());
+ }
+ }
}
+ /** the directory to pick up the test scripts */
+ private final File testDir = new File("src/test/scripts");
+
+ /** simulates a PDF print job */
+ private final File acroRd32Script = TestUtil.resolveScriptForOS(testDir + "/acrord32");
+
/**
* Simulate printing a PDF document.
*
@@ -119,34 +123,30 @@ public class TutorialTest {
return resultHandler;
}
- private final class PrintResultHandler extends DefaultExecuteResultHandler {
+ @Test
+ public void testTutorialExample() throws Exception {
- private ExecuteWatchdog watchdog;
+ final long printJobTimeout = 15000;
+ final boolean printInBackground = false;
+ final File pdfFile = new File("/Documents and Settings/foo.pdf");
- public PrintResultHandler(final ExecuteWatchdog watchdog)
- {
- this.watchdog = watchdog;
- }
+ PrintResultHandler printResult;
- public PrintResultHandler(final int exitValue) {
- super.onProcessComplete(exitValue);
+ try {
+ // printing takes around 10 seconds
+ System.out.println("[main] Preparing print job ...");
+ printResult = print(pdfFile, printJobTimeout, printInBackground);
+ System.out.println("[main] Successfully sent the print job ...");
}
-
- @Override
- public void onProcessComplete(final int exitValue) {
- super.onProcessComplete(exitValue);
- System.out.println("[resultHandler] The document was successfully printed ...");
+ catch (final Exception e) {
+ e.printStackTrace();
+ fail("[main] Printing of the following document failed : " + pdfFile.getAbsolutePath());
+ throw e;
}
- @Override
- public void onProcessFailed(final ExecuteException e) {
- super.onProcessFailed(e);
- if (watchdog != null && watchdog.killedProcess()) {
- System.err.println("[resultHandler] The print process timed out");
- }
- else {
- System.err.println("[resultHandler] The print process failed to do : " + e.getMessage());
- }
- }
+ // come back to check the print result
+ System.out.println("[main] Test is exiting but waiting for the print job to finish...");
+ printResult.waitFor();
+ System.out.println("[main] The print job has finished ...");
}
}
\ No newline at end of file
diff --git a/src/test/java/org/apache/commons/exec/environment/EnvironmentUtilsTest.java b/src/test/java/org/apache/commons/exec/environment/EnvironmentUtilsTest.java
index d45ef9fe..8ba06401 100644
--- a/src/test/java/org/apache/commons/exec/environment/EnvironmentUtilsTest.java
+++ b/src/test/java/org/apache/commons/exec/environment/EnvironmentUtilsTest.java
@@ -38,24 +38,19 @@ import org.junit.Test;
public class EnvironmentUtilsTest {
/**
- * Tests the behavior of the EnvironmentUtils.toStrings()
- * when using a {@code null} environment.
+ * Accessing environment variables is case-sensitive or not depending
+ * on the operating system but the values of the environment variable
+ * are always case-sensitive. So make sure that this assumption holds
+ * on all operating systems.
+ *
+ * @throws Exception the test failed
*/
@Test
- public void testToStrings() {
- // check for a non-existing environment when passing null
- assertNull(EnvironmentUtils.toStrings(null));
- // check for an environment when filling in two variables
- final Map<String, String> env = new HashMap<>();
- assertArrayEquals(new String[0], EnvironmentUtils.toStrings(env));
- env.put("foo2", "bar2");
- env.put("foo", "bar");
- final String[] envStrings = EnvironmentUtils.toStrings(env);
- final String[] expected = {"foo2=bar2", "foo=bar"};
- // ensure the result does not depend on the hash ordering
- Arrays.sort(expected);
- Arrays.sort(envStrings);
- assertArrayEquals(expected, envStrings);
+ public void testCaseInsensitiveVariableLookup() throws Exception {
+ final Map<String, String> procEnvironment = EnvironmentUtils.getProcEnvironment();
+ // Check that case is preserved for values
+ EnvironmentUtils.addVariableToEnvironment(procEnvironment, "foo=bAr");
+ assertEquals("bAr", procEnvironment.get("foo"));
}
/**
@@ -110,19 +105,24 @@ public class EnvironmentUtilsTest {
}
/**
- * Accessing environment variables is case-sensitive or not depending
- * on the operating system but the values of the environment variable
- * are always case-sensitive. So make sure that this assumption holds
- * on all operating systems.
- *
- * @throws Exception the test failed
+ * Tests the behavior of the EnvironmentUtils.toStrings()
+ * when using a {@code null} environment.
*/
@Test
- public void testCaseInsensitiveVariableLookup() throws Exception {
- final Map<String, String> procEnvironment = EnvironmentUtils.getProcEnvironment();
- // Check that case is preserved for values
- EnvironmentUtils.addVariableToEnvironment(procEnvironment, "foo=bAr");
- assertEquals("bAr", procEnvironment.get("foo"));
+ public void testToStrings() {
+ // check for a non-existing environment when passing null
+ assertNull(EnvironmentUtils.toStrings(null));
+ // check for an environment when filling in two variables
+ final Map<String, String> env = new HashMap<>();
+ assertArrayEquals(new String[0], EnvironmentUtils.toStrings(env));
+ env.put("foo2", "bar2");
+ env.put("foo", "bar");
+ final String[] envStrings = EnvironmentUtils.toStrings(env);
+ final String[] expected = {"foo2=bar2", "foo=bar"};
+ // ensure the result does not depend on the hash ordering
+ Arrays.sort(expected);
+ Arrays.sort(envStrings);
+ assertArrayEquals(expected, envStrings);
}
/**
diff --git a/src/test/java/org/apache/commons/exec/issues/Exec36Test.java b/src/test/java/org/apache/commons/exec/issues/Exec36Test.java
index 104ad380..ccd9083c 100644
--- a/src/test/java/org/apache/commons/exec/issues/Exec36Test.java
+++ b/src/test/java/org/apache/commons/exec/issues/Exec36Test.java
@@ -47,6 +47,72 @@ public class Exec36Test {
private ByteArrayOutputStream baos;
+ /**
+ * Some complex real-life command line from
+ * http://blogs.msdn.com/b/astebner/archive/2005/12/13/503471.aspx
+ */
+ @Test
+ @Ignore
+ public void _testExec36_4() throws Exception {
+
+ CommandLine cmdl;
+
+ final String line = "./script/jrake "
+ + "cruise:publish_installers "
+ + "INSTALLER_VERSION=unstable_2_1 "
+ + "INSTALLER_PATH=\"/var/lib/cruise-agent/installers\" "
+ + "INSTALLER_DOWNLOAD_SERVER='something'"
+ + "WITHOUT_HELP_DOC=true";
+
+ cmdl = CommandLine.parse(line);
+ final String[] args = cmdl.toStrings();
+ assertEquals("./script/jrake", args[0]);
+ assertEquals("cruise:publish_installers", args[1]);
+ assertEquals("INSTALLER_VERSION=unstable_2_1", args[2]);
+ assertEquals("INSTALLER_PATH=\"/var/lib/cruise-agent/installers\"", args[3]);
+ assertEquals("INSTALLER_DOWNLOAD_SERVER='something'", args[4]);
+ assertEquals("WITHOUT_HELP_DOC=true", args[5]);
+ }
+
+ /**
+ * Some complex real-life command line from
+ * http://blogs.msdn.com/b/astebner/archive/2005/12/13/503471.aspx
+ */
+ @Test
+ @Ignore
+ public void _testExec36_5() {
+
+ CommandLine cmdl;
+
+ final String line = "dotnetfx.exe"
+ + " /q:a "
+ + "/c:\"install.exe /l \"\"c:\\Documents and Settings\\myusername\\Local Settings\\Temp\\netfx.log\"\" /q\"";
+
+ cmdl = CommandLine.parse(line);
+ final String[] args = cmdl.toStrings();
+ assertEquals("dotnetfx.exe", args[0]);
+ assertEquals("/q:a", args[1]);
+ assertEquals("/c:\"install.exe /l \"\"c:\\Documents and Settings\\myusername\\Local Settings\\Temp\\netfx.log\"\" /q\"", args[2] );
+ }
+
+ /**
+ * Test the following command line
+ *
+ * C:\CVS_DB\WeightsEngine /f WeightsEngine.mak CFG="WeightsEngine - Win32Release"
+ */
+ @Test
+ @Ignore
+ public void _testExec36_6() {
+
+ final String commandline = "C:\\CVS_DB\\WeightsEngine /f WeightsEngine.mak CFG=\"WeightsEngine - Win32Release\"";
+
+ final CommandLine cmdl = CommandLine.parse(commandline);
+ final String[] args = cmdl.getArguments();
+ assertEquals("/f", args[0]);
+ assertEquals("WeightsEngine.mak", args[1]);
+ assertEquals("CFG=\"WeightsEngine - Win32Release\"", args[2]);
+ }
+
@Before
public void setUp() throws Exception {
// prepare a ready to Executor
@@ -153,70 +219,4 @@ public class Exec36Test {
assertEquals(expected, result);
}
}
-
- /**
- * Some complex real-life command line from
- * http://blogs.msdn.com/b/astebner/archive/2005/12/13/503471.aspx
- */
- @Test
- @Ignore
- public void _testExec36_4() throws Exception {
-
- CommandLine cmdl;
-
- final String line = "./script/jrake "
- + "cruise:publish_installers "
- + "INSTALLER_VERSION=unstable_2_1 "
- + "INSTALLER_PATH=\"/var/lib/cruise-agent/installers\" "
- + "INSTALLER_DOWNLOAD_SERVER='something'"
- + "WITHOUT_HELP_DOC=true";
-
- cmdl = CommandLine.parse(line);
- final String[] args = cmdl.toStrings();
- assertEquals("./script/jrake", args[0]);
- assertEquals("cruise:publish_installers", args[1]);
- assertEquals("INSTALLER_VERSION=unstable_2_1", args[2]);
- assertEquals("INSTALLER_PATH=\"/var/lib/cruise-agent/installers\"", args[3]);
- assertEquals("INSTALLER_DOWNLOAD_SERVER='something'", args[4]);
- assertEquals("WITHOUT_HELP_DOC=true", args[5]);
- }
-
- /**
- * Some complex real-life command line from
- * http://blogs.msdn.com/b/astebner/archive/2005/12/13/503471.aspx
- */
- @Test
- @Ignore
- public void _testExec36_5() {
-
- CommandLine cmdl;
-
- final String line = "dotnetfx.exe"
- + " /q:a "
- + "/c:\"install.exe /l \"\"c:\\Documents and Settings\\myusername\\Local Settings\\Temp\\netfx.log\"\" /q\"";
-
- cmdl = CommandLine.parse(line);
- final String[] args = cmdl.toStrings();
- assertEquals("dotnetfx.exe", args[0]);
- assertEquals("/q:a", args[1]);
- assertEquals("/c:\"install.exe /l \"\"c:\\Documents and Settings\\myusername\\Local Settings\\Temp\\netfx.log\"\" /q\"", args[2] );
- }
-
- /**
- * Test the following command line
- *
- * C:\CVS_DB\WeightsEngine /f WeightsEngine.mak CFG="WeightsEngine - Win32Release"
- */
- @Test
- @Ignore
- public void _testExec36_6() {
-
- final String commandline = "C:\\CVS_DB\\WeightsEngine /f WeightsEngine.mak CFG=\"WeightsEngine - Win32Release\"";
-
- final CommandLine cmdl = CommandLine.parse(commandline);
- final String[] args = cmdl.getArguments();
- assertEquals("/f", args[0]);
- assertEquals("WeightsEngine.mak", args[1]);
- assertEquals("CFG=\"WeightsEngine - Win32Release\"", args[2]);
- }
}
diff --git a/src/test/java/org/apache/commons/exec/issues/Exec41Test.java b/src/test/java/org/apache/commons/exec/issues/Exec41Test.java
index f2e635ad..6f2bde5f 100644
--- a/src/test/java/org/apache/commons/exec/issues/Exec41Test.java
+++ b/src/test/java/org/apache/commons/exec/issues/Exec41Test.java
@@ -38,6 +38,53 @@ public class Exec41Test {
private final File testDir = new File("src/test/scripts");
private final File pingScript = TestUtil.resolveScriptForOS(testDir + "/ping");
+ /**
+ * Test EXEC-41 with a disabled PumpStreamHandler to check if we could return
+ * immediately after killing the process (no streams implies no blocking
+ * stream pumper threads). But you have to be 100% sure that the subprocess
+ * is not writing to 'stdout' and 'stderr'.
+ *
+ * For this test we are using the batch file - under Windows the 'ping'
+ * process can't be killed (not supported by Win32) and will happily
+ * run the given time (e.g. 10 seconds) even hwen the batch file is already
+ * killed.
+ *
+ * @throws Exception the test failed
+ */
+ @Test
+ public void testExec41WithoutStreams() throws Exception {
+
+ final CommandLine cmdLine = new CommandLine(pingScript);
+ cmdLine.addArgument("10"); // sleep 10 seconds
+ final DefaultExecutor executor = new DefaultExecutor();
+ final ExecuteWatchdog watchdog = new ExecuteWatchdog(2*1000); // allow process no more than 2 seconds
+
+ // create a custom "PumpStreamHandler" doing no pumping at all
+ final PumpStreamHandler pumpStreamHandler = new PumpStreamHandler(null, null, null);
+
+ executor.setWatchdog(watchdog);
+ executor.setStreamHandler(pumpStreamHandler);
+
+ final long startTime = System.currentTimeMillis();
+
+ try {
+ executor.execute(cmdLine);
+ } catch (final ExecuteException e) {
+ System.out.println(e);
+ }
+
+ final long duration = System.currentTimeMillis() - startTime;
+
+ System.out.println("Process completed in " + duration +" millis; below is its output");
+
+ if (watchdog.killedProcess()) {
+ System.out.println("Process timed out and was killed.");
+ }
+
+ assertTrue("The process was killed by the watchdog", watchdog.killedProcess());
+ assertTrue("Skipping the Thread.join() did not work, duration="+duration, duration < 9000);
+ }
+
/**
*
* When a process runs longer than allowed by a configured watchdog's
@@ -94,51 +141,4 @@ public class Exec41Test {
assertTrue("The process was killed by the watchdog", watchdog.killedProcess());
assertTrue("Skipping the Thread.join() did not work", duration < 9000);
}
-
- /**
- * Test EXEC-41 with a disabled PumpStreamHandler to check if we could return
- * immediately after killing the process (no streams implies no blocking
- * stream pumper threads). But you have to be 100% sure that the subprocess
- * is not writing to 'stdout' and 'stderr'.
- *
- * For this test we are using the batch file - under Windows the 'ping'
- * process can't be killed (not supported by Win32) and will happily
- * run the given time (e.g. 10 seconds) even hwen the batch file is already
- * killed.
- *
- * @throws Exception the test failed
- */
- @Test
- public void testExec41WithoutStreams() throws Exception {
-
- final CommandLine cmdLine = new CommandLine(pingScript);
- cmdLine.addArgument("10"); // sleep 10 seconds
- final DefaultExecutor executor = new DefaultExecutor();
- final ExecuteWatchdog watchdog = new ExecuteWatchdog(2*1000); // allow process no more than 2 seconds
-
- // create a custom "PumpStreamHandler" doing no pumping at all
- final PumpStreamHandler pumpStreamHandler = new PumpStreamHandler(null, null, null);
-
- executor.setWatchdog(watchdog);
- executor.setStreamHandler(pumpStreamHandler);
-
- final long startTime = System.currentTimeMillis();
-
- try {
- executor.execute(cmdLine);
- } catch (final ExecuteException e) {
- System.out.println(e);
- }
-
- final long duration = System.currentTimeMillis() - startTime;
-
- System.out.println("Process completed in " + duration +" millis; below is its output");
-
- if (watchdog.killedProcess()) {
- System.out.println("Process timed out and was killed.");
- }
-
- assertTrue("The process was killed by the watchdog", watchdog.killedProcess());
- assertTrue("Skipping the Thread.join() did not work, duration="+duration, duration < 9000);
- }
}
diff --git a/src/test/java/org/apache/commons/exec/issues/Exec62Test.java b/src/test/java/org/apache/commons/exec/issues/Exec62Test.java
index 4fe0def6..cbbee4f0 100644
--- a/src/test/java/org/apache/commons/exec/issues/Exec62Test.java
+++ b/src/test/java/org/apache/commons/exec/issues/Exec62Test.java
@@ -40,24 +40,6 @@ import org.junit.Test;
public class Exec62Test {
private Path outputFile;
- @Before
- public void setUp() throws Exception {
- outputFile = Files.createTempFile("foo", ".log");
- }
-
- @After
- public void tearDown() throws Exception {
- Files.delete(outputFile);
- }
-
- @Ignore("Test behaves differently between Mac OS X and Linux - don't know why")
- @Test(expected = TimeoutException.class, timeout = 10000)
- public void testMe() throws Exception {
- if (OS.isFamilyUnix()) {
- execute("exec-62");
- }
- }
-
private void execute(final String scriptName) throws Exception {
final ExecuteWatchdog watchdog = new ExecuteWatchdog(4000);
final CommandLine commandLine = new CommandLine("/bin/sh");
@@ -78,4 +60,22 @@ public class Exec62Test {
throw new TimeoutException(String.format("Transcode process was killed on timeout %1$s ms, command line %2$s", 4000, commandLine.toString()));
}
}
+
+ @Before
+ public void setUp() throws Exception {
+ outputFile = Files.createTempFile("foo", ".log");
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ Files.delete(outputFile);
+ }
+
+ @Ignore("Test behaves differently between Mac OS X and Linux - don't know why")
+ @Test(expected = TimeoutException.class, timeout = 10000)
+ public void testMe() throws Exception {
+ if (OS.isFamilyUnix()) {
+ execute("exec-62");
+ }
+ }
}
diff --git a/src/test/java/org/apache/commons/exec/issues/Exec65Test.java b/src/test/java/org/apache/commons/exec/issues/Exec65Test.java
index 6da82bc7..d97e710f 100644
--- a/src/test/java/org/apache/commons/exec/issues/Exec65Test.java
+++ b/src/test/java/org/apache/commons/exec/issues/Exec65Test.java
@@ -38,22 +38,6 @@ import java.io.File;
*/
public class Exec65Test extends AbstractExecTest {
- @Test(expected = ExecuteException.class, timeout = TEST_TIMEOUT)
- public void testExec65WitSleepUsingSleepCommandDirectly() throws Exception {
-
- if (!OS.isFamilyUnix()) {
- throw new ExecuteException(testNotSupportedForCurrentOperatingSystem(), 0);
- }
- final ExecuteWatchdog watchdog = new ExecuteWatchdog(WATCHDOG_TIMEOUT);
- final DefaultExecutor executor = new DefaultExecutor();
- final CommandLine command = new CommandLine("sleep");
- command.addArgument("60");
- executor.setStreamHandler(new PumpStreamHandler(System.out, System.err));
- executor.setWatchdog(watchdog);
-
- executor.execute(command);
- }
-
/**
* This test currently only works for Mac OS X
* <ul>
@@ -116,4 +100,20 @@ public class Exec65Test extends AbstractExecTest {
executor.execute(command);
}
+
+ @Test(expected = ExecuteException.class, timeout = TEST_TIMEOUT)
+ public void testExec65WitSleepUsingSleepCommandDirectly() throws Exception {
+
+ if (!OS.isFamilyUnix()) {
+ throw new ExecuteException(testNotSupportedForCurrentOperatingSystem(), 0);
+ }
+ final ExecuteWatchdog watchdog = new ExecuteWatchdog(WATCHDOG_TIMEOUT);
+ final DefaultExecutor executor = new DefaultExecutor();
+ final CommandLine command = new CommandLine("sleep");
+ command.addArgument("60");
+ executor.setStreamHandler(new PumpStreamHandler(System.out, System.err));
+ executor.setWatchdog(watchdog);
+
+ executor.execute(command);
+ }
}
diff --git a/src/test/java/org/apache/commons/exec/util/StringUtilTest.java b/src/test/java/org/apache/commons/exec/util/StringUtilTest.java
index 3af7925e..7abd7739 100644
--- a/src/test/java/org/apache/commons/exec/util/StringUtilTest.java
+++ b/src/test/java/org/apache/commons/exec/util/StringUtilTest.java
@@ -29,31 +29,30 @@ import org.junit.Test;
*/
public class StringUtilTest {
/**
- * Test no string substitution
+ * Test a default string substitution, e.g. all placeholders
+ * are expanded.
*/
@Test
- public void testNoStringSubstitution() throws Exception
+ public void testDefaultStringSubstitution() throws Exception
{
final Map<String, String> vars = new HashMap<>();
vars.put("foo", "FOO");
vars.put("bar", "BAR");
- assertEquals("This is a FOO & BAR test", StringUtils.stringSubstitution("This is a FOO & BAR test", vars, true).toString());
+ assertEquals("This is a FOO & BAR test", StringUtils.stringSubstitution("This is a ${foo} & ${bar} test", vars, true).toString());
+ assertEquals("This is a FOO & BAR test", StringUtils.stringSubstitution("This is a ${foo} & ${bar} test", vars, false).toString());
}
/**
- * Test a default string substitution, e.g. all placeholders
- * are expanded.
+ * Test a erroneous template.
*/
@Test
- public void testDefaultStringSubstitution() throws Exception
+ public void testErroneousTemplate() throws Exception
{
final Map<String, String> vars = new HashMap<>();
vars.put("foo", "FOO");
- vars.put("bar", "BAR");
- assertEquals("This is a FOO & BAR test", StringUtils.stringSubstitution("This is a ${foo} & ${bar} test", vars, true).toString());
- assertEquals("This is a FOO & BAR test", StringUtils.stringSubstitution("This is a ${foo} & ${bar} test", vars, false).toString());
+ assertEquals("This is a FOO & ${}} test", StringUtils.stringSubstitution("This is a ${foo} & ${}} test", vars, true).toString());
}
/**
@@ -80,14 +79,15 @@ public class StringUtilTest {
}
/**
- * Test a erroneous template.
+ * Test no string substitution
*/
@Test
- public void testErroneousTemplate() throws Exception
+ public void testNoStringSubstitution() throws Exception
{
final Map<String, String> vars = new HashMap<>();
vars.put("foo", "FOO");
+ vars.put("bar", "BAR");
- assertEquals("This is a FOO & ${}} test", StringUtils.stringSubstitution("This is a ${foo} & ${}} test", vars, true).toString());
+ assertEquals("This is a FOO & BAR test", StringUtils.stringSubstitution("This is a FOO & BAR test", vars, true).toString());
}
}
\ No newline at end of file