Author: ngn Date: Sun Jul 9 13:32:36 2006 New Revision: 420347 URL: http://svn.apache.org/viewvc?rev=420347&view=rev Log: Implemented async execution Added unit tests, including tests for scripts returning error exit values
Added: jakarta/commons/sandbox/exec/trunk/src/test/scripts/error.bat (with props) jakarta/commons/sandbox/exec/trunk/src/test/scripts/error.sh (with props) Modified: jakarta/commons/sandbox/exec/trunk/src/main/java/org/apache/commons/exec/CommandLine.java jakarta/commons/sandbox/exec/trunk/src/main/java/org/apache/commons/exec/DefaultExecutor.java jakarta/commons/sandbox/exec/trunk/src/main/java/org/apache/commons/exec/environment/DefaultProcessingEnvironment.java jakarta/commons/sandbox/exec/trunk/src/test/java/org/apache/commons/exec/CommandLineTest.java jakarta/commons/sandbox/exec/trunk/src/test/java/org/apache/commons/exec/DefaultExecutorTest.java jakarta/commons/sandbox/exec/trunk/src/test/java/org/apache/commons/exec/MockExecuteResultHandler.java jakarta/commons/sandbox/exec/trunk/src/test/java/org/apache/commons/exec/TestUtil.java Modified: jakarta/commons/sandbox/exec/trunk/src/main/java/org/apache/commons/exec/CommandLine.java URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/exec/trunk/src/main/java/org/apache/commons/exec/CommandLine.java?rev=420347&r1=420346&r2=420347&view=diff ============================================================================== --- jakarta/commons/sandbox/exec/trunk/src/main/java/org/apache/commons/exec/CommandLine.java (original) +++ jakarta/commons/sandbox/exec/trunk/src/main/java/org/apache/commons/exec/CommandLine.java Sun Jul 9 13:32:36 2006 @@ -79,6 +79,13 @@ setExecutable(executable); } + /** + * Create a command line without any arguments. + */ + public CommandLine(File executable) { + setExecutable(executable.getAbsolutePath()); + } + private void setExecutable(final String executable) { if (executable == null) { throw new IllegalArgumentException("Executable can not be null"); Modified: jakarta/commons/sandbox/exec/trunk/src/main/java/org/apache/commons/exec/DefaultExecutor.java URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/exec/trunk/src/main/java/org/apache/commons/exec/DefaultExecutor.java?rev=420347&r1=420346&r2=420347&view=diff ============================================================================== --- jakarta/commons/sandbox/exec/trunk/src/main/java/org/apache/commons/exec/DefaultExecutor.java (original) +++ jakarta/commons/sandbox/exec/trunk/src/main/java/org/apache/commons/exec/DefaultExecutor.java Sun Jul 9 13:32:36 2006 @@ -101,30 +101,20 @@ return execute(command, (Map) null); } - /* - * (non-Javadoc) - * - * @see org.apache.commons.exec.Executor#execute(java.lang.String[], - * java.util.Map) - */ - public int execute(final CommandLine command, Map environment) - throws ExecuteException, IOException { + private int executeInternal(final CommandLine command, final Map environment, + final File dir, final ExecuteStreamHandler streams) throws IOException { - if (workingDirectory != null && !workingDirectory.exists()) { - throw new IOException(workingDirectory + " doesn't exist."); - } - - final Process process = launch(command, environment, workingDirectory); + final Process process = launch(command, environment, dir); try { - streamHandler.setProcessInputStream(process.getOutputStream()); - streamHandler.setProcessOutputStream(process.getInputStream()); - streamHandler.setProcessErrorStream(process.getErrorStream()); + streams.setProcessInputStream(process.getOutputStream()); + streams.setProcessOutputStream(process.getInputStream()); + streams.setProcessErrorStream(process.getErrorStream()); } catch (IOException e) { process.destroy(); throw e; } - streamHandler.start(); + streams.start(); try { // add the process to the list of those to destroy if the VM exits @@ -144,7 +134,7 @@ if (watchdog != null) { watchdog.stop(); } - streamHandler.stop(); + streams.stop(); closeStreams(process); if (watchdog != null) { @@ -157,7 +147,10 @@ } - // TODO check exitValue and throw if not OK + if(isFailure(exitValue)) { + throw new ExecuteException("Process exited with an error: " + exitValue, exitValue); + } + return exitValue; } finally { // remove the process to the list of those to destroy if the VM @@ -165,6 +158,25 @@ // // processDestroyer.remove(process); } + + + } + + /* + * (non-Javadoc) + * + * @see org.apache.commons.exec.Executor#execute(java.lang.String[], + * java.util.Map) + */ + public int execute(final CommandLine command, Map environment) + throws ExecuteException, IOException { + + if (workingDirectory != null && !workingDirectory.exists()) { + throw new IOException(workingDirectory + " doesn't exist."); + } + + return executeInternal(command, environment, workingDirectory, streamHandler); + } /** @@ -203,7 +215,7 @@ */ public void execute(final CommandLine command, ExecuteResultHandler handler) throws ExecuteException, IOException { - // TODO Auto-generated method stub + execute(command, null, handler); } @@ -215,8 +227,35 @@ */ public void execute(final CommandLine command, final Map environment, final ExecuteResultHandler handler) throws ExecuteException, IOException { - // TODO Auto-generated method stub + if (workingDirectory != null && !workingDirectory.exists()) { + throw new IOException(workingDirectory + " doesn't exist."); + } + new Thread() { + + /* (non-Javadoc) + * @see java.lang.Thread#run() + */ + public void run() { + int exitValue = Executor.INVALID_EXITVALUE; + try { + + exitValue = executeInternal(command, environment, workingDirectory, streamHandler); + + // TODO check exitValue and throw if not OK + handler.onProcessComplete(exitValue); + } catch (ExecuteException e) { + handler.onProcessFailed(e); + } catch(Exception e) { + handler.onProcessFailed(new ExecuteException("Execution failed", exitValue, e)); + } finally { + // remove the process to the list of those to destroy if the VM + // exits + // + // processDestroyer.remove(process); + } + } + }.start(); } /** @@ -240,6 +279,32 @@ process.getErrorStream().close(); } catch (IOException eyeOhEx) { // ignore error + } + } + + /** + * Checks whether <code>exitValue</code> signals a failure on the current + * system (OS specific). + * <p> + * <b>Note</b> that this method relies on the conventions of the OS, it + * will return false results if the application you are running doesn't + * follow these conventions. One notable exception is the Java VM provided + * by HP for OpenVMS - it will return 0 if successful (like on any other + * platform), but this signals a failure on OpenVMS. So if you execute a new + * Java VM on OpenVMS, you cannot trust this method. + * </p> + * + * @param exitValue + * the exit value (return code) to be checked + * @return <code>true</code> if <code>exitValue</code> signals a failure + */ + public static boolean isFailure(final int exitValue) { + if (OS.isFamilyOpenVms()) { + // even exit value signals failure + return (exitValue % 2) == 0; + } else { + // non zero exit value signals failure + return exitValue != 0; } } } Modified: jakarta/commons/sandbox/exec/trunk/src/main/java/org/apache/commons/exec/environment/DefaultProcessingEnvironment.java URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/exec/trunk/src/main/java/org/apache/commons/exec/environment/DefaultProcessingEnvironment.java?rev=420347&r1=420346&r2=420347&view=diff ============================================================================== --- jakarta/commons/sandbox/exec/trunk/src/main/java/org/apache/commons/exec/environment/DefaultProcessingEnvironment.java (original) +++ jakarta/commons/sandbox/exec/trunk/src/main/java/org/apache/commons/exec/environment/DefaultProcessingEnvironment.java Sun Jul 9 13:32:36 2006 @@ -28,7 +28,8 @@ import java.util.Map; import org.apache.commons.exec.CommandLine; -import org.apache.commons.exec.Execute; +import org.apache.commons.exec.DefaultExecutor; +import org.apache.commons.exec.Executor; import org.apache.commons.exec.OS; import org.apache.commons.exec.PumpStreamHandler; import org.apache.commons.logging.Log; @@ -104,11 +105,10 @@ */ protected BufferedReader runProcEnvCommand() throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); - Execute exe = new Execute(new PumpStreamHandler(out)); - exe.setCommandline(getProcEnvCommand()); - // Make sure we do not recurse forever - exe.setNewEnvironment(true); - int retval = exe.execute(); + Executor exe = new DefaultExecutor(); + exe.setStreamHandler(new PumpStreamHandler(out)); + + int retval = exe.execute(getProcEnvCommand(), new HashMap()); if (retval != 0) { // Just try to use what we got } Modified: jakarta/commons/sandbox/exec/trunk/src/test/java/org/apache/commons/exec/CommandLineTest.java URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/exec/trunk/src/test/java/org/apache/commons/exec/CommandLineTest.java?rev=420347&r1=420346&r2=420347&view=diff ============================================================================== --- jakarta/commons/sandbox/exec/trunk/src/test/java/org/apache/commons/exec/CommandLineTest.java (original) +++ jakarta/commons/sandbox/exec/trunk/src/test/java/org/apache/commons/exec/CommandLineTest.java Sun Jul 9 13:32:36 2006 @@ -56,7 +56,7 @@ public void testNullExecutable() { try { - CommandLine cmdl = new CommandLine(null); + CommandLine cmdl = new CommandLine((String)null); fail("Must throw IllegalArgumentException"); } catch (IllegalArgumentException e) { // Expected Modified: jakarta/commons/sandbox/exec/trunk/src/test/java/org/apache/commons/exec/DefaultExecutorTest.java URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/exec/trunk/src/test/java/org/apache/commons/exec/DefaultExecutorTest.java?rev=420347&r1=420346&r2=420347&view=diff ============================================================================== --- jakarta/commons/sandbox/exec/trunk/src/test/java/org/apache/commons/exec/DefaultExecutorTest.java (original) +++ jakarta/commons/sandbox/exec/trunk/src/test/java/org/apache/commons/exec/DefaultExecutorTest.java Sun Jul 9 13:32:36 2006 @@ -26,29 +26,38 @@ public class DefaultExecutorTest extends TestCase { - private String testDir = "src/test/scripts"; + + private Executor exec = new DefaultExecutor(); + private File testDir = new File("src/test/scripts"); private ByteArrayOutputStream baos; - private String testScript = TestUtil.resolveScriptForOS(testDir + "/test"); + private File testScript = TestUtil.resolveScriptForOS(testDir + "/test"); + private File errorTestScript = TestUtil.resolveScriptForOS(testDir + "/error"); protected void setUp() throws Exception { baos = new ByteArrayOutputStream(); + exec.setStreamHandler(new PumpStreamHandler(baos, baos)); } public void testExecute() throws Exception { - Executor exec = new DefaultExecutor(); - exec.setStreamHandler(new PumpStreamHandler(baos, baos)); - - CommandLine cl = new CommandLine(new File(testScript).getAbsolutePath()); + CommandLine cl = new CommandLine(testScript); int exitValue = exec.execute(cl); assertEquals("FOO..", baos.toString().trim()); assertEquals(0, exitValue); } - public void testExecuteWithArg() throws Exception { - Executor exec = new DefaultExecutor(); - exec.setStreamHandler(new PumpStreamHandler(baos, baos)); + public void testExecuteWithError() throws Exception { + CommandLine cl = new CommandLine(errorTestScript); + + try{ + exec.execute(cl); + fail("Must throw ExecuteException"); + } catch(ExecuteException e) { + assertEquals(1, e.getExitValue()); + } + } + public void testExecuteWithArg() throws Exception { CommandLine cl = new CommandLine(testScript); cl.addArgument("BAR"); int exitValue = exec.execute(cl); @@ -58,9 +67,6 @@ } public void testExecuteWithEnv() throws Exception { - Executor exec = new DefaultExecutor(); - exec.setStreamHandler(new PumpStreamHandler(baos, baos)); - Map env = new HashMap(); env.put("TEST_ENV_VAR", "XYZ"); @@ -72,10 +78,7 @@ assertEquals(0, exitValue); } - public void disabledtestExecuteAsync() throws Exception { - Executor exec = new DefaultExecutor(); - exec.setStreamHandler(new PumpStreamHandler(baos, baos)); - + public void testExecuteAsync() throws Exception { CommandLine cl = new CommandLine(testScript); MockExecuteResultHandler handler = new MockExecuteResultHandler(); @@ -83,10 +86,25 @@ exec.execute(cl, handler); // wait for script to run - Thread.sleep(1000); + Thread.sleep(2000); - assertEquals("FOO..", baos.toString().trim()); assertEquals(0, handler.getExitValue()); + assertEquals("FOO..", baos.toString().trim()); + } + + public void testExecuteAsyncWithError() throws Exception { + CommandLine cl = new CommandLine(errorTestScript); + + MockExecuteResultHandler handler = new MockExecuteResultHandler(); + + exec.execute(cl, handler); + + // wait for script to run + Thread.sleep(2000); + + assertEquals(1, handler.getExitValue()); + assertTrue(handler.getException() instanceof ExecuteException); + assertEquals("FOO..", baos.toString().trim()); } Modified: jakarta/commons/sandbox/exec/trunk/src/test/java/org/apache/commons/exec/MockExecuteResultHandler.java URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/exec/trunk/src/test/java/org/apache/commons/exec/MockExecuteResultHandler.java?rev=420347&r1=420346&r2=420347&view=diff ============================================================================== --- jakarta/commons/sandbox/exec/trunk/src/test/java/org/apache/commons/exec/MockExecuteResultHandler.java (original) +++ jakarta/commons/sandbox/exec/trunk/src/test/java/org/apache/commons/exec/MockExecuteResultHandler.java Sun Jul 9 13:32:36 2006 @@ -34,6 +34,7 @@ */ public void onProcessFailed(ExecuteException e) { this.exception = e; + exitValue = e.getExitValue(); } /** Modified: jakarta/commons/sandbox/exec/trunk/src/test/java/org/apache/commons/exec/TestUtil.java URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/exec/trunk/src/test/java/org/apache/commons/exec/TestUtil.java?rev=420347&r1=420346&r2=420347&view=diff ============================================================================== --- jakarta/commons/sandbox/exec/trunk/src/test/java/org/apache/commons/exec/TestUtil.java (original) +++ jakarta/commons/sandbox/exec/trunk/src/test/java/org/apache/commons/exec/TestUtil.java Sun Jul 9 13:32:36 2006 @@ -17,6 +17,7 @@ package org.apache.commons.exec; +import java.io.File; import java.util.Arrays; import junit.framework.AssertionFailedError; @@ -27,11 +28,11 @@ private TestUtil() { } - public static String resolveScriptForOS(String script) { + public static File resolveScriptForOS(String script) { if (OS.isFamilyWindows()) { - return script + ".bat"; + return new File(script + ".bat"); } else if (OS.isFamilyUnix()) { - return script + ".sh"; + return new File(script + ".sh"); } else { throw new AssertionFailedError("Test not supported for this OS"); } Added: jakarta/commons/sandbox/exec/trunk/src/test/scripts/error.bat URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/exec/trunk/src/test/scripts/error.bat?rev=420347&view=auto ============================================================================== --- jakarta/commons/sandbox/exec/trunk/src/test/scripts/error.bat (added) +++ jakarta/commons/sandbox/exec/trunk/src/test/scripts/error.bat Sun Jul 9 13:32:36 2006 @@ -0,0 +1,23 @@ [EMAIL PROTECTED] off +REM +REM Copyright 2001-2002,2004 The Apache Software Foundation +REM +REM Licensed under the Apache License, Version 2.0 (the "License"); +REM you may not use this file except in compliance with the License. +REM You may obtain a copy of the License at +REM +REM http://www.apache.org/licenses/LICENSE-2.0 +REM +REM Unless required by applicable law or agreed to in writing, software +REM distributed under the License is distributed on an "AS IS" BASIS, +REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +REM See the License for the specific language governing permissions and +REM limitations under the License. +REM +REM + +REM This test script will return an error exit code + [EMAIL PROTECTED] FOO.%TEST_ENV_VAR%.%1 + +EXIT 1 Propchange: jakarta/commons/sandbox/exec/trunk/src/test/scripts/error.bat ------------------------------------------------------------------------------ svn:eol-style = native Added: jakarta/commons/sandbox/exec/trunk/src/test/scripts/error.sh URL: http://svn.apache.org/viewvc/jakarta/commons/sandbox/exec/trunk/src/test/scripts/error.sh?rev=420347&view=auto ============================================================================== --- jakarta/commons/sandbox/exec/trunk/src/test/scripts/error.sh (added) +++ jakarta/commons/sandbox/exec/trunk/src/test/scripts/error.sh Sun Jul 9 13:32:36 2006 @@ -0,0 +1,22 @@ +#!/bin/sh + +# +# Copyright 2001-2002,2004 The Apache Software Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# + +echo FOO.$TEST_ENV_VAR.$1 + +exit 1 Propchange: jakarta/commons/sandbox/exec/trunk/src/test/scripts/error.sh ------------------------------------------------------------------------------ svn:eol-style = native --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]