From 13194de97c2858365330a971b6e9fb2a0969c3b5 Mon Sep 17 00:00:00 2001 From: tms08012 Date: Wed, 13 Jun 2012 17:36:32 -0400 Subject: [PATCH] initial, with class diagram, compiles --- ApacheCommonsExec/.classpath | 11 + ApacheCommonsExec/.project | 17 + .../.settings/org.eclipse.jdt.core.prefs | 11 + ApacheCommonsExec/LICENSE.txt | 203 +++ ApacheCommonsExec/NOTICE.txt | 5 + ApacheCommonsExec/STATUS | 50 + ApacheCommonsExec/bin/test4class.cld | 1575 +++++++++++++++++ ApacheCommonsExec/build.xml | 153 ++ ApacheCommonsExec/doap_exec.rdf | 58 + ApacheCommonsExec/findbugs-exclude-filter.xml | 33 + ApacheCommonsExec/pom.xml | 270 +++ ApacheCommonsExec/src/assembly/bin.xml | 43 + ApacheCommonsExec/src/assembly/src.xml | 39 + .../src/assembly/test-distribution.xml | 68 + ApacheCommonsExec/src/changes/changes.xml | 233 +++ .../org/apache/commons/exec/CommandLine.java | 441 +++++ .../apache/commons/exec/CommandLineTest.java | 546 ++++++ .../exec/DefaultExecuteResultHandler.java | 144 ++ .../apache/commons/exec/DefaultExecutor.java | 434 +++++ .../commons/exec/EnvironmentUtilTest.java | 117 ++ .../apache/commons/exec/ExecuteException.java | 85 + .../commons/exec/ExecuteResultHandler.java | 43 + .../commons/exec/ExecuteStreamHandler.java | 66 + .../apache/commons/exec/ExecuteWatchdog.java | 233 +++ .../src/org/apache/commons/exec/Executor.java | 208 +++ .../commons/exec/InputStreamPumper.java | 83 + .../apache/commons/exec/LogOutputStream.java | 176 ++ .../commons/exec/LogOutputStreamTest.java | 77 + .../src/org/apache/commons/exec/OS.java | 244 +++ .../apache/commons/exec/ProcessDestroyer.java | 60 + .../commons/exec/PumpStreamHandler.java | 316 ++++ .../exec/ShutdownHookProcessDestroyer.java | 194 ++ .../apache/commons/exec/StandAloneTest.java | 46 + .../org/apache/commons/exec/StreamPumper.java | 145 ++ .../org/apache/commons/exec/TestRunner.java | 58 + .../src/org/apache/commons/exec/TestUtil.java | 84 + .../org/apache/commons/exec/TestUtilTest.java | 94 + .../apache/commons/exec/TimeoutObserver.java | 34 + .../org/apache/commons/exec/TutorialTest.java | 148 ++ .../src/org/apache/commons/exec/Watchdog.java | 93 + .../DefaultProcessingEnvironment.java | 241 +++ .../exec/environment/EnvironmentUtils.java | 119 ++ .../OpenVmsProcessingEnvironment.java | 86 + .../exec/launcher/CommandLauncher.java | 86 + .../exec/launcher/CommandLauncherFactory.java | 48 + .../exec/launcher/CommandLauncherImpl.java | 50 + .../exec/launcher/CommandLauncherProxy.java | 53 + .../exec/launcher/Java13CommandLauncher.java | 61 + .../exec/launcher/OS2CommandLauncher.java | 68 + .../exec/launcher/VmsCommandLauncher.java | 146 ++ .../exec/launcher/WinNTCommandLauncher.java | 63 + .../apache/commons/exec/util/DebugUtils.java | 86 + .../apache/commons/exec/util/MapUtilTest.java | 74 + .../apache/commons/exec/util/MapUtils.java | 105 ++ .../commons/exec/util/StringUtilTest.java | 86 + .../apache/commons/exec/util/StringUtils.java | 258 +++ .../src/site/apt/commandline.apt | 150 ++ ApacheCommonsExec/src/site/apt/index.apt | 57 + ApacheCommonsExec/src/site/apt/technical.apt | 36 + ApacheCommonsExec/src/site/apt/tutorial.apt | 178 ++ ApacheCommonsExec/src/site/fml/faq.fml | 85 + ApacheCommonsExec/src/site/site.xml | 41 + .../src/site/xdoc/download_exec.xml | 138 ++ .../src/site/xdoc/issue-tracking.xml | 102 ++ .../src/site/xdoc/mail-lists.xml | 202 +++ .../src/site/xdoc/testmatrix.xml | 210 +++ ApacheCommonsExec/src/test/bin/testme.bat | 20 + ApacheCommonsExec/src/test/bin/testme.dcl | 25 + ApacheCommonsExec/src/test/bin/testme.sh | 22 + .../src/test/scripts/acrord32.bat | 21 + .../src/test/scripts/acrord32.sh | 29 + .../src/test/scripts/environment.bat | 22 + .../src/test/scripts/environment.dcl | 22 + .../src/test/scripts/environment.sh | 21 + ApacheCommonsExec/src/test/scripts/error.bat | 22 + ApacheCommonsExec/src/test/scripts/error.dcl | 25 + ApacheCommonsExec/src/test/scripts/error.sh | 24 + .../src/test/scripts/forever.bat | 27 + .../src/test/scripts/forever.dcl | 38 + ApacheCommonsExec/src/test/scripts/forever.sh | 27 + ApacheCommonsExec/src/test/scripts/invoker.sh | 23 + ApacheCommonsExec/src/test/scripts/ping.bat | 24 + ApacheCommonsExec/src/test/scripts/ping.dcl | 23 + ApacheCommonsExec/src/test/scripts/ping.sh | 29 + .../src/test/scripts/printargs.bat | 25 + .../src/test/scripts/printargs.dcl | 30 + .../src/test/scripts/printargs.sh | 27 + .../src/test/scripts/redirect.sh | 30 + .../src/test/scripts/standalone.sh | 21 + ApacheCommonsExec/src/test/scripts/stdin.bat | 19 + ApacheCommonsExec/src/test/scripts/stdin.dcl | 23 + ApacheCommonsExec/src/test/scripts/stdin.sh | 23 + ApacheCommonsExec/src/test/scripts/test.bat | 24 + ApacheCommonsExec/src/test/scripts/test.dcl | 25 + ApacheCommonsExec/src/test/scripts/test.sh | 23 + ApacheCommonsExec/test4class.cld | 1575 +++++++++++++++++ 96 files changed, 12056 insertions(+) create mode 100644 ApacheCommonsExec/.classpath create mode 100644 ApacheCommonsExec/.project create mode 100644 ApacheCommonsExec/.settings/org.eclipse.jdt.core.prefs create mode 100644 ApacheCommonsExec/LICENSE.txt create mode 100644 ApacheCommonsExec/NOTICE.txt create mode 100644 ApacheCommonsExec/STATUS create mode 100644 ApacheCommonsExec/bin/test4class.cld create mode 100644 ApacheCommonsExec/build.xml create mode 100644 ApacheCommonsExec/doap_exec.rdf create mode 100644 ApacheCommonsExec/findbugs-exclude-filter.xml create mode 100644 ApacheCommonsExec/pom.xml create mode 100644 ApacheCommonsExec/src/assembly/bin.xml create mode 100644 ApacheCommonsExec/src/assembly/src.xml create mode 100644 ApacheCommonsExec/src/assembly/test-distribution.xml create mode 100644 ApacheCommonsExec/src/changes/changes.xml create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/CommandLine.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/CommandLineTest.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/DefaultExecuteResultHandler.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/DefaultExecutor.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/EnvironmentUtilTest.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/ExecuteException.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/ExecuteResultHandler.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/ExecuteStreamHandler.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/ExecuteWatchdog.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/Executor.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/InputStreamPumper.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/LogOutputStream.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/LogOutputStreamTest.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/OS.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/ProcessDestroyer.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/PumpStreamHandler.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/ShutdownHookProcessDestroyer.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/StandAloneTest.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/StreamPumper.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/TestRunner.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/TestUtil.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/TestUtilTest.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/TimeoutObserver.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/TutorialTest.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/Watchdog.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/environment/DefaultProcessingEnvironment.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/environment/EnvironmentUtils.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/environment/OpenVmsProcessingEnvironment.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/launcher/CommandLauncher.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/launcher/CommandLauncherFactory.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/launcher/CommandLauncherImpl.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/launcher/CommandLauncherProxy.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/launcher/Java13CommandLauncher.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/launcher/OS2CommandLauncher.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/launcher/VmsCommandLauncher.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/launcher/WinNTCommandLauncher.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/util/DebugUtils.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/util/MapUtilTest.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/util/MapUtils.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/util/StringUtilTest.java create mode 100644 ApacheCommonsExec/src/org/apache/commons/exec/util/StringUtils.java create mode 100644 ApacheCommonsExec/src/site/apt/commandline.apt create mode 100644 ApacheCommonsExec/src/site/apt/index.apt create mode 100644 ApacheCommonsExec/src/site/apt/technical.apt create mode 100644 ApacheCommonsExec/src/site/apt/tutorial.apt create mode 100644 ApacheCommonsExec/src/site/fml/faq.fml create mode 100644 ApacheCommonsExec/src/site/site.xml create mode 100644 ApacheCommonsExec/src/site/xdoc/download_exec.xml create mode 100644 ApacheCommonsExec/src/site/xdoc/issue-tracking.xml create mode 100644 ApacheCommonsExec/src/site/xdoc/mail-lists.xml create mode 100644 ApacheCommonsExec/src/site/xdoc/testmatrix.xml create mode 100644 ApacheCommonsExec/src/test/bin/testme.bat create mode 100644 ApacheCommonsExec/src/test/bin/testme.dcl create mode 100644 ApacheCommonsExec/src/test/bin/testme.sh create mode 100644 ApacheCommonsExec/src/test/scripts/acrord32.bat create mode 100644 ApacheCommonsExec/src/test/scripts/acrord32.sh create mode 100644 ApacheCommonsExec/src/test/scripts/environment.bat create mode 100644 ApacheCommonsExec/src/test/scripts/environment.dcl create mode 100644 ApacheCommonsExec/src/test/scripts/environment.sh create mode 100644 ApacheCommonsExec/src/test/scripts/error.bat create mode 100644 ApacheCommonsExec/src/test/scripts/error.dcl create mode 100644 ApacheCommonsExec/src/test/scripts/error.sh create mode 100644 ApacheCommonsExec/src/test/scripts/forever.bat create mode 100644 ApacheCommonsExec/src/test/scripts/forever.dcl create mode 100644 ApacheCommonsExec/src/test/scripts/forever.sh create mode 100644 ApacheCommonsExec/src/test/scripts/invoker.sh create mode 100644 ApacheCommonsExec/src/test/scripts/ping.bat create mode 100644 ApacheCommonsExec/src/test/scripts/ping.dcl create mode 100644 ApacheCommonsExec/src/test/scripts/ping.sh create mode 100644 ApacheCommonsExec/src/test/scripts/printargs.bat create mode 100644 ApacheCommonsExec/src/test/scripts/printargs.dcl create mode 100644 ApacheCommonsExec/src/test/scripts/printargs.sh create mode 100644 ApacheCommonsExec/src/test/scripts/redirect.sh create mode 100644 ApacheCommonsExec/src/test/scripts/standalone.sh create mode 100644 ApacheCommonsExec/src/test/scripts/stdin.bat create mode 100644 ApacheCommonsExec/src/test/scripts/stdin.dcl create mode 100644 ApacheCommonsExec/src/test/scripts/stdin.sh create mode 100644 ApacheCommonsExec/src/test/scripts/test.bat create mode 100644 ApacheCommonsExec/src/test/scripts/test.dcl create mode 100644 ApacheCommonsExec/src/test/scripts/test.sh create mode 100644 ApacheCommonsExec/test4class.cld diff --git a/ApacheCommonsExec/.classpath b/ApacheCommonsExec/.classpath new file mode 100644 index 0000000..ce96bfe --- /dev/null +++ b/ApacheCommonsExec/.classpath @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/ApacheCommonsExec/.project b/ApacheCommonsExec/.project new file mode 100644 index 0000000..5797b6e --- /dev/null +++ b/ApacheCommonsExec/.project @@ -0,0 +1,17 @@ + + + ApacheCommonsExec + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/ApacheCommonsExec/.settings/org.eclipse.jdt.core.prefs b/ApacheCommonsExec/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..54e493c --- /dev/null +++ b/ApacheCommonsExec/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/ApacheCommonsExec/LICENSE.txt b/ApacheCommonsExec/LICENSE.txt new file mode 100644 index 0000000..8b5861d --- /dev/null +++ b/ApacheCommonsExec/LICENSE.txt @@ -0,0 +1,203 @@ +/* + * Apache License + * Version 2.0, January 2004 + * http://www.apache.org/licenses/ + * + * TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + * + * 1. Definitions. + * + * "License" shall mean the terms and conditions for use, reproduction, + * and distribution as defined by Sections 1 through 9 of this document. + * + * "Licensor" shall mean the copyright owner or entity authorized by + * the copyright owner that is granting the License. + * + * "Legal Entity" shall mean the union of the acting entity and all + * other entities that control, are controlled by, or are under common + * control with that entity. For the purposes of this definition, + * "control" means (i) the power, direct or indirect, to cause the + * direction or management of such entity, whether by contract or + * otherwise, or (ii) ownership of fifty percent (50%) or more of the + * outstanding shares, or (iii) beneficial ownership of such entity. + * + * "You" (or "Your") shall mean an individual or Legal Entity + * exercising permissions granted by this License. + * + * "Source" form shall mean the preferred form for making modifications, + * including but not limited to software source code, documentation + * source, and configuration files. + * + * "Object" form shall mean any form resulting from mechanical + * transformation or translation of a Source form, including but + * not limited to compiled object code, generated documentation, + * and conversions to other media types. + * + * "Work" shall mean the work of authorship, whether in Source or + * Object form, made available under the License, as indicated by a + * copyright notice that is included in or attached to the work + * (an example is provided in the Appendix below). + * + * "Derivative Works" shall mean any work, whether in Source or Object + * form, that is based on (or derived from) the Work and for which the + * editorial revisions, annotations, elaborations, or other modifications + * represent, as a whole, an original work of authorship. For the purposes + * of this License, Derivative Works shall not include works that remain + * separable from, or merely link (or bind by name) to the interfaces of, + * the Work and Derivative Works thereof. + * + * "Contribution" shall mean any work of authorship, including + * the original version of the Work and any modifications or additions + * to that Work or Derivative Works thereof, that is intentionally + * submitted to Licensor for inclusion in the Work by the copyright owner + * or by an individual or Legal Entity authorized to submit on behalf of + * the copyright owner. For the purposes of this definition, "submitted" + * means any form of electronic, verbal, or written communication sent + * to the Licensor or its representatives, including but not limited to + * communication on electronic mailing lists, source code control systems, + * and issue tracking systems that are managed by, or on behalf of, the + * Licensor for the purpose of discussing and improving the Work, but + * excluding communication that is conspicuously marked or otherwise + * designated in writing by the copyright owner as "Not a Contribution." + * + * "Contributor" shall mean Licensor and any individual or Legal Entity + * on behalf of whom a Contribution has been received by Licensor and + * subsequently incorporated within the Work. + * + * 2. Grant of Copyright License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * copyright license to reproduce, prepare Derivative Works of, + * publicly display, publicly perform, sublicense, and distribute the + * Work and such Derivative Works in Source or Object form. + * + * 3. Grant of Patent License. Subject to the terms and conditions of + * this License, each Contributor hereby grants to You a perpetual, + * worldwide, non-exclusive, no-charge, royalty-free, irrevocable + * (except as stated in this section) patent license to make, have made, + * use, offer to sell, sell, import, and otherwise transfer the Work, + * where such license applies only to those patent claims licensable + * by such Contributor that are necessarily infringed by their + * Contribution(s) alone or by combination of their Contribution(s) + * with the Work to which such Contribution(s) was submitted. If You + * institute patent litigation against any entity (including a + * cross-claim or counterclaim in a lawsuit) alleging that the Work + * or a Contribution incorporated within the Work constitutes direct + * or contributory patent infringement, then any patent licenses + * granted to You under this License for that Work shall terminate + * as of the date such litigation is filed. + * + * 4. Redistribution. You may reproduce and distribute copies of the + * Work or Derivative Works thereof in any medium, with or without + * modifications, and in Source or Object form, provided that You + * meet the following conditions: + * + * (a) You must give any other recipients of the Work or + * Derivative Works a copy of this License; and + * + * (b) You must cause any modified files to carry prominent notices + * stating that You changed the files; and + * + * (c) You must retain, in the Source form of any Derivative Works + * that You distribute, all copyright, patent, trademark, and + * attribution notices from the Source form of the Work, + * excluding those notices that do not pertain to any part of + * the Derivative Works; and + * + * (d) If the Work includes a "NOTICE" text file as part of its + * distribution, then any Derivative Works that You distribute must + * include a readable copy of the attribution notices contained + * within such NOTICE file, excluding those notices that do not + * pertain to any part of the Derivative Works, in at least one + * of the following places: within a NOTICE text file distributed + * as part of the Derivative Works; within the Source form or + * documentation, if provided along with the Derivative Works; or, + * within a display generated by the Derivative Works, if and + * wherever such third-party notices normally appear. The contents + * of the NOTICE file are for informational purposes only and + * do not modify the License. You may add Your own attribution + * notices within Derivative Works that You distribute, alongside + * or as an addendum to the NOTICE text from the Work, provided + * that such additional attribution notices cannot be construed + * as modifying the License. + * + * You may add Your own copyright statement to Your modifications and + * may provide additional or different license terms and conditions + * for use, reproduction, or distribution of Your modifications, or + * for any such Derivative Works as a whole, provided Your use, + * reproduction, and distribution of the Work otherwise complies with + * the conditions stated in this License. + * + * 5. Submission of Contributions. Unless You explicitly state otherwise, + * any Contribution intentionally submitted for inclusion in the Work + * by You to the Licensor shall be under the terms and conditions of + * this License, without any additional terms or conditions. + * Notwithstanding the above, nothing herein shall supersede or modify + * the terms of any separate license agreement you may have executed + * with Licensor regarding such Contributions. + * + * 6. Trademarks. This License does not grant permission to use the trade + * names, trademarks, service marks, or product names of the Licensor, + * except as required for reasonable and customary use in describing the + * origin of the Work and reproducing the content of the NOTICE file. + * + * 7. Disclaimer of Warranty. Unless required by applicable law or + * agreed to in writing, Licensor provides the Work (and each + * Contributor provides its Contributions) on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied, including, without limitation, any warranties or conditions + * of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + * PARTICULAR PURPOSE. You are solely responsible for determining the + * appropriateness of using or redistributing the Work and assume any + * risks associated with Your exercise of permissions under this License. + * + * 8. Limitation of Liability. In no event and under no legal theory, + * whether in tort (including negligence), contract, or otherwise, + * unless required by applicable law (such as deliberate and grossly + * negligent acts) or agreed to in writing, shall any Contributor be + * liable to You for damages, including any direct, indirect, special, + * incidental, or consequential damages of any character arising as a + * result of this License or out of the use or inability to use the + * Work (including but not limited to damages for loss of goodwill, + * work stoppage, computer failure or malfunction, or any and all + * other commercial damages or losses), even if such Contributor + * has been advised of the possibility of such damages. + * + * 9. Accepting Warranty or Additional Liability. While redistributing + * the Work or Derivative Works thereof, You may choose to offer, + * and charge a fee for, acceptance of support, warranty, indemnity, + * or other liability obligations and/or rights consistent with this + * License. However, in accepting such obligations, You may act only + * on Your own behalf and on Your sole responsibility, not on behalf + * of any other Contributor, and only if You agree to indemnify, + * defend, and hold each Contributor harmless for any liability + * incurred by, or claims asserted against, such Contributor by reason + * of your accepting any such warranty or additional liability. + * + * END OF TERMS AND CONDITIONS + * + * APPENDIX: How to apply the Apache License to your work. + * + * To apply the Apache License to your work, attach the following + * boilerplate notice, with the fields enclosed by brackets "[]" + * replaced with your own identifying information. (Don't include + * the brackets!) The text should be enclosed in the appropriate + * comment syntax for the file format. We also recommend that a + * file or class name and description of purpose be included on the + * same "printed page" as the copyright notice for easier + * identification within third-party archives. + * + * Copyright [yyyy] [name of copyright owner] + * + * 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. + */ diff --git a/ApacheCommonsExec/NOTICE.txt b/ApacheCommonsExec/NOTICE.txt new file mode 100644 index 0000000..2d23a87 --- /dev/null +++ b/ApacheCommonsExec/NOTICE.txt @@ -0,0 +1,5 @@ +Apache Commons Exec +Copyright 2005-2011 The Apache Software Foundation + +This product includes software developed by +The Apache Software Foundation (http://www.apache.org/). diff --git a/ApacheCommonsExec/STATUS b/ApacheCommonsExec/STATUS new file mode 100644 index 0000000..8378b47 --- /dev/null +++ b/ApacheCommonsExec/STATUS @@ -0,0 +1,50 @@ +Proposal for Exec Package +28th July 2005 + +Rationale +------------------------------------ +Executing external processes from Java is a well-known problem area. It is inheriently platform dependent and requires +the developer to know and test for platform specific behaviors, for example using cmd.exe on Windows or limited buffer +sizes causing deadlocks. The JRE support for this is very limited, albeit better with the new Java SE 1.5 +ProcessBuilder class. + +Reliably executing external processes can also require knowledge of the environment variables before or after the +command is executed. In J2SE 1.1-1.4 there is not support for this, since the method, System.getenv(), for retriving +environment variables is deprecated (in later releases the deprecation was removed). + +The are currently several different libraries that for their own purposes has implemented frameworks around +Runtime.exec() to handle the various issue outlined above. The proposed project should aim at coordinating and +learning from these initatives to create and maintain a simple, reusable and well-tested package. Since some of the +more problematic platforms are not readily available, it is my hope that the broad Apache community can be a +great help. + +Scope of the package +------------------------------------ +The package shall create and maintain a process execution package written in the Java language to be distributed +under the ASF license. The Java code might also be complemented with scripts (e.g. Perl scripts) to fully enable +execution on some operating systems. The package should aim for supporting a wide range of operating systems while +still having a consistent API for all platforms. + +Identify the initial source for the package +------------------------------------ +Several implementations exists and should be researched before finalizing the design: + * Ant 1.X contains probably the most mature code within the exec task. This code has been stripped of the + Ant specifics and cleaned up by Niklas Gustavsson and can be donated under the ASF license. + * Ideas from http://ant.apache.org/ant2/actionlist.html#exec + * plexus-utils has a similar but slimmer BSD-licensed implementation than Ant that can be reused + +Identify the base name for the package +------------------------------------ +org.apache.commons.exec + +INITIAL COMMITTERS +------------------------------------ +Brett Porter +Stefan Bodewig +Trygve Laugstol + +INITIAL CONTRIBUTORS +------------------------------------ +Niklas Gustavsson +Kev Jackson + diff --git a/ApacheCommonsExec/bin/test4class.cld b/ApacheCommonsExec/bin/test4class.cld new file mode 100644 index 0000000..7b0e036 --- /dev/null +++ b/ApacheCommonsExec/bin/test4class.cld @@ -0,0 +1,1575 @@ + + + + + + + false + + + _stereo_type + Stereo Type + false + + + _simpleEntityName + Simple Name + false + + + _entityName + Name + false + + + _background + Background Color + false + + + _attrs + Attributes... + false + + + _operations + Operations... + false + + + _abstract + abstract + false + + + + org.apache.commons.exec.CommandLine + + -1 + -1 + 173 + 110 + + + + + + + arguments + Vector + false + + 255 + 255 + 206 + + + 0 + 0 + 0 + + true + + + + + + 2 + + + + + + + + executable + String + false + + + true + + + + + + 2 + + + + + + + + substitutionMap + Map + false + + + true + + + + + + 2 + + + + + + + + isFile + boolean + false + + + true + + + + + + 2 + + + + + + + + parse + CommandLine + + + line + String + + + false + true + + + true + + + + + + 2 + + + + + + + + parse + CommandLine + + + line + String + + + substitutionMap + Map + + + false + true + + + true + + + + + + 2 + + + + + + + + CommandLine + void + + + executable + String + + + false + false + + + true + + + + + + 2 + + + + + + + + CommandLine + void + + + executable + File + + + false + false + + + true + + + + + + 2 + + + + + + + + CommandLine + void + + + other + CommandLine + + + false + false + + + true + + + + + + 2 + + + + + + + + getExecutable + String + + false + false + + + true + + + + + + 2 + + + + + + + + isFile + boolean + + false + false + + + true + + + + + + 2 + + + + + + + + addArguments + CommandLine + + + arguments + String[] + + + false + false + + + true + + + + + + 2 + + + + + + + + addArguments + CommandLine + + + arguments + String[] + + + handleQuoting + boolean + + + false + false + + + true + + + + + + 2 + + + + + + + + addArguments + CommandLine + + + arguments + String + + + false + false + + + true + + + + + + 2 + + + + + + + + addArguments + CommandLine + + + arguments + String + + + handleQuoting + boolean + + + false + false + + + true + + + + + + 2 + + + + + + + + addArgument + CommandLine + + + argument + String + + + false + false + + + true + + + + + + 2 + + + + + + + + addArgument + CommandLine + + + argument + String + + + handleQuoting + boolean + + + false + false + + + true + + + + + + 2 + + + + + + + + getArguments + String[] + + false + false + + + true + + + + + + 2 + + + + + + + + getSubstitutionMap + Map + + false + false + + + true + + + + + + 2 + + + + + + + + setSubstitutionMap + void + + + substitutionMap + Map + + + false + false + + + true + + + + + + 2 + + + + + + + + toStrings + String[] + + false + false + + + true + + + + + + 2 + + + + + + + + toString + String + + false + false + + + true + + + + + + 2 + + + + + + + + expandArgument + String + + + argument + String + + + false + false + + + true + + + + + + 2 + + + + + + + + translateCommandline + String[] + + + toProcess + String + + + false + true + + + true + + + + + + 2 + + + + + + + + getExecutable + String + + + executable + String + + + false + false + + + true + + + + + + 2 + + + + + + + + + + true + + + + + + 2 + + + + + + + false + + + _stereo_type + Stereo Type + false + + + _simpleEntityName + Simple Name + false + + + _entityName + Name + false + + + _background + Background Color + false + + + _attrs + Attributes... + false + + + _operations + Operations... + false + + + _abstract + abstract + false + + + + org.apache.commons.exec.CommandLineTest + + -1 + -1 + 819 + 139 + + + + + + + assertEquals + void + + + expected + String[] + + + actual + String[] + + + false + false + + + true + + + + + + 2 + + + + + + + + testExecutable + void + + false + false + + + true + + + + + + 2 + + + + + + + + testExecutableZeroLengthString + void + + false + false + + + true + + + + + + 2 + + + + + + + + testExecutableWhitespaceString + void + + false + false + + + true + + + + + + 2 + + + + + + + + testNullExecutable + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArgument + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddNullArgument + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArgumentWithSpace + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArgumentWithQuote + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArgumentWithQuotesAround + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArgumentWithSingleQuote + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArgumentWithBothQuotes + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArguments + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArgumentsWithQuotes + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArgumentsWithQuotesAndSpaces + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArgumentsArray + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArgumentsArrayNull + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddTwoArguments + void + + false + false + + + true + + + + + + 2 + + + + + + + + testParseCommandLine + void + + false + false + + + true + + + + + + 2 + + + + + + + + testParseCommandLineWithQuotes + void + + false + false + + + true + + + + + + 2 + + + + + + + + testParseCommandLineWithUnevenQuotes + void + + false + false + + + true + + + + + + 2 + + + + + + + + testParseCommandLineWithNull + void + + false + false + + + true + + + + + + 2 + + + + + + + + testParseCommandLineWithOnlyWhitespace + void + + false + false + + + true + + + + + + 2 + + + + + + + + testParseComplexCommandLine1 + void + + false + false + + + true + + + + + + 2 + + + + + + + + testParseComplexCommandLine2 + void + + false + false + + + true + + + + + + 2 + + + + + + + + testParseRealLifeCommandLine_1 + void + + false + false + + + true + + + + + + 2 + + + + + + + + testComplexAddArgument + void + + false + false + + + true + + + + + + 2 + + + + + + + + testComplexAddArguments1 + void + + false + false + + + true + + + + + + 2 + + + + + + + + testComplexAddArguments2 + void + + false + false + + + true + + + + + + 2 + + + + + + + + testCommandLineParsingWithExpansion1 + void + + false + false + + + true + + + + + + 2 + + + + + + + + testCommandLineParsingWithExpansion2 + void + + false + false + + + true + + + + + + 2 + + + + + + + + testCommandLineParsingWithExpansion3 + void + + false + false + + + true + + + + + + 2 + + + + + + + + testToString + void + + false + false + + + true + + + + + + 2 + + + + + + + + testToStringTroubleshooting + void + + false + false + + + true + + + + + + 2 + + + + + + + + _testExec36_1 + void + + false + false + + + true + + + + + + 2 + + + + + + + + _testExec36_2 + void + + false + false + + + true + + + + + + 2 + + + + + + + + _testExec36_3 + void + + false + false + + + true + + + + + + 2 + + + + + + + + testCopyConstructor + void + + false + false + + + true + + + + + + 2 + + + + + + + + + + true + + + + + + 2 + + + + + + + + + + true + + + + + 2 + + + + + \ No newline at end of file diff --git a/ApacheCommonsExec/build.xml b/ApacheCommonsExec/build.xml new file mode 100644 index 0000000..dae6f05 --- /dev/null +++ b/ApacheCommonsExec/build.xml @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ================================= WARNING ================================ + JUnit isn't present in your classpath. Tests not executed. + ========================================================================== + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ApacheCommonsExec/doap_exec.rdf b/ApacheCommonsExec/doap_exec.rdf new file mode 100644 index 0000000..75fc87c --- /dev/null +++ b/ApacheCommonsExec/doap_exec.rdf @@ -0,0 +1,58 @@ + + + + + Apache Commons Exec + Commons Exec + + Java + + + + + + A library to reliably execute external processes from within the JVM + + A library to reliably execute external processes from within the JVM + + + + commons-exec + 2010-10-08 + 1.1 + + + commons-exec + 2009-09-23 + 1.0.1 + + + commons-exec + 2009-03-25 + 1.0 + + + + + + + + + + + diff --git a/ApacheCommonsExec/findbugs-exclude-filter.xml b/ApacheCommonsExec/findbugs-exclude-filter.xml new file mode 100644 index 0000000..ec557f4 --- /dev/null +++ b/ApacheCommonsExec/findbugs-exclude-filter.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + diff --git a/ApacheCommonsExec/pom.xml b/ApacheCommonsExec/pom.xml new file mode 100644 index 0000000..438075c --- /dev/null +++ b/ApacheCommonsExec/pom.xml @@ -0,0 +1,270 @@ + + + + + org.apache.commons + commons-parent + 18 + + 4.0.0 + Commons Exec + org.apache.commons + commons-exec + 1.1.1-SNAPSHOT + A library to reliably execute external processes from within the JVM + http://commons.apache.org/exec/ + + jira + http://issues.apache.org/jira/browse/EXEC + + + + junit + junit + + 3.8.1 + test + + + + + brett + Brett Porter + Apache + +10 + + + trygvis + Trygve Laugstøl + Apache + +1 + + + sgoeschl + Siegfried Goeschl + Apache + +1 + + + sebb + Sebastian Bazley + Apache + +1 + + + + + Niklas Gustavsson + + + Benjamin Bentmann + + + Marco Ferrante + + + Jerome Lacoste + + + Milos Kleint + + + Pablo Hoertner + + + Niall Pemberton + + + + scm:svn:http://svn.apache.org/repos/asf/commons/proper/exec/trunk + scm:svn:https://svn.apache.org/repos/asf/commons/proper/exec/trunk + http://svn.apache.org/viewvc/commons/proper/exec/trunk + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/TestUtil.java + + + + + maven-assembly-plugin + + + src/assembly/bin.xml + src/assembly/src.xml + + gnu + + + + org.apache.maven.plugins + maven-jar-plugin + + + + true + true + + + + + + org.apache.maven.plugins + maven-release-plugin + 2.0 + + forked-path + + + + + + + website + Apache Website + ${commons.deployment.protocol}://people.apache.org/www/commons.apache.org/exec/ + + + + + + + org.apache.maven.plugins + maven-changes-plugin + 2.0 + + %URL%/%ISSUE% + + + + + changes-report + + + + + + org.codehaus.mojo + findbugs-maven-plugin + 1.2 + + Normal + Default + ${basedir}/findbugs-exclude-filter.xml + + + + + + + + coverage + + + + + org.codehaus.mojo + cobertura-maven-plugin + 2.0 + + + + + + rc + + + + apache.website + Apache Commons Release Candidate Staging Site + + ${commons.deployment.protocol}://people.apache.org/www/people.apache.org/builds/commons/${commons.componentid}/${commons.release.version}/${commons.rc.version}/site + + + + + + + + test-distribution + + + + maven-assembly-plugin + + + src/assembly/test-distribution.xml + + gnu + + + + package + + assembly + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + true + true + + + + + + + jar + test-jar + + + + + + + + + + + 1.3 + 1.3 + *Test + exec + EXEC + 12310814 + 1.1 + + RC1 + + UTF-8 + UTF-8 + + diff --git a/ApacheCommonsExec/src/assembly/bin.xml b/ApacheCommonsExec/src/assembly/bin.xml new file mode 100644 index 0000000..1f92645 --- /dev/null +++ b/ApacheCommonsExec/src/assembly/bin.xml @@ -0,0 +1,43 @@ + + + bin + + tar.gz + zip + + false + + + + LICENSE.txt + NOTICE.txt + + + + target + + + *.jar + + + + target/site/apidocs + apidocs + + + diff --git a/ApacheCommonsExec/src/assembly/src.xml b/ApacheCommonsExec/src/assembly/src.xml new file mode 100644 index 0000000..ddc4fa3 --- /dev/null +++ b/ApacheCommonsExec/src/assembly/src.xml @@ -0,0 +1,39 @@ + + + src + + tar.gz + zip + + ${artifactId}-${commons.release.version}-src + + + + build.xml + LICENSE.txt + NOTICE.txt + pom.xml + STATUS + findbugs-exclude-filter.xml + + + + src + + + diff --git a/ApacheCommonsExec/src/assembly/test-distribution.xml b/ApacheCommonsExec/src/assembly/test-distribution.xml new file mode 100644 index 0000000..6cb395c --- /dev/null +++ b/ApacheCommonsExec/src/assembly/test-distribution.xml @@ -0,0 +1,68 @@ + + + test + + tar.gz + zip + + + + + + LICENSE.txt + NOTICE.txt + + + + src/test/bin + + + testme.bat + testme.dcl + + true + + + src/test/scripts + + + target + lib + + ${artifact.artifactId}-${artifact.version}.jar + ${artifact.artifactId}-${artifact.version}-tests.jar + + + + + + src/test/bin/testme.sh + 775 + true + + + + + test + + junit:junit + + lib + + + diff --git a/ApacheCommonsExec/src/changes/changes.xml b/ApacheCommonsExec/src/changes/changes.xml new file mode 100644 index 0000000..b85f320 --- /dev/null +++ b/ApacheCommonsExec/src/changes/changes.xml @@ -0,0 +1,233 @@ + + + + + commons-exec + Siegfried Goeschl + + + + + Applied the patch from Nickolay Martinov but the timeout disguises the fact + that the process might be still runnung - therefore added a sanity check in + order to throw an exception if the the timeout for join() was exceeded. + + + Fixed dead lock by calling the timeout observers outside of the synchronized block thereby + removing on pre-requisite of a deadlock. Also added a test case to demonstrate that this + problem is fixed (which of course can not guarantee the absence of a dead lock). + + + Set names for started threads. + + + Tests fail on HP-UX, because it uses a different syntax for the ping command. + + + "Write dead end" IOException when using Piped streams w/PumpStreamHandler. + When encountering a PipedOutputStream we will automatically close it to avoid + the exception. + + + Race condition prevent watchdog working using ExecuteStreamHandler. + Patch submitted by Kristian Rosenvold. + + + + + OpenVMS now uses symbols instead of logicals for environment variables. + + + Adding 'Argument' class and quote the arguments after expansion. + + + Reverting changes of [EXEC-41] because the patch does not fix the problem. + Also added test case for the broken patch. + + + Added TutorialTest as a playground for new user and removed + similar code from DefaultExecutorTest. + + + String substitution handles now java.io.File instances in order + to create a cross-platform file name. + + + The 'forever.bat' accidentally overwrite the 'forever.txt' instead of + appending. + + + DefaultExecutor() now sets the working directory with the current working + directory. + + + Added 'DefaultExecutorTest#testStdInHandling' to show how + commons-exec can feed the 'stdin' of a child process. + + + Improved the documentation. + + + Added a PumpStreamHandler.setAlwaysWaitForStreamThreads() which allows to skip + joining with the pumper threads. Having said that - using that flag is for the + desperate because it could leave up to three worker threads behind but there + might be situations where this is the only escape. + + + Process.waitFor should clear interrupt status when throwing InterruptedException + + + Added 'DefaultExecuteResultHandler' + + + Added a new section to the tutorial to show working with asynchronous + processes. Thanks to Pablo for providing this documentation update. + + + Because the ExecuteWatchdog is the only way to destroy asynchronous processes, + it should be possible to set it to an infinite timeout, for processes which + should not timeout, but manually destroyed under some circumstances. + + + + + On a Mac, the unit tests never finish. Culprit is InputStreamPumper which + sets its stop member in the run method; however, run might really be executed + after the stopProcessing method is called if the process + thread completes before the InputStreamPumper starts. + + + Fixes NPE in DefaultExecutor.setExitValues(). + + + Copies all data from an System.input stream to an output stream of + the executed process. + + + + + Removed useless synchronized statement in + OpenVmsProcessingEnvironment.createProcEnvironment + + + Using System.in for child process will actually hang your application - + see JIRA for more details. Since there is no easy fix an + IllegalRuntimeException is thrown when System.in is passed. + + + Fixing a few findbugs issues. + + + Handle null streams consistently. + + + After a long discussion we decided to stick to following groupId + "org.apache.commons" instead of "commons-exec". + + + The Ant build now works even when junit is not on the classpath + + + Fixed broken "groupId" from "org.apache.commons" to "commons-exec" + + + Renamed EnvironmentUtil to EnvironmentUtils to align with other classes + in this project and commons in general. Please note that this change + could break existing clients (but would be rather unlikely). + + + Make environment variables respect casing rules of platforms. Under Windows + "PATH", "Path" and "path" would access the same environment variable whereas + the real name is "Path". + + + Invoking DefaultExecutor.execute(CommandLine command, Map environment) using + a 'null' Map results in inheriting all environment variables of the current + process while passing an empty map implies starting the new process with no + environment variables. In short 'null' is not the same as an empty map. + + + Added one additional test : DefaultExecutorTest.testExecuteWithFancyArg + + + Using variable substitution within CommandLine broke the regression tests + under Windows. Found also another bug when calling CommandLine.getExecutable() + the result was not substituted at all. As a general rule we do variable + substitution and file separator fixing on the command line executable and + variable substitution but NO file separator fixing for the command line + arguments. + + + Added convinience method to add two parameters to the CommandLine + using one method invocation. + + + Implemented better regression test for OpenVMS affecting also + the Executor and CommandLauncher interface. + + + Added test scripts for OpenVMS - he seems to be the last human + having access to an OpenVMS box ... :-) + + + With the help of the Apache Commons community I added the first results + of cross-OS testing. + + + The regression tests now also works on Windows - so it should + work now on Linux, Windows and Mac OS X + + + Added DebugUtils to improve cross-platform testing. + + + Removed commons-logging integration + + + Made DefaultExecutor.launch() protected to enable mocking. + + + Made ProcessDestroyer optional and pluggable when using Executor. + + + CommandLine can now expand the given command line by a user-suppied + map. This allows to execute something like "${JAVA_HOME}/bin/java -jar ${myapp}" + + + Added methods to provide pre-quoted arguments. + + + Exposing a ExecuteWatchdog.destroy() to kill an asynchrounous process + manually. This formalizes a workaround described in the JIRA + + + Extending exit value handling to support applications returning an error + code. + + + Cleaned up the source code to get rid of javadoc errors and + unused imports. + + + Added a few regression tests for the watchdog since they were missing. + + + + diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/CommandLine.java b/ApacheCommonsExec/src/org/apache/commons/exec/CommandLine.java new file mode 100644 index 0000000..cf006cf --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/CommandLine.java @@ -0,0 +1,441 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec; + +import org.apache.commons.exec.util.StringUtils; + +import java.io.File; +import java.util.HashMap; +import java.util.Iterator; +import java.util.StringTokenizer; +import java.util.Vector; +import java.util.Map; + +/** + * CommandLine objects help handling command lines specifying processes to + * execute. The class can be used to a command line by an application. + */ +public class CommandLine { + + /** + * The arguments of the command. + */ + private final Vector 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 substitutionMap; + + /** + * Was a file being used to set the executable? + */ + private final boolean isFile; + + /** + * Create a command line from a string. + * + * @param line the first element becomes the executable, the rest the arguments + * @return the parsed command line + * @throws IllegalArgumentException If line is null or all whitespace + */ + public static CommandLine parse(final String line) { + return parse(line, null); + } + + /** + * Create a command line from a string. + * + * @param line the first element becomes the executable, the rest the arguments + * @param substitutionMap the name/value pairs used for substitution + * @return the parsed command line + * @throws IllegalArgumentException If line is null or all whitespace + */ + public static CommandLine parse(final String line, Map substitutionMap) { + + if (line == null) { + throw new IllegalArgumentException("Command line can not be null"); + } else if (line.trim().length() == 0) { + throw new IllegalArgumentException("Command line can not be empty"); + } else { + String[] tmp = translateCommandline(line); + + CommandLine cl = new CommandLine(tmp[0]); + cl.setSubstitutionMap(substitutionMap); + for (int i = 1; i < tmp.length; i++) { + cl.addArgument(tmp[i]); + } + + return cl; + } + } + + /** + * Create a command line without any arguments. + * + * @param executable the executable + */ + public CommandLine(String executable) { + this.isFile=false; + this.executable=getExecutable(executable); + } + + /** + * Create a command line without any arguments. + * + * @param executable the executable file + */ + public CommandLine(File executable) { + this.isFile=true; + this.executable=getExecutable(executable.getAbsolutePath()); + } + + /** + * Copy constructor. + * + * @param other the instance to copy + */ + public CommandLine(CommandLine other) + { + this.executable = other.getExecutable(); + this.isFile = other.isFile(); + this.arguments.addAll(other.arguments); + + if(other.getSubstitutionMap() != null) + { + this.substitutionMap = new HashMap(); + Iterator iterator = other.substitutionMap.keySet().iterator(); + while(iterator.hasNext()) + { + Object key = iterator.next(); + this.substitutionMap.put(key, other.getSubstitutionMap().get(key)); + } + } + } + + /** + * Returns the executable. + * + * @return The executable + */ + 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)); + } + + /** + * Was a file being used to set the executable? + * + * @return true if a file was used for setting the executable + */ + public boolean isFile(){ + return isFile; + } + + /** + * Add multiple arguments. Handles parsing of quotes and whitespace. + * + * @param arguments An array of arguments + * @return The command line itself + */ + public CommandLine addArguments(final String[] arguments) { + return this.addArguments(arguments, true); + } + + /** + * Add multiple arguments. + * + * @param arguments An array of arguments + * @param handleQuoting Add the argument with/without handling quoting + * @return The command line itself + */ + public CommandLine addArguments(final String[] arguments, boolean handleQuoting) { + if (arguments != null) { + for (int i = 0; i < arguments.length; i++) { + addArgument(arguments[i], handleQuoting); + } + } + + return this; + } + + /** + * Add multiple arguments. Handles parsing of quotes and whitespace. + * Please note that the parsing can have undesired side-effects therefore + * it is recommended to build the command line incrementally. + * + * @param arguments An string containing multiple arguments. + * @return The command line itself + */ + public CommandLine addArguments(final String arguments) { + return this.addArguments(arguments, true); + } + + /** + * Add multiple arguments. Handles parsing of quotes and whitespace. + * Please note that the parsing can have undesired side-effects therefore + * it is recommended to build the command line incrementally. + * + * @param arguments An string containing multiple arguments. + * @param handleQuoting Add the argument with/without handling quoting + * @return The command line itself + */ + public CommandLine addArguments(final String arguments, boolean handleQuoting) { + if (arguments != null) { + String[] argumentsArray = translateCommandline(arguments); + addArguments(argumentsArray, handleQuoting); + } + + return this; + } + + /** + * Add a single argument. Handles quoting. + * + * @param argument The argument to add + * @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); + } + + /** + * Add a single argument. + * + * @param argument The argument to add + * @param handleQuoting Add the argument with/without handling quoting + * @return The command line itself + */ + public CommandLine addArgument(final String argument, 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; + } + + /** + * Returns the expanded and quoted command line arguments. + * + * @return The quoted arguments + */ + public String[] getArguments() { + + Argument currArgument; + String expandedArgument; + String[] result = new String[arguments.size()]; + + for(int i=0; i" parameter (including quotes) and it is simply not possible to + * do that without adding a space, e.g. "500x> ". + */ + public void testParseComplexCommandLine1() { + HashMap substitutionMap = new HashMap(); + substitutionMap.put("in", "source.jpg"); + substitutionMap.put("out", "target.jpg"); + 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. + */ + public void testParseComplexCommandLine2() { + + 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"; + + CommandLine cmdl = CommandLine.parse(commandline); + 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 + */ + public void testParseRealLifeCommandLine_1() { + + String commandline = "cmd.exe /C \"c:\\was51\\Web Sphere\\AppServer\\bin\\versionInfo.bat\""; + + CommandLine cmdl = CommandLine.parse(commandline); + 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\"" + */ + public void testComplexAddArgument() { + 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); + assertEquals(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\"" + */ + public void testComplexAddArguments1() { + CommandLine cmdl = new CommandLine("runMemorySud.cmd"); + cmdl.addArguments(new String[] {"10", "30", "-XX:+UseParallelGC", "\"-XX:ParallelGCThreads=2\""}, false); + assertEquals(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. + */ + public void testComplexAddArguments2() { + CommandLine cmdl = new CommandLine("runMemorySud.cmd"); + cmdl.addArguments("10 30 -XX:+UseParallelGC '\"-XX:ParallelGCThreads=2\"'", false); + assertEquals(new String[] {"runMemorySud.cmd", "10", "30", "-XX:+UseParallelGC", "\"-XX:ParallelGCThreads=2\""}, cmdl.toStrings()); + } + + /** + * Test expanding the command line based on a user-supplied map. + */ + public void testCommandLineParsingWithExpansion1() { + + CommandLine cmdl; + + HashMap substitutionMap = new HashMap(); + substitutionMap.put("JAVA_HOME", "/usr/local/java"); + substitutionMap.put("appMainClass", "foo.bar.Main"); + substitutionMap.put("file1", new File("./pom.xml")); + substitutionMap.put("file2", new File(".\\temp\\READ ME.txt")); + + HashMap incompleteMap = new HashMap(); + incompleteMap.put("JAVA_HOME", "/usr/local/java"); + + // do not pass substitution map + cmdl = CommandLine.parse("${JAVA_HOME}/bin/java ${appMainClass}"); + assertTrue(cmdl.getExecutable().indexOf("${JAVA_HOME}") == 0 ); + assertEquals(new String[] {"${appMainClass}"}, cmdl.getArguments()); + + // pass arguments with an empty map + cmdl = CommandLine.parse("${JAVA_HOME}/bin/java ${appMainClass}", new HashMap()); + assertTrue(cmdl.getExecutable().indexOf("${JAVA_HOME}") == 0 ); + assertEquals(new String[] {"${appMainClass}"}, cmdl.getArguments()); + + // pass an complete substitution map + cmdl = CommandLine.parse("${JAVA_HOME}/bin/java ${appMainClass}", substitutionMap); + assertTrue(cmdl.getExecutable().indexOf("${JAVA_HOME}") < 0 ); + assertTrue(cmdl.getExecutable().indexOf("local") > 0 ); + assertEquals(new String[] {"foo.bar.Main"}, cmdl.getArguments()); + + // pass an incomplete substitution map resulting in unresolved variables + cmdl = CommandLine.parse("${JAVA_HOME}/bin/java ${appMainClass}", incompleteMap); + assertTrue(cmdl.getExecutable().indexOf("${JAVA_HOME}") < 0 ); + assertTrue(cmdl.getExecutable().indexOf("local") > 0 ); + assertEquals(new String[] {"${appMainClass}"}, cmdl.getArguments()); + + // pass a file + cmdl = CommandLine.parse("${JAVA_HOME}/bin/java ${appMainClass} ${file1} ${file2}", substitutionMap); + assertTrue(cmdl.getExecutable().indexOf("${file}") < 0 ); + } + + /** + * Test expanding the command line based on a user-supplied map. The main + * goal of the test is to setup a command line using macros and reuse + * it multiple times. + */ + public void testCommandLineParsingWithExpansion2() { + + CommandLine cmdl; + String[] result; + + // build the user supplied parameters + HashMap substitutionMap = new HashMap(); + substitutionMap.put("JAVA_HOME", "C:\\Programme\\jdk1.5.0_12"); + substitutionMap.put("appMainClass", "foo.bar.Main"); + + // build the command line + cmdl = new CommandLine("${JAVA_HOME}\\bin\\java"); + cmdl.addArgument("-class"); + cmdl.addArgument("${appMainClass}"); + cmdl.addArgument("${file}"); + + // build the first command line + substitutionMap.put("file", "C:\\Document And Settings\\documents\\432431.pdf"); + cmdl.setSubstitutionMap(substitutionMap); + result = cmdl.toStrings(); + + // verify the first command line + // please note - the executable argument is changed to using platform specific file separator char + // whereas all other variable substitution are not touched + assertEquals(StringUtils.fixFileSeparatorChar("C:\\Programme\\jdk1.5.0_12\\bin\\java"), result[0]); + assertEquals("-class", result[1]); + assertEquals("foo.bar.Main", result[2]); + assertEquals("\"C:\\Document And Settings\\documents\\432431.pdf\"", result[3]); + + // verify the first command line again but by + // accessing the executable and arguments directly + String executable = cmdl.getExecutable(); + String[] arguments = cmdl.getArguments(); + assertEquals(StringUtils.fixFileSeparatorChar("C:\\Programme\\jdk1.5.0_12\\bin\\java"), executable); + assertEquals("-class", arguments[0]); + assertEquals("foo.bar.Main", arguments[1]); + assertEquals("\"C:\\Document And Settings\\documents\\432431.pdf\"", arguments[2]); + + // build the second command line with updated parameters resulting in a different command line + substitutionMap.put("file", "C:\\Document And Settings\\documents\\432432.pdf"); + result = cmdl.toStrings(); + assertEquals(StringUtils.fixFileSeparatorChar("C:\\Programme\\jdk1.5.0_12\\bin\\java"), result[0]); + assertEquals("-class", result[1]); + assertEquals("foo.bar.Main", result[2]); + assertEquals("\"C:\\Document And Settings\\documents\\432432.pdf\"", result[3]); + } + + public void testCommandLineParsingWithExpansion3(){ + CommandLine cmdl = CommandLine.parse("AcroRd32.exe"); + cmdl.addArgument("/p"); + cmdl.addArgument("/h"); + cmdl.addArgument("${file}", false); + HashMap params = new HashMap(); + params.put("file", "C:\\Document And Settings\\documents\\432432.pdf"); + cmdl.setSubstitutionMap(params); + String[] result = cmdl.toStrings(); + assertEquals("AcroRd32.exe", result[0]); + assertEquals("/p", result[1]); + assertEquals("/h", result[2]); + assertEquals("C:\\Document And Settings\\documents\\432432.pdf", result[3]); + + } + /** + * Test the toString() method. + * + * @throws Exception the test failed + */ + public void testToString() throws Exception { + CommandLine cmdl; + HashMap params = new HashMap(); + + // use no arguments + cmdl = CommandLine.parse("AcroRd32.exe", params); + assertEquals("[AcroRd32.exe]", cmdl.toString()); + + // use an argument containing spaces + params.put("file", "C:\\Document And Settings\\documents\\432432.pdf"); + cmdl = CommandLine.parse("AcroRd32.exe /p /h '${file}'", params); + assertEquals("[AcroRd32.exe, /p, /h, \"C:\\Document And Settings\\documents\\432432.pdf\"]", cmdl.toString()); + + // use an argument without spaces + params.put("file", "C:\\documents\\432432.pdf"); + cmdl = CommandLine.parse("AcroRd32.exe /p /h '${file}'", params); + assertEquals("[AcroRd32.exe, /p, /h, C:\\documents\\432432.pdf]", cmdl.toString()); + } + + /** + * Test that toString() produces output that is useful for troubleshooting. + * + * @throws Exception the test failed + */ + public void testToStringTroubleshooting() throws Exception { + System.out.println("testToStringTroubleshooting"); + // On HP-UX quotes handling leads to errors, + // also usage of quotes isn't mandatory on other platforms too + // so it probably should work correctly either way. + CommandLine cmd1 = new CommandLine("sh").addArgument("-c") + .addArgument("echo 1", false); + CommandLine cmd2 = new CommandLine("sh").addArgument("-c") + .addArgument("echo").addArgument("1"); + System.out.println("cmd1: " + cmd1.toString()); + System.out.println("cmd2: " + cmd2.toString()); + assertTrue("toString() is useful for troubleshooting", + !cmd1.toString().equals(cmd2.toString())); + } + + /** + * Some complex real-life command line from + * http://blogs.msdn.com/b/astebner/archive/2005/12/13/503471.aspx + */ + public void _testExec36_1() throws Exception { + + CommandLine cmdl; + + 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); + 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 + */ + public void _testExec36_2() { + + CommandLine cmdl; + + 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); + 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" + */ + public void _testExec36_3() { + + String commandline = "C:\\CVS_DB\\WeightsEngine /f WeightsEngine.mak CFG=\"WeightsEngine - Win32Release\""; + + CommandLine cmdl = CommandLine.parse(commandline); + String[] args = cmdl.getArguments(); + assertEquals("/f", args[0]); + assertEquals("WeightsEngine.mak", args[1]); + assertEquals("CFG=\"WeightsEngine - Win32Release\"", args[2]); + } + + public void testCopyConstructor() + { + Map map = new HashMap(); + map.put("bar", "bar"); + CommandLine other = new CommandLine("test"); + other.addArgument("foo"); + other.setSubstitutionMap(map); + + CommandLine cmdl = new CommandLine(other); + assertEquals(other.getExecutable(), cmdl.getExecutable()); + assertEquals(other.getArguments(), cmdl.getArguments()); + assertEquals(other.isFile(), cmdl.isFile()); + assertEquals(other.getSubstitutionMap(), cmdl.getSubstitutionMap()); + + } + +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/DefaultExecuteResultHandler.java b/ApacheCommonsExec/src/org/apache/commons/exec/DefaultExecuteResultHandler.java new file mode 100644 index 0000000..97cc0e0 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/DefaultExecuteResultHandler.java @@ -0,0 +1,144 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec; + +/** + * A default implementation of 'ExecuteResultHandler' used for asynchronous + * process handling. + */ +public class DefaultExecuteResultHandler implements ExecuteResultHandler { + + /** the interval polling the result */ + private static final int SLEEP_TIME_MS = 50; + + /** Keep track if the process is still running */ + private volatile boolean hasResult; + + /** The exit value of the finished process */ + private volatile int exitValue; + + /** Any offending exception */ + private volatile ExecuteException exception; + + /** + * Constructor. + */ + public DefaultExecuteResultHandler() { + this.hasResult = false; + this.exitValue = Executor.INVALID_EXITVALUE; + } + + /** + * @see org.apache.commons.exec.ExecuteResultHandler#onProcessComplete(int) + */ + public void onProcessComplete(int exitValue) { + this.exitValue = exitValue; + this.exception = null; + this.hasResult = true; + } + + /** + * @see org.apache.commons.exec.ExecuteResultHandler#onProcessFailed(org.apache.commons.exec.ExecuteException) + */ + public void onProcessFailed(ExecuteException e) { + this.exitValue = e.getExitValue(); + this.exception = e; + this.hasResult = true; + } + + /** + * Get the exception causing the process execution to fail. + * + * @return Returns the exception. + * @throws IllegalStateException if the process has not exited yet + */ + public ExecuteException getException() { + + if(!hasResult) { + throw new IllegalStateException("The process has not exited yet therefore no result is available ..."); + } + + return exception; + } + + /** + * Get the exitValue of the process. + * + * @return Returns the exitValue. + * @throws IllegalStateException if the process has not exited yet + */ + public int getExitValue() { + + if(!hasResult) { + throw new IllegalStateException("The process has not exited yet therefore no result is available ..."); + } + + return exitValue; + } + + /** + * Has the process exited and a result is available, i.e. exitCode or exception? + * + * @return true if a result of the execution is available + */ + public boolean hasResult() { + return hasResult; + } + + /** + * Causes the current thread to wait, if necessary, until the + * process has terminated. This method returns immediately if + * the process has already terminated. If the process has + * not yet terminated, the calling thread will be blocked until the + * process exits. + * + * @exception InterruptedException if the current thread is + * {@linkplain Thread#interrupt() interrupted} by another + * thread while it is waiting, then the wait is ended and + * an {@link InterruptedException} is thrown. + */ + public void waitFor() throws InterruptedException { + + while (!hasResult()) { + Thread.sleep(SLEEP_TIME_MS); + } + } + + /** + * Causes the current thread to wait, if necessary, until the + * process has terminated. This method returns immediately if + * the process has already terminated. If the process has + * not yet terminated, the calling thread will be blocked until the + * process exits. + * + * @param timeout the maximum time to wait in milliseconds + * @exception InterruptedException if the current thread is + * {@linkplain Thread#interrupt() interrupted} by another + * thread while it is waiting, then the wait is ended and + * an {@link InterruptedException} is thrown. + */ + public void waitFor(long timeout) throws InterruptedException { + + long until = System.currentTimeMillis() + timeout; + + while (!hasResult() && (System.currentTimeMillis() < until)) { + Thread.sleep(SLEEP_TIME_MS); + } + } +} \ No newline at end of file diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/DefaultExecutor.java b/ApacheCommonsExec/src/org/apache/commons/exec/DefaultExecutor.java new file mode 100644 index 0000000..02987cd --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/DefaultExecutor.java @@ -0,0 +1,434 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +package org.apache.commons.exec; + +import java.io.File; +import java.io.IOException; +import java.util.Map; + +import org.apache.commons.exec.launcher.CommandLauncher; +import org.apache.commons.exec.launcher.CommandLauncherFactory; + +/** + * The default class to start a subprocess. The implementation + * allows to + *
    + *
  • set a current working directory for the subprocess
  • + *
  • provide a set of environment variables passed to the subprocess
  • + *
  • capture the subprocess output of stdout and stderr using an ExecuteStreamHandler
  • + *
  • kill long-running processes using an ExecuteWatchdog
  • + *
  • define a set of expected exit values
  • + *
  • terminate any started processes when the main process is terminating using a ProcessDestroyer
  • + *
+ * + * The following example shows the basic usage: + * + *
+ * Executor exec = new DefaultExecutor();
+ * CommandLine cl = new CommandLine("ls -l");
+ * int exitvalue = exec.execute(cl);
+ * 
+ */ +public class DefaultExecutor implements Executor { + + /** taking care of output and error stream */ + private ExecuteStreamHandler streamHandler; + + /** the working directory of the process */ + private File workingDirectory; + + /** monitoring of long running processes */ + private ExecuteWatchdog watchdog; + + /** the exit values considered to be successful */ + private int[] exitValues; + + /** launches the command in a new process */ + private final CommandLauncher launcher; + + /** optional cleanup of started processes */ + private ProcessDestroyer processDestroyer; + + /** worker thread for asynchronous execution */ + private Thread executorThread; + + /** the first exception being caught to be thrown to the caller */ + private IOException exceptionCaught; + + /** + * Default constructor creating a default PumpStreamHandler + * and sets the working directory of the subprocess to the current + * working directory. + * + * The PumpStreamHandler pumps the output of the subprocess + * into our System.out and System.err to avoid + * into our System.out and System.err to avoid + * a blocked or deadlocked subprocess (see{@link java.lang.Process Process}). + */ + public DefaultExecutor() { + this.streamHandler = new PumpStreamHandler(); + this.launcher = CommandLauncherFactory.createVMLauncher(); + this.exitValues = new int[0]; + this.workingDirectory = new File("."); + this.exceptionCaught = null; + } + + /** + * @see org.apache.commons.exec.Executor#getStreamHandler() + */ + public ExecuteStreamHandler getStreamHandler() { + return streamHandler; + } + + /** + * @see org.apache.commons.exec.Executor#setStreamHandler(org.apache.commons.exec.ExecuteStreamHandler) + */ + public void setStreamHandler(ExecuteStreamHandler streamHandler) { + this.streamHandler = streamHandler; + } + + /** + * @see org.apache.commons.exec.Executor#getWatchdog() + */ + public ExecuteWatchdog getWatchdog() { + return watchdog; + } + + /** + * @see org.apache.commons.exec.Executor#setWatchdog(org.apache.commons.exec.ExecuteWatchdog) + */ + public void setWatchdog(ExecuteWatchdog watchDog) { + this.watchdog = watchDog; + } + + /** + * @see org.apache.commons.exec.Executor#getProcessDestroyer() + */ + public ProcessDestroyer getProcessDestroyer() { + return this.processDestroyer; + } + + /** + * @see org.apache.commons.exec.Executor#setProcessDestroyer(ProcessDestroyer) + */ + public void setProcessDestroyer(ProcessDestroyer processDestroyer) { + this.processDestroyer = processDestroyer; + } + + /** + * @see org.apache.commons.exec.Executor#getWorkingDirectory() + */ + public File getWorkingDirectory() { + return workingDirectory; + } + + /** + * @see org.apache.commons.exec.Executor#setWorkingDirectory(java.io.File) + */ + public void setWorkingDirectory(File dir) { + this.workingDirectory = dir; + } + + /** + * @see org.apache.commons.exec.Executor#execute(CommandLine) + */ + public int execute(final CommandLine command) throws ExecuteException, + IOException { + return execute(command, (Map) null); + } + + /** + * @see org.apache.commons.exec.Executor#execute(CommandLine, 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); + + } + + /** + * @see org.apache.commons.exec.Executor#execute(CommandLine, + * org.apache.commons.exec.ExecuteResultHandler) + */ + public void execute(final CommandLine command, 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) + */ + public void execute(final CommandLine command, final Map environment, + final ExecuteResultHandler handler) throws ExecuteException, IOException { + + if (workingDirectory != null && !workingDirectory.exists()) { + throw new IOException(workingDirectory + " doesn't exist."); + } + + if (watchdog != null) { + watchdog.setProcessNotStarted(); + } + + Runnable runnable = new Runnable() + { + public void run() + { + int exitValue = Executor.INVALID_EXITVALUE; + try { + exitValue = executeInternal(command, environment, workingDirectory, streamHandler); + handler.onProcessComplete(exitValue); + } catch (ExecuteException e) { + handler.onProcessFailed(e); + } catch(Exception e) { + handler.onProcessFailed(new ExecuteException("Execution failed", exitValue, e)); + } + } + }; + + this.executorThread = createThread(runnable, "Exec Default Executor"); + getExecutorThread().start(); + } + + /** @see org.apache.commons.exec.Executor#setExitValue(int) */ + public void setExitValue(final int value) { + this.setExitValues(new int[] {value}); + } + + + /** @see org.apache.commons.exec.Executor#setExitValues(int[]) */ + public void setExitValues(final int[] values) { + this.exitValues = (values == null ? null : (int[]) values.clone()); + } + + /** @see org.apache.commons.exec.Executor#isFailure(int) */ + public boolean isFailure(final int exitValue) { + + if(this.exitValues == null) { + return false; + } + else if(this.exitValues.length == 0) { + return this.launcher.isFailure(exitValue); + } + else { + for(int i=0; iProcess
. + */ + private void closeProcessStreams(final Process process) { + + try { + process.getInputStream().close(); + } + catch(IOException e) { + setExceptionCaught(e); + } + + try { + process.getOutputStream().close(); + } + catch(IOException e) { + setExceptionCaught(e); + } + + try { + process.getErrorStream().close(); + } + catch(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. + * + * @param command the command to execute + * @param environment the execution environment + * @param dir the working directory + * @param streams process the streams (in, out, err) of the process + * @return the exit code of the process + * @throws IOException executing the process failed + */ + private int executeInternal(final CommandLine command, final Map environment, + final File dir, final ExecuteStreamHandler streams) throws IOException { + + setExceptionCaught(null); + + final Process process = this.launch(command, environment, dir); + + try { + streams.setProcessInputStream(process.getOutputStream()); + streams.setProcessOutputStream(process.getInputStream()); + streams.setProcessErrorStream(process.getErrorStream()); + } catch (IOException e) { + process.destroy(); + throw e; + } + + streams.start(); + + try { + + // add the process to the list of those to destroy if the VM exits + if(this.getProcessDestroyer() != null) { + this.getProcessDestroyer().add(process); + } + + // associate the watchdog with the newly created process + if (watchdog != null) { + watchdog.start(process); + } + + int exitValue = Executor.INVALID_EXITVALUE; + + try { + exitValue = process.waitFor(); + } catch (InterruptedException e) { + process.destroy(); + } + finally { + // see http://bugs.sun.com/view_bug.do?bug_id=6420270 + // see https://issues.apache.org/jira/browse/EXEC-46 + // Process.waitFor should clear interrupt status when throwing InterruptedException + // but we have to do that manually + Thread.interrupted(); + } + + if (watchdog != null) { + watchdog.stop(); + } + + try { + streams.stop(); + } + catch(IOException e) { + setExceptionCaught(e); + } + + closeProcessStreams(process); + + if(getExceptionCaught() != null) { + throw getExceptionCaught(); + } + + if (watchdog != null) { + try { + watchdog.checkException(); + } catch (IOException e) { + throw e; + } catch (Exception e) { + throw new IOException(e.getMessage()); + } + } + + if(this.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 exits + if(this.getProcessDestroyer() != null) { + this.getProcessDestroyer().remove(process); + } + } + } + + /** + * Keep track of the first IOException being thrown. + * + * @param e the IOException + */ + private void setExceptionCaught(IOException e) { + if(this.exceptionCaught == null) { + this.exceptionCaught = e; + } + } + + /** + * Get the first IOException being thrown. + * + * @return the first IOException being caught + */ + private IOException getExceptionCaught() { + return this.exceptionCaught; + } + +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/EnvironmentUtilTest.java b/ApacheCommonsExec/src/org/apache/commons/exec/EnvironmentUtilTest.java new file mode 100644 index 0000000..1db1da7 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/EnvironmentUtilTest.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; + +import junit.framework.TestCase; + +import org.apache.commons.exec.OS; +import org.apache.commons.exec.TestUtil; +import org.apache.commons.exec.environment.EnvironmentUtils; + +public class EnvironmentUtilTest extends TestCase { + + /** + * Tests the behaviour of the EnvironmentUtils.toStrings() + * when using a null environment. + */ + public void testToStrings() { + // check for a non-existing environment when passing null + TestUtil.assertEquals(null, EnvironmentUtils.toStrings(null), false); + // check for an environment when filling in two variables + Map env = new HashMap(); + TestUtil.assertEquals(new String[0], EnvironmentUtils.toStrings(env), false); + env.put("foo2", "bar2"); + env.put("foo", "bar"); + String[] envStrings = EnvironmentUtils.toStrings(env); + String[] expected = new String[]{"foo=bar", "foo2=bar2"}; + TestUtil.assertEquals(expected, envStrings, false); + } + + /** + * Test to access the environment variables of the current + * process. Please note that this test does not run on + * java-gjc. + * + * @throws IOException the test failed + */ + public void testGetProcEnvironment() throws IOException { + Map procEnvironment = EnvironmentUtils.getProcEnvironment(); + // we assume that there is at least one environment variable + // for this process, i.e. $JAVA_HOME + assertTrue("Expecting non-zero environment size", procEnvironment.size() > 0); + String[] envArgs = EnvironmentUtils.toStrings(procEnvironment); + for(int i=0; i 0); + // System.out.println(envArgs[i]); + } + } + + /** + * On Windows platforms test that accessing environment variables + * can be done in a case-insensitive way, e.g. "PATH", "Path" and + * "path" would reference the same environment variable. + * + * @throws IOException the test failed + */ + public void testGetProcEnvironmentCaseInsensitiveLookup() throws IOException { + // run tests only on windows platforms + if (!OS.isFamilyWindows()) { + return; + } + + // ensure that we have the same value for upper and lowercase keys + Map procEnvironment = EnvironmentUtils.getProcEnvironment(); + for (Iterator it = procEnvironment.entrySet().iterator(); it.hasNext();) { + Map.Entry entry = (Map.Entry) it.next(); + String key = (String) entry.getKey(); + String value = (String) entry.getValue(); + assertEquals(value, procEnvironment.get(key.toLowerCase(Locale.ENGLISH))); + assertEquals(value, procEnvironment.get(key.toUpperCase(Locale.ENGLISH))); + } + + // add an environment variable and check access + EnvironmentUtils.addVariableToEnvironment( procEnvironment, "foo=bar" ); + assertEquals("bar", procEnvironment.get("FOO")); + assertEquals("bar", procEnvironment.get("Foo")); + assertEquals("bar", procEnvironment.get("foo")); + } + + /** + * 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 + */ + public void testCaseInsensitiveVariableLookup() throws Exception { + Map procEnvironment = EnvironmentUtils.getProcEnvironment(); + // Check that case is preserved for values + EnvironmentUtils.addVariableToEnvironment( procEnvironment, "foo=bAr" ); + assertEquals("bAr", procEnvironment.get("foo")); + } + +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/ExecuteException.java b/ApacheCommonsExec/src/org/apache/commons/exec/ExecuteException.java new file mode 100644 index 0000000..cdaf17d --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/ExecuteException.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec; + +import java.io.IOException; + +/** + * An exception indicating that the executing a subprocesses failed. + */ +public class ExecuteException extends IOException { + + /** + * Comment for serialVersionUID. + */ + private static final long serialVersionUID = 3256443620654331699L; + + /** + * The underlying cause of this exception. + */ + private final Throwable cause; + + /** + * The exit value returned by the failed process + */ + private final int exitValue; + + /** + * Construct a new exception with the specified detail message. + * + * @param message + * The detail message + * @param exitValue The exit value + */ + public ExecuteException(final String message, int exitValue) { + super(message + " (Exit value: " + exitValue + ")"); + this.cause = null; + this.exitValue = exitValue; + } + + /** + * Construct a new exception with the specified detail message and cause. + * + * @param message + * The detail message + * @param exitValue The exit value + * @param cause + * The underlying cause + */ + public ExecuteException(final String message, int exitValue, final Throwable cause) { + super(message + " (Exit value: " + exitValue + ". Caused by " + cause + ")"); + this.cause = cause; // Two-argument version requires JDK 1.4 or later + this.exitValue = exitValue; + } + + /** + * Return the underlying cause of this exception (if any). + */ + public Throwable getCause() { + return (this.cause); + } + + /** + * Gets the exit value returned by the failed process + * @return The exit value + */ + public int getExitValue() { + return exitValue; + } +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/ExecuteResultHandler.java b/ApacheCommonsExec/src/org/apache/commons/exec/ExecuteResultHandler.java new file mode 100644 index 0000000..5a5cffa --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/ExecuteResultHandler.java @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec; + +/** + * The callback handlers for the result of asynchronous process execution. When a + * process is started asynchronously the callback provides you with the result of + * the executed process, i.e. the exit value or an exception. + * + * @see org.apache.commons.exec.Executor#execute(CommandLine, java.util.Map, ExecuteResultHandler) + */ +public interface ExecuteResultHandler { + + /** + * The asynchronous execution completed. + * + * @param exitValue the exit value of the sub-process + */ + void onProcessComplete(int exitValue); + + /** + * The asynchronous execution failed. + * + * @param e the ExecuteException containing the root cause + */ + void onProcessFailed(ExecuteException e); +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/ExecuteStreamHandler.java b/ApacheCommonsExec/src/org/apache/commons/exec/ExecuteStreamHandler.java new file mode 100644 index 0000000..874d6a3 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/ExecuteStreamHandler.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Used by Execute to handle input and output stream of + * subprocesses. + */ +public interface ExecuteStreamHandler { + + /** + * Install a handler for the input stream of the subprocess. + * + * @param os + * output stream to write to the standard input stream of the + * subprocess + */ + void setProcessInputStream(OutputStream os) throws IOException; + + /** + * Install a handler for the error stream of the subprocess. + * + * @param is + * input stream to read from the error stream from the subprocess + */ + void setProcessErrorStream(InputStream is) throws IOException; + + /** + * Install a handler for the output stream of the subprocess. + * + * @param is + * input stream to read from the error stream from the subprocess + */ + void setProcessOutputStream(InputStream is) throws IOException; + + /** + * Start handling of the streams. + */ + void start() throws IOException; + + /** + * Stop handling of the streams - will not be restarted. + * Will wait for pump threads to complete. + */ + void stop() throws IOException; +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/ExecuteWatchdog.java b/ApacheCommonsExec/src/org/apache/commons/exec/ExecuteWatchdog.java new file mode 100644 index 0000000..97de809 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/ExecuteWatchdog.java @@ -0,0 +1,233 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec; + +import org.apache.commons.exec.util.DebugUtils; + +/** + * Destroys a process running for too long. For example: + * + *
+ * ExecuteWatchdog watchdog = new ExecuteWatchdog(30000);
+ * Executer exec = new Executer(myloghandler, watchdog);
+ * exec.setCommandLine(mycmdline);
+ * int exitvalue = exec.execute();
+ * if (Execute.isFailure(exitvalue) && watchdog.killedProcess()) {
+ *     // it was killed on purpose by the watchdog
+ * }
+ * 
+ * + * When starting an asynchronous process than 'ExecuteWatchdog' is the + * keeper of the process handle. In some cases it is useful not to define + * a timeout (and pass 'INFINITE_TIMEOUT') and to kill the process explicitly + * using 'destroyProcess()'. + *

+ * Please note that ExecuteWatchdog is processed asynchronously, e.g. it might + * be still attached to a process even after the DefaultExecutor.execute + * has returned. + * + * @see org.apache.commons.exec.Executor + * @see org.apache.commons.exec.Watchdog + */ +public class ExecuteWatchdog implements TimeoutObserver { + + /** The marker for an infinite timeout */ + public static final long INFINITE_TIMEOUT = -1; + + /** The process to execute and watch for duration. */ + private Process process; + + /** Is a user-supplied timeout in use */ + private final boolean hasWatchdog; + + /** Say whether or not the watchdog is currently monitoring a process. */ + private boolean watch; + + /** Exception that might be thrown during the process execution. */ + private Exception caught; + + /** Say whether or not the process was killed due to running overtime. */ + private boolean killedProcess; + + /** Will tell us whether timeout has occurred. */ + private final Watchdog watchdog; + + /** Indicates that the process is verified as started */ + private volatile boolean processStarted; + + /** + * Creates a new watchdog with a given timeout. + * + * @param timeout + * the timeout for the process in milliseconds. It must be + * greater than 0 or 'INFINITE_TIMEOUT' + */ + public ExecuteWatchdog(final long timeout) { + this.killedProcess = false; + this.watch = false; + this.hasWatchdog = (timeout != INFINITE_TIMEOUT); + this.processStarted = false; + if(this.hasWatchdog) { + this.watchdog = new Watchdog(timeout); + this.watchdog.addTimeoutObserver(this); + } + else { + this.watchdog = null; + } + } + + /** + * Watches the given process and terminates it, if it runs for too long. All + * information from the previous run are reset. + * + * @param process + * the process to monitor. It cannot be null + * @throws IllegalStateException + * if a process is still being monitored. + */ + public synchronized void start(final Process process) { + if (process == null) { + throw new NullPointerException("process is null."); + } + if (this.process != null) { + throw new IllegalStateException("Already running."); + } + this.caught = null; + this.killedProcess = false; + this.watch = true; + this.process = process; + this.processStarted = true; + this.notifyAll(); + if(this.hasWatchdog) { + watchdog.start(); + } + } + + /** + * 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; + } + + /** + * Destroys the running process manually. + */ + public synchronized void destroyProcess() { + ensureStarted(); + this.timeoutOccured(null); + this.stop(); + } + + /** + * Called after watchdog has finished. + */ + public synchronized void timeoutOccured(final Watchdog w) { + try { + try { + // We must check if the process was not stopped + // before being here + if(process != null) { + process.exitValue(); + } + } catch (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 (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. + * + * @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; + } + } + + /** + * Indicates whether or not the watchdog is still monitoring the process. + * + * @return true if the process is still running, otherwise + * false. + */ + public synchronized boolean isWatching() { + ensureStarted(); + return watch; + } + + /** + * Indicates whether the last process run was killed. + * + * @return true if the process was killed + * false. + */ + public synchronized boolean killedProcess() { + return killedProcess; + } + + /** + * reset the monitor flag and the process. + */ + protected synchronized void cleanUp() { + watch = false; + process = null; + } + + void setProcessNotStarted(){ + processStarted = false; + } + + /** + * Ensures that the process is started, so we do not race with asynch execution. + * The caller of this method must be holding the lock on this + */ + private void ensureStarted(){ + while (!processStarted){ + try { + this.wait(); + } catch (InterruptedException e) { + throw new RuntimeException(e.getMessage()); + } + } + } +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/Executor.java b/ApacheCommonsExec/src/org/apache/commons/exec/Executor.java new file mode 100644 index 0000000..bbc356d --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/Executor.java @@ -0,0 +1,208 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec; + +import java.io.File; +import java.io.IOException; +import java.util.Map; + +/** + * The main abstraction to start an external process. + * + * The interface allows to + *

    + *
  • set a current working directory for the subprocess
  • + *
  • provide a set of environment variables passed to the subprocess
  • + *
  • capture the subprocess output of stdout and stderr using an ExecuteStreamHandler
  • + *
  • kill long-running processes using an ExecuteWatchdog
  • + *
  • define a set of expected exit values
  • + *
  • terminate any started processes when the main process is terminating using a ProcessDestroyer
  • + *
+ * + * The following example shows the basic usage: + * + *
+ * Executor exec = new DefaultExecutor();
+ * CommandLine cl = new CommandLine("ls -l");
+ * int exitvalue = exec.execute(cl);
+ * 
+ */ + +public interface Executor { + + /** Invalid exit code. */ + int INVALID_EXITVALUE = 0xdeadbeef; + + /** + * Define the 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 value the exit code representing successful execution + */ + void setExitValue(final int value); + + /** + * Define a list of exitValue of the process to be considered + * successful. The caller can pass one of the following values + *
    + *
  • an array of exit values to be considered successful
  • + *
  • an empty array for auto-detect of successful exit codes relying on {@link org.apache.commons.exec.Executor#isFailure(int)}
  • + *
  • null to indicate to skip checking of exit codes
  • + *
+ * + * 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 values a list of the exit codes + */ + void setExitValues(final int[] values); + + /** + * Checks whether 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. + * + * @param exitValue the exit value (return code) to be checked + * @return true if exitValue signals a failure + */ + boolean isFailure(final int exitValue); + + /** + * Get the StreamHandler used for providing input and + * retrieving the output. + * + * @return the StreamHandler + */ + ExecuteStreamHandler getStreamHandler(); + + /** + * Set 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 java.lang.Process Process}). + * + * @param streamHandler the stream handler + */ + void setStreamHandler(ExecuteStreamHandler streamHandler); + + /** + * Get the watchdog used to kill of processes running, + * typically, too long time. + * + * @return the watchdog + */ + ExecuteWatchdog getWatchdog(); + + /** + * Set the watchdog used to kill of processes running, + * typically, too long time. + * + * @param watchDog the watchdog + */ + void setWatchdog(ExecuteWatchdog watchDog); + + /** + * Set the handler for cleanup of started processes if the main process + * is going to terminate. + * + * @return the ProcessDestroyer + */ + ProcessDestroyer getProcessDestroyer(); + + /** + * Get the handler for cleanup of started processes if the main process + * is going to terminate. + * + * @param processDestroyer the ProcessDestroyer + */ + void setProcessDestroyer(ProcessDestroyer processDestroyer); + + /** + * Get the working directory of the created process. + * + * @return the working directory + */ + File getWorkingDirectory(); + + /** + * Set the working directory of the created process. The + * working directory must exist when you start the process. + * + * @param dir the working directory + */ + void setWorkingDirectory(File dir); + + /** + * Methods for starting synchronous execution. The child process inherits + * all environment variables of the parent process. + * + * @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)}. + */ + int execute(CommandLine command) + throws ExecuteException, IOException; + + /** + * Methods for starting synchronous execution. + * + * @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)}. + */ + int execute(CommandLine command, Map environment) + throws ExecuteException, IOException; + + /** + * Methods for starting asynchronous execution. The child process inherits + * all environment variables of the parent process. Result provided to + * callback handler. + * + * @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 asynchronous execution. The child process inherits + * all environment variables of the parent process. Result provided to + * callback handler. + * + * @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 + */ + void execute(CommandLine command, Map environment, ExecuteResultHandler handler) + throws ExecuteException, IOException; +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/InputStreamPumper.java b/ApacheCommonsExec/src/org/apache/commons/exec/InputStreamPumper.java new file mode 100644 index 0000000..ae26fee --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/InputStreamPumper.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec; + +import org.apache.commons.exec.util.DebugUtils; + +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Copies all data from an System.input stream to an output stream of the executed process. + * + * @author mkleint + */ +public class InputStreamPumper implements Runnable { + + public static final int SLEEPING_TIME = 100; + + /** the input stream to pump from */ + private final InputStream is; + + /** the output stream to pmp into */ + private final OutputStream os; + + /** flag to stop the stream pumping */ + private volatile boolean stop; + + + /** + * Create a new stream pumper. + * + * @param is input stream to read data from + * @param os output stream to write data to. + */ + public InputStreamPumper(final InputStream is, final OutputStream os) { + this.is = is; + this.os = os; + this.stop = false; + } + + + /** + * Copies data from the input stream to the output stream. Terminates as + * soon as the input stream is closed or an error occurs. + */ + public void run() { + try { + while (!stop) { + while (is.available() > 0 && !stop) { + os.write(is.read()); + } + os.flush(); + Thread.sleep(SLEEPING_TIME); + } + } catch (Exception e) { + String msg = "Got exception while reading/writing the stream"; + DebugUtils.handleException(msg ,e); + } finally { + } + } + + + public void stopProcessing() { + stop = true; + } + +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/LogOutputStream.java b/ApacheCommonsExec/src/org/apache/commons/exec/LogOutputStream.java new file mode 100644 index 0000000..fed8378 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/LogOutputStream.java @@ -0,0 +1,176 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * Base class to connect a logging system to the output and/or + * error stream of then external process. The implementation + * parses the incoming data to construct a line and passes + * the complete line to an user-defined implementation. + */ +public abstract class LogOutputStream + extends OutputStream { + + /** Initial buffer size. */ + private static final int INTIAL_SIZE = 132; + + /** Carriage return */ + private static final int CR = 0x0d; + + /** Linefeed */ + private static final int LF = 0x0a; + + /** the internal buffer */ + private final ByteArrayOutputStream buffer = new ByteArrayOutputStream( + INTIAL_SIZE); + + private boolean skip = false; + + private final int level; + + /** + * Creates a new instance of this class. + * Uses the default level of 999. + */ + public LogOutputStream() { + this(999); + } + + /** + * Creates a new instance of this class. + * + * @param level loglevel used to log data written to this stream. + */ + public LogOutputStream(final int level) { + this.level = level; + } + + /** + * Write the data to the buffer and flush the buffer, if a line separator is + * detected. + * + * @param cc data to log (byte). + * @see java.io.OutputStream#write(int) + */ + 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'); + } + + /** + * Flush this log stream. + * + * @see java.io.OutputStream#flush() + */ + public void flush() { + if (buffer.size() > 0) { + processBuffer(); + } + } + + /** + * Writes all remaining data from the buffer. + * + * @see java.io.OutputStream#close() + */ + public void close() throws IOException { + if (buffer.size() > 0) { + processBuffer(); + } + super.close(); + } + + /** + * @return the trace level of the log system + */ + public int getMessageLevel() { + return level; + } + + /** + * Write a block of characters to the output stream + * + * @param b the array containing the data + * @param off the offset into the array where data starts + * @param len the length of block + * @throws java.io.IOException if the data cannot be written into the stream. + * @see java.io.OutputStream#write(byte[], int, int) + */ + public void write(final byte[] b, final int off, final int len) + throws IOException { + // find the line breaks and pass other chars through in blocks + int offset = off; + int blockStartOffset = offset; + int remaining = len; + while (remaining > 0) { + while (remaining > 0 && b[offset] != LF && b[offset] != CR) { + offset++; + remaining--; + } + // either end of buffer or a line separator char + int blockLength = offset - blockStartOffset; + if (blockLength > 0) { + buffer.write(b, blockStartOffset, blockLength); + } + while (remaining > 0 && (b[offset] == LF || b[offset] == CR)) { + write(b[offset]); + offset++; + remaining--; + } + blockStartOffset = offset; + } + } + + /** + * Converts the buffer to a string and sends it to processLine. + */ + protected void processBuffer() { + processLine(buffer.toString()); + 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 level the log level to use + */ + protected abstract void processLine(final String line, final int level); +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/LogOutputStreamTest.java b/ApacheCommonsExec/src/org/apache/commons/exec/LogOutputStreamTest.java new file mode 100644 index 0000000..4e3f64a --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/LogOutputStreamTest.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ +package org.apache.commons.exec; + +import junit.framework.TestCase; + +import java.io.File; +import java.io.OutputStream; + +/** + * Test the LogOutputStream. + */ +public class LogOutputStreamTest extends TestCase +{ + + private Executor exec = new DefaultExecutor(); + private File testDir = new File("src/test/scripts"); + private OutputStream systemOut; + private File environmentScript = TestUtil.resolveScriptForOS(testDir + "/environment"); + + static{ + // 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"); + } + + + protected void setUp() throws Exception { + this.systemOut = new SystemLogOutputStream(1); + this.exec.setStreamHandler(new PumpStreamHandler(systemOut, systemOut)); + } + + protected void tearDown() throws Exception { + this.systemOut.close(); + } + + // ====================================================================== + // Start of regression tests + // ====================================================================== + + public void testStdout() throws Exception { + CommandLine cl = new CommandLine(environmentScript); + int exitValue = exec.execute(cl); + assertFalse(exec.isFailure(exitValue)); + } + + // ====================================================================== + // Helper classes + // ====================================================================== + + private class SystemLogOutputStream extends LogOutputStream { + + private SystemLogOutputStream(int level) { + super(level); + } + + protected void processLine(String line, int level) { + System.out.println(line); + } + } + +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/OS.java b/ApacheCommonsExec/src/org/apache/commons/exec/OS.java new file mode 100644 index 0000000..0e83028 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/OS.java @@ -0,0 +1,244 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec; + +import java.util.Locale; + +/** + * Condition that tests the OS type. + */ +public final class OS { + private static final String FAMILY_OS_400 = "os/400"; + + private static final String FAMILY_Z_OS = "z/os"; + + private static final String FAMILY_WIN9X = "win9x"; + + private static final String FAMILY_OPENVMS = "openvms"; + + private static final String FAMILY_UNIX = "unix"; + + private static final String FAMILY_TANDEM = "tandem"; + + private static final String FAMILY_MAC = "mac"; + + private static final String FAMILY_DOS = "dos"; + + private static final String FAMILY_NETWARE = "netware"; + + private static final String FAMILY_OS_2 = "os/2"; + + private static final String FAMILY_WINDOWS = "windows"; + + private static final String OS_NAME = System.getProperty("os.name") + .toLowerCase(Locale.US); + + private static final String OS_ARCH = System.getProperty("os.arch") + .toLowerCase(Locale.US); + + private static final String OS_VERSION = System.getProperty("os.version") + .toLowerCase(Locale.US); + + private static final String PATH_SEP = System.getProperty("path.separator"); + + /** + * Default constructor + */ + private OS() { + } + + /** + * Determines if the OS on which Ant is executing matches the given OS + * family. * Possible values:
+ *
    + *
  • dos
  • + *
  • mac
  • + *
  • netware
  • + *
  • os/2
  • + *
  • tandem
  • + *
  • unix
  • + *
  • windows
  • + *
  • win9x
  • + *
  • z/os
  • + *
  • os/400
  • + *
+ * + * @param family + * the family to check for + * @return true if the OS matches + */ + private static boolean isFamily(final String family) { + return isOs(family, null, null, null); + } + + public static boolean isFamilyDOS() { + return isFamily(FAMILY_DOS); + } + + public static boolean isFamilyMac() { + return isFamily(FAMILY_MAC); + } + + public static boolean isFamilyNetware() { + return isFamily(FAMILY_NETWARE); + } + + public static boolean isFamilyOS2() { + return isFamily(FAMILY_OS_2); + } + + public static boolean isFamilyTandem() { + return isFamily(FAMILY_TANDEM); + } + + public static boolean isFamilyUnix() { + return isFamily(FAMILY_UNIX); + } + + public static boolean isFamilyWindows() { + return isFamily(FAMILY_WINDOWS); + } + + public static boolean isFamilyWin9x() { + return isFamily(FAMILY_WIN9X); + } + + public static boolean isFamilyZOS() { + return isFamily(FAMILY_Z_OS); + } + + public static boolean isFamilyOS400() { + return isFamily(FAMILY_OS_400); + } + + public static boolean isFamilyOpenVms() { + return isFamily(FAMILY_OPENVMS); + } + + /** + * Determines if the OS on which Ant is executing matches the given OS name. + * + * @param name + * the OS name to check for + * @return true if the OS matches + */ + public static boolean isName(final String name) { + return isOs(null, name, null, null); + } + + /** + * Determines if the OS on which Ant 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 Ant 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 Ant is executing matches the given OS + * family, name, architecture and version + * + * @param family + * The OS family + * @param name + * The OS name + * @param arch + * The OS architecture + * @param version + * The OS version + * @return true if the OS matches + */ + public static boolean isOs(final String family, final String name, + final String arch, final String version) { + boolean retValue = false; + + if (family != null || name != null || arch != null || version != null) { + + boolean isFamily = true; + boolean isName = true; + boolean isArch = true; + boolean isVersion = true; + + if (family != null) { + if (family.equals(FAMILY_WINDOWS)) { + isFamily = OS_NAME.indexOf(FAMILY_WINDOWS) > -1; + } else if (family.equals(FAMILY_OS_2)) { + isFamily = OS_NAME.indexOf(FAMILY_OS_2) > -1; + } else if (family.equals(FAMILY_NETWARE)) { + isFamily = OS_NAME.indexOf(FAMILY_NETWARE) > -1; + } else if (family.equals(FAMILY_DOS)) { + isFamily = PATH_SEP.equals(";") + && !isFamily(FAMILY_NETWARE); + } else if (family.equals(FAMILY_MAC)) { + isFamily = OS_NAME.indexOf(FAMILY_MAC) > -1; + } else if (family.equals(FAMILY_TANDEM)) { + isFamily = OS_NAME.indexOf("nonstop_kernel") > -1; + } else if (family.equals(FAMILY_UNIX)) { + isFamily = PATH_SEP.equals(":") + && !isFamily(FAMILY_OPENVMS) + && (!isFamily(FAMILY_MAC) || OS_NAME.endsWith("x")); + } else if (family.equals(FAMILY_WIN9X)) { + isFamily = isFamily(FAMILY_WINDOWS) + && (OS_NAME.indexOf("95") >= 0 + || OS_NAME.indexOf("98") >= 0 + || OS_NAME.indexOf("me") >= 0 || OS_NAME + .indexOf("ce") >= 0); + } else if (family.equals(FAMILY_Z_OS)) { + isFamily = OS_NAME.indexOf(FAMILY_Z_OS) > -1 + || OS_NAME.indexOf("os/390") > -1; + } else if (family.equals(FAMILY_OS_400)) { + isFamily = OS_NAME.indexOf(FAMILY_OS_400) > -1; + } else if (family.equals(FAMILY_OPENVMS)) { + isFamily = OS_NAME.indexOf(FAMILY_OPENVMS) > -1; + } else { + throw new IllegalArgumentException( + "Don\'t know how to detect os family \"" + family + + "\""); + } + } + if (name != null) { + isName = name.equals(OS_NAME); + } + if (arch != null) { + isArch = arch.equals(OS_ARCH); + } + if (version != null) { + isVersion = version.equals(OS_VERSION); + } + retValue = isFamily && isName && isArch && isVersion; + } + return retValue; + } +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/ProcessDestroyer.java b/ApacheCommonsExec/src/org/apache/commons/exec/ProcessDestroyer.java new file mode 100644 index 0000000..d63bdb3 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/ProcessDestroyer.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec; + +/** + * Destroys all registered {@link java.lang.Process} after a certain event, + * typically when the VM exits + * @see org.apache.commons.exec.ShutdownHookProcessDestroyer + */ +public interface ProcessDestroyer { + + /** + * Returns true if the specified + * {@link java.lang.Process} was + * successfully added to the list of processes to be destroy. + * + * @param process + * the process to add + * @return true if the specified + * {@link java.lang.Process} was + * successfully added + */ + boolean add(Process process); + + /** + * Returns true if the specified + * {@link java.lang.Process} was + * successfully removed from the list of processes to be destroy. + * + * @param process + * the process to remove + * @return true if the specified + * {@link java.lang.Process} was + * successfully removed + */ + boolean remove(Process process); + + /** + * Returns the number of registered processes. + * + * @return the number of register process + */ + int size(); +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/PumpStreamHandler.java b/ApacheCommonsExec/src/org/apache/commons/exec/PumpStreamHandler.java new file mode 100644 index 0000000..6f073f7 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/PumpStreamHandler.java @@ -0,0 +1,316 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec; + +import org.apache.commons.exec.util.DebugUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PipedOutputStream; + +/** + * Copies standard output and error of sub-processes to standard output and error + * of the parent process. If output or error stream are set to null, any feedback + * from that stream will be lost. + */ +public class PumpStreamHandler implements ExecuteStreamHandler { + + private static final long STOP_TIMEOUT_ADDITION = 2000L; + + private Thread outputThread; + + private Thread errorThread; + + private Thread inputThread; + + private final OutputStream out; + + private final OutputStream err; + + private final InputStream input; + + private InputStreamPumper inputStreamPumper; + + /** the timeout in ms the implementation waits when stopping the pumper threads */ + private long stopTimeout; + + /** the last exception being caught */ + private IOException caught = null; + + /** + * Construct a new PumpStreamHandler. + */ + public PumpStreamHandler() { + this(System.out, System.err); + } + + /** + * Construct a new PumpStreamHandler. + * + * @param outAndErr the output/error OutputStream. + */ + public PumpStreamHandler(final OutputStream outAndErr) { + this(outAndErr, outAndErr); + } + + /** + * Construct a new PumpStreamHandler. + * + * @param out the output OutputStream. + * @param err the error OutputStream. + */ + public PumpStreamHandler(final OutputStream out, final OutputStream err) { + this(out, err, null); + } + + /** + * Construct a new PumpStreamHandler. + * + * @param out the output OutputStream. + * @param err the error OutputStream. + * @param input the input InputStream. + */ + public PumpStreamHandler(final OutputStream out, final OutputStream err, final InputStream input) { + this.out = out; + this.err = err; + this.input = input; + } + + /** + * Set 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(long timeout) { + this.stopTimeout = timeout; + } + + /** + * Set the InputStream from which to read the standard output + * of the process. + * + * @param is the InputStream. + */ + public void setProcessOutputStream(final InputStream is) { + if (out != null) { + createProcessOutputPump(is, out); + } + } + + /** + * Set the InputStream from which to read the standard error + * of the process. + * + * @param is the InputStream. + */ + public void setProcessErrorStream(final InputStream is) { + if (err != null) { + createProcessErrorPump(is, err); + } + } + + /** + * Set the OutputStream by means of which input can be sent + * to the process. + * + * @param os the OutputStream. + */ + public void setProcessInputStream(final OutputStream os) { + if (input != null) { + if (input == System.in) { + inputThread = createSystemInPump(input, os); + } else { + inputThread = createPump(input, os, true); + } + } else { + try { + os.close(); + } catch (IOException e) { + String msg = "Got exception while closing output stream"; + DebugUtils.handleException(msg, e); + } + } + } + + /** + * Start the Threads. + */ + public void start() { + if (outputThread != null) { + outputThread.start(); + } + if (errorThread != null) { + errorThread.start(); + } + if (inputThread != null) { + inputThread.start(); + } + } + + /** + * Stop pumping the streams. When a timeout is specified it it is not guaranteed that the + * pumper threads are cleanly terminated. + */ + public void stop() throws IOException { + + if (inputStreamPumper != null) { + inputStreamPumper.stopProcessing(); + } + + stopThread(outputThread, stopTimeout); + stopThread(errorThread, stopTimeout); + stopThread(inputThread, stopTimeout); + + if (err != null && err != out) { + try { + err.flush(); + } catch (IOException e) { + String msg = "Got exception while flushing the error stream : " + e.getMessage(); + DebugUtils.handleException(msg, e); + } + } + + if (out != null) { + try { + out.flush(); + } catch (IOException e) { + String msg = "Got exception while flushing the output stream"; + DebugUtils.handleException(msg, e); + } + } + + if(caught != null) { + throw caught; + } + } + + /** + * Get the error stream. + * + * @return OutputStream. + */ + protected OutputStream getErr() { + return err; + } + + /** + * Get the output stream. + * + * @return OutputStream. + */ + protected OutputStream getOut() { + return out; + } + + /** + * Create the pump to handle process output. + * + * @param is the InputStream. + * @param os the OutputStream. + */ + protected void createProcessOutputPump(final InputStream is, final OutputStream os) { + outputThread = createPump(is, os); + } + + /** + * Create the pump to handle error output. + * + * @param is the InputStream. + * @param os the OutputStream. + */ + 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) { + boolean closeWhenExhausted = (os instanceof PipedOutputStream ? true : false); + return createPump(is, os, closeWhenExhausted); + } + + /** + * 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 + * was indeed exceeded. If the timeout was exceeded an IOException + * is created to be thrown to the caller. + * + * @param thread the thread to be stopped + * @param timeout the time in ms to wait to join + */ + protected void stopThread(Thread thread, long timeout) { + + if (thread != null) { + try { + if (timeout == 0) { + thread.join(); + } else { + long timeToWait = timeout + STOP_TIMEOUT_ADDITION; + long startTime = System.currentTimeMillis(); + thread.join(timeToWait); + if (!(System.currentTimeMillis() < startTime + timeToWait)) { + String msg = "The stop timeout of " + timeout + " ms was exceeded"; + caught = new ExecuteException(msg, Executor.INVALID_EXITVALUE); + } + } + } catch (InterruptedException e) { + thread.interrupt(); + } + } + } + + /** + * 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(InputStream is, 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/ApacheCommonsExec/src/org/apache/commons/exec/ShutdownHookProcessDestroyer.java b/ApacheCommonsExec/src/org/apache/commons/exec/ShutdownHookProcessDestroyer.java new file mode 100644 index 0000000..1e3998e --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/ShutdownHookProcessDestroyer.java @@ -0,0 +1,194 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec; + +import java.util.Enumeration; +import java.util.Vector; + +/** + * Destroys all registered Processes when the VM exits. + */ +public class ShutdownHookProcessDestroyer implements ProcessDestroyer, Runnable { + + /** the list of currently running processes */ + private final Vector processes = new Vector(); + + /** The thread registered at the JVM to execute the shutdown handler */ + private ProcessDestroyerImpl destroyProcessThread = null; + + /** Whether or not this ProcessDestroyer has been registered as a shutdown hook */ + private boolean added = false; + + /** + * Whether or not this ProcessDestroyer is currently running as shutdown hook + */ + private volatile boolean running = false; + + private class ProcessDestroyerImpl extends Thread { + + private boolean shouldDestroy = true; + + public ProcessDestroyerImpl() { + super("ProcessDestroyer Shutdown Hook"); + } + + public void run() { + if (shouldDestroy) { + ShutdownHookProcessDestroyer.this.run(); + } + } + + public void setShouldDestroy(final boolean shouldDestroy) { + this.shouldDestroy = shouldDestroy; + } + } + + /** + * Constructs a ProcessDestroyer and obtains + * Runtime.addShutdownHook() and + * Runtime.removeShutdownHook() through reflection. The + * ProcessDestroyer manages a list of processes to be destroyed when the VM + * exits. If a process is added when the list is empty, this + * ProcessDestroyer is registered as a shutdown hook. If + * removing a process results in an empty list, the + * ProcessDestroyer is removed as a shutdown hook. + */ + public ShutdownHookProcessDestroyer() { + } + + /** + * Registers this ProcessDestroyer as a shutdown hook, uses + * reflection to ensure pre-JDK 1.3 compatibility. + */ + private void addShutdownHook() { + if (!running) { + destroyProcessThread = new ProcessDestroyerImpl(); + Runtime.getRuntime().addShutdownHook(destroyProcessThread); + added = true; + } + } + + /** + * Removes this ProcessDestroyer as a shutdown hook, uses + * reflection to ensure pre-JDK 1.3 compatibility + */ + private void removeShutdownHook() { + if (added && !running) { + boolean removed = Runtime.getRuntime().removeShutdownHook( + destroyProcessThread); + if (!removed) { + System.err.println("Could not remove shutdown hook"); + } + /* + * start the hook thread, a unstarted thread may not be eligible for + * garbage collection Cf.: http://developer.java.sun.com/developer/ + * bugParade/bugs/4533087.html + */ + + destroyProcessThread.setShouldDestroy(false); + destroyProcessThread.start(); + // this should return quickly, since it basically is a NO-OP. + try { + destroyProcessThread.join(20000); + } catch (InterruptedException ie) { + // the thread didn't die in time + // it should not kill any processes unexpectedly + } + destroyProcessThread = null; + added = false; + } + } + + /** + * Returns whether or not the ProcessDestroyer is registered as as shutdown + * hook + * + * @return true if this is currently added as shutdown hook + */ + public boolean isAddedAsShutdownHook() { + return added; + } + + /** + * Returns true if the specified Process was + * successfully added to the list of processes to destroy upon VM exit. + * + * @param process + * the process to add + * @return true if the specified Process was + * successfully added + */ + public boolean add(final Process process) { + synchronized (processes) { + // if this list is empty, register the shutdown hook + if (processes.size() == 0) { + addShutdownHook(); + } + processes.addElement(process); + return processes.contains(process); + } + } + + /** + * Returns true if the specified Process was + * successfully removed from the list of processes to destroy upon VM exit. + * + * @param process + * the process to remove + * @return true if the specified Process was + * successfully removed + */ + public boolean remove(final Process process) { + synchronized (processes) { + boolean processRemoved = processes.removeElement(process); + if (processRemoved && processes.size() == 0) { + removeShutdownHook(); + } + return processRemoved; + } + } + + /** + * Returns the number of registered processes. + * + * @return the number of register process + */ + public int size() { + return processes.size(); + } + + /** + * Invoked by the VM when it is exiting. + */ + public void run() { + synchronized (processes) { + running = true; + Enumeration e = processes.elements(); + while (e.hasMoreElements()) { + Process process = (Process) e.nextElement(); + try { + process.destroy(); + } + catch (Throwable t) { + System.err.println("Unable to terminate process during process shutdown"); + } + } + } + } +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/StandAloneTest.java b/ApacheCommonsExec/src/org/apache/commons/exec/StandAloneTest.java new file mode 100644 index 0000000..35f3774 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/StandAloneTest.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec; + +import junit.framework.TestCase; + +import java.io.File; + +/** + * Placeholder for mailing list question - provided a minimal test case + * to answer the question as sel-contained regression test. + */ +public class StandAloneTest extends TestCase { + + static{ + System.setProperty("org.apache.commons.exec.lenient", "false"); + System.setProperty("org.apache.commons.exec.debug", "true"); + } + + public void testMe() throws Exception { + if(OS.isFamilyUnix()) { + File testScript = TestUtil.resolveScriptForOS("./src/test/scripts/standalone"); + Executor exec = new DefaultExecutor(); + exec.setStreamHandler(new PumpStreamHandler()); + CommandLine cl = new CommandLine(testScript); + exec.execute(cl); + assertTrue(new File("./target/mybackup.gz").exists()); + } + } +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/StreamPumper.java b/ApacheCommonsExec/src/org/apache/commons/exec/StreamPumper.java new file mode 100644 index 0000000..164768d --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/StreamPumper.java @@ -0,0 +1,145 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec; + +import org.apache.commons.exec.util.DebugUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Copies all data from an input stream to an output stream. + */ +public class StreamPumper implements Runnable { + + /** the default size of the internal buffer for copying the streams */ + private static final int DEFAULT_SIZE = 1024; + + /** the input stream to pump from */ + private final InputStream is; + + /** the output stream to pmp into */ + private final OutputStream os; + + /** the size of the internal buffer for copying the streams */ + private final int size; + + /** was the end of the stream reached */ + private boolean finished; + + /** 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. + * @param closeWhenExhausted if true, the output stream will be closed when the input is exhausted. + */ + public StreamPumper(final InputStream is, final OutputStream os, + final boolean closeWhenExhausted) { + this.is = is; + this.os = os; + this.size = DEFAULT_SIZE; + this.closeWhenExhausted = closeWhenExhausted; + } + + /** + * Create a new stream pumper. + * + * @param is input stream to read data from + * @param os output stream to write data to. + * @param closeWhenExhausted if true, the output stream will be closed when the input is exhausted. + * @param size the size of the internal buffer for copying the streams + */ + public StreamPumper(final InputStream is, final OutputStream os, + final boolean closeWhenExhausted, final int size) { + this.is = is; + this.os = os; + this.size = (size > 0 ? size : DEFAULT_SIZE); + this.closeWhenExhausted = 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); + } + + /** + * Copies data from the input stream to the output stream. Terminates as + * soon as the input stream is closed or an error occurs. + */ + public void run() { + synchronized (this) { + // Just in case this object is reused in the future + finished = false; + } + + final byte[] buf = new byte[this.size]; + + int length; + try { + while ((length = is.read(buf)) > 0) { + os.write(buf, 0, length); + } + } catch (Exception e) { + // nothing to do - happens quite often with watchdog + } finally { + if (closeWhenExhausted) { + try { + os.close(); + } catch (IOException e) { + String msg = "Got exception while closing exhausted output stream"; + DebugUtils.handleException(msg ,e); + } + } + synchronized (this) { + finished = true; + notifyAll(); + } + } + } + + /** + * 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. + * + * @see #isFinished() + */ + public synchronized void waitFor() throws InterruptedException { + while (!isFinished()) { + wait(); + } + } +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/TestRunner.java b/ApacheCommonsExec/src/org/apache/commons/exec/TestRunner.java new file mode 100644 index 0000000..0522ed6 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/TestRunner.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.commons.exec; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestResult; +import junit.framework.TestSuite; +// tms import org.apache.commons.exec.environment.EnvironmentUtilTest; +import org.apache.commons.exec.util.MapUtilTest; + +/** + * A stand-alone JUnit invocation to allow running JUnit tests without + * having ANT or M2 installed. + */ +public class TestRunner extends TestCase { + + public static Test suite() { + TestSuite suite = new TestSuite("TestRunner"); + suite.addTestSuite(CommandLineTest.class); + //tms suite.addTestSuite(DefaultExecutorTest.class); + suite.addTestSuite(EnvironmentUtilTest.class); + suite.addTestSuite(MapUtilTest.class); + suite.addTestSuite(TestUtilTest.class); + return suite; + } + + public static void main(String[] args) { + + Test test = TestRunner.suite(); + junit.textui.TestRunner testRunner = new junit.textui.TestRunner(System.out); + TestResult testResult = testRunner.doRun(test); + + if(!testResult.wasSuccessful()) { + System.exit(1); + } + + // not calling System.exit(0) here to ensure that the application + // properly terminates (e.g. not waiting for any background threads + // indicating serious problems + return; + } +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/TestUtil.java b/ApacheCommonsExec/src/org/apache/commons/exec/TestUtil.java new file mode 100644 index 0000000..62d4ec6 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/TestUtil.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec; + +import java.io.File; +import java.util.Arrays; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +public final class TestUtil { + + private TestUtil() { + } + + public static File resolveScriptForOS(String script) { + if (OS.isFamilyWindows()) { + return new File(script + ".bat"); + } else if (OS.isFamilyUnix()) { + return new File(script + ".sh"); + } else if (OS.isFamilyOpenVms()) { + return new File(script + ".dcl"); + } else { + throw new AssertionFailedError("Test not supported for this OS"); + } + } + + /** + * Get 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 int[]{0,1}; + } else if (OS.isFamilyUnix()) { + return new int[]{0,1}; + } else if (OS.isFamilyOpenVms()) { + return new int[]{1,2}; + } else { + throw new AssertionFailedError("Test not supported for this OS"); + } + } + + + public static void assertEquals(Object[] expected, Object[] actual, boolean orderSignificant) { + + if(expected == null && actual == null) { + // all good + } else if (actual == null) { + throw new AssertionFailedError("Expected non null array"); + } else if (expected == null) { + throw new AssertionFailedError("Expected null array"); + } else { + if(expected.length != actual.length) { + throw new AssertionFailedError("Arrays not of same length"); + } + + if(!orderSignificant) { + Arrays.sort(expected); + Arrays.sort(actual); + } + + for (int i = 0; i < actual.length; i++) { + TestCase.assertEquals("Array element at " + i, expected[i], actual[i]); + } + } + } +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/TestUtilTest.java b/ApacheCommonsExec/src/org/apache/commons/exec/TestUtilTest.java new file mode 100644 index 0000000..10de76d --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/TestUtilTest.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec; + +import junit.framework.AssertionFailedError; +import junit.framework.TestCase; + +public class TestUtilTest extends TestCase { + + public void testAssertArrayEquals() { + String[] expected = new String[]{"aaa", "bbb", "ccc"}; + String[] actual = new String[]{"aaa", "bbb", "ccc"}; + + TestUtil.assertEquals(expected, actual, true); + } + + public void testAssertArrayNotEquals() { + String[] expected = new String[]{"aaa", "bbb", "ccc"}; + String[] actual = new String[]{"aaa", "ddd", "ccc"}; + + try{ + TestUtil.assertEquals(expected, actual, true); + fail("Must throw AssertionFailedError"); + } catch(AssertionFailedError e) { + // OK + } + } + + public void testAssertArrayNotOrderEquals() { + String[] expected = new String[]{"aaa", "ccc", "bbb"}; + String[] actual = new String[]{"aaa", "ddd", "ccc"}; + + try{ + TestUtil.assertEquals(expected, actual, true); + fail("Must throw AssertionFailedError"); + } catch(AssertionFailedError e) { + // OK + } + } + + public void testAssertArrayEqualsOrderNotSignificant() { + String[] expected = new String[]{"aaa", "ccc", "bbb"}; + String[] actual = new String[]{"aaa", "bbb", "ccc"}; + + TestUtil.assertEquals(expected, actual, false); + } + + public void testAssertArrayEqualsNullNull() { + String[] expected = null; + String[] actual = null; + + TestUtil.assertEquals(expected, actual, false); + } + + public void testAssertArrayEqualsActualNull() { + String[] expected = new String[]{"aaa", "ccc", "bbb"}; + String[] actual = null; + + try{ + TestUtil.assertEquals(expected, actual, true); + fail("Must throw AssertionFailedError"); + } catch(AssertionFailedError e) { + // OK + } + } + + public void testAssertArrayEqualsExpectedNull() { + String[] expected = null; + String[] actual = new String[]{"aaa", "ddd", "ccc"}; + + try{ + TestUtil.assertEquals(expected, actual, true); + fail("Must throw AssertionFailedError"); + } catch(AssertionFailedError e) { + // OK + } + } +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/TimeoutObserver.java b/ApacheCommonsExec/src/org/apache/commons/exec/TimeoutObserver.java new file mode 100644 index 0000000..dfb87cf --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/TimeoutObserver.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec; + +/** + * Interface for classes that want to be notified by Watchdog. + * + * @see org.apache.commons.exec.Watchdog + */ +public interface TimeoutObserver { + + /** + * Called when the watchdog times out. + * + * @param w the watchdog that timed out. + */ + void timeoutOccured(Watchdog w); +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/TutorialTest.java b/ApacheCommonsExec/src/org/apache/commons/exec/TutorialTest.java new file mode 100644 index 0000000..b939e84 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/TutorialTest.java @@ -0,0 +1,148 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec; + +import junit.framework.TestCase; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * An example based on the tutorial where the user can can safely play with + *
    + *
  • blocking or non-blocking print jobs + *
  • with print job timeouts to trigger the ExecuteWatchdog + *
  • with the exitValue returned from the print script + *
+ */ +public class TutorialTest extends TestCase { + + /** the directory to pick up the test scripts */ + private File testDir = new File("src/test/scripts"); + + /** simulates a PDF print job */ + private File acroRd32Script = TestUtil.resolveScriptForOS(testDir + "/acrord32"); + + public void testTutorialExample() throws Exception { + + long printJobTimeout = 15000; + boolean printInBackground = false; + File pdfFile = new File("/Documents and Settings/foo.pdf"); + + PrintResultHandler printResult; + + 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 ..."); + } + catch(Exception e) { + e.printStackTrace(); + fail("[main] Printing of the following document failed : " + pdfFile.getAbsolutePath()); + throw e; + } + + // 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 ..."); + } + + /** + * Simulate printing a PDF document. + * + * @param file the file to print + * @param printJobTimeout the printJobTimeout (ms) before the watchdog terminates the print process + * @param printInBackground printing done in the background or blocking + * @return a print result handler (implementing a future) + * @throws IOException the test failed + */ + public PrintResultHandler print(File file, long printJobTimeout, boolean printInBackground) + throws IOException { + + int exitValue; + ExecuteWatchdog watchdog = null; + PrintResultHandler resultHandler; + + // build up the command line to using a 'java.io.File' + Map map = new HashMap(); + map.put("file", file); + CommandLine commandLine = new CommandLine(acroRd32Script); + commandLine.addArgument("/p"); + commandLine.addArgument("/h"); + commandLine.addArgument("${file}"); + commandLine.setSubstitutionMap(map); + + // create the executor and consider the exitValue '1' as success + Executor executor = new DefaultExecutor(); + executor.setExitValue(1); + + // create a watchdog if requested + if(printJobTimeout > 0) { + watchdog = new ExecuteWatchdog(printJobTimeout); + executor.setWatchdog(watchdog); + } + + // pass a "ExecuteResultHandler" when doing background printing + if(printInBackground) { + System.out.println("[print] Executing non-blocking print job ..."); + resultHandler = new PrintResultHandler(watchdog); + executor.execute(commandLine, resultHandler); + } + else { + System.out.println("[print] Executing blocking print job ..."); + exitValue = executor.execute(commandLine); + resultHandler = new PrintResultHandler(exitValue); + } + + return resultHandler; + } + + private class PrintResultHandler extends DefaultExecuteResultHandler { + + private ExecuteWatchdog watchdog; + + public PrintResultHandler(ExecuteWatchdog watchdog) + { + this.watchdog = watchdog; + } + + public PrintResultHandler(int exitValue) { + super.onProcessComplete(exitValue); + } + + public void onProcessComplete(int exitValue) { + super.onProcessComplete(exitValue); + System.out.println("[resultHandler] The document was successfully printed ..."); + } + + public void onProcessFailed(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()); + } + } + } +} \ No newline at end of file diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/Watchdog.java b/ApacheCommonsExec/src/org/apache/commons/exec/Watchdog.java new file mode 100644 index 0000000..8442a88 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/Watchdog.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec; + +import java.util.Enumeration; +import java.util.Vector; + +/** + * Generalization of ExecuteWatchdog + * + * @see org.apache.commons.exec.ExecuteWatchdog + */ +public class Watchdog implements Runnable { + + private Vector observers = new Vector(1); + + private final long timeout; + + private boolean stopped = false; + + public Watchdog(final long timeout) { + if (timeout < 1) { + throw new IllegalArgumentException("timeout must not be less than 1."); + } + this.timeout = timeout; + } + + public void addTimeoutObserver(final TimeoutObserver to) { + observers.addElement(to); + } + + public void removeTimeoutObserver(final TimeoutObserver to) { + observers.removeElement(to); + } + + protected final void fireTimeoutOccured() { + Enumeration e = observers.elements(); + while (e.hasMoreElements()) { + ((TimeoutObserver) e.nextElement()).timeoutOccured(this); + } + } + + public synchronized void start() { + stopped = false; + Thread t = new Thread(this, "WATCHDOG"); + t.setDaemon(true); + t.start(); + } + + public synchronized void stop() { + stopped = true; + notifyAll(); + } + + public void run() { + final long until = System.currentTimeMillis() + timeout; + boolean isWaiting; + synchronized (this) { + long now = System.currentTimeMillis(); + isWaiting = until > now; + while (!stopped && isWaiting) { + try { + wait(until - now); + } catch (InterruptedException e) { + } + now = System.currentTimeMillis(); + isWaiting = until > now; + } + } + + // notify the listeners outside of the synchronized block (see EXEC-60) + if (!isWaiting) { + fireTimeoutOccured(); + } + } + +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/environment/DefaultProcessingEnvironment.java b/ApacheCommonsExec/src/org/apache/commons/exec/environment/DefaultProcessingEnvironment.java new file mode 100644 index 0000000..37279aa --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/environment/DefaultProcessingEnvironment.java @@ -0,0 +1,241 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.commons.exec.environment; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.StringReader; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +import org.apache.commons.exec.CommandLine; +import org.apache.commons.exec.DefaultExecutor; +import org.apache.commons.exec.Executor; +import org.apache.commons.exec.OS; +import org.apache.commons.exec.PumpStreamHandler; + +/** + * Helper class to determine the environment variable + * for the OS. Depending on the JDK the environment + * variables can be either retrieved directly from the + * JVM or requires starting a process to get them running + * an OS command line. + */ +public class DefaultProcessingEnvironment { + + /** the line separator of the system */ + private static final String LINE_SEPARATOR = System.getProperty("line.separator"); + + /** the environment variables of the process */ + protected Map procEnvironment; + + /** + * 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 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 + Map copy = createEnvironmentMap(); + copy.putAll(procEnvironment); + return copy; + } + + /** + * Find the list of environment variables for this process. + * + * @return a amp containing the environment variables + * @throws IOException the operation failed + */ + protected Map createProcEnvironment() throws IOException { + if (procEnvironment == null) { + try { + Method getenvs = System.class.getMethod( "getenv", (java.lang.Class[]) null ); + Map env = (Map) getenvs.invoke( null, (java.lang.Object[]) null ); + procEnvironment = createEnvironmentMap(); + procEnvironment.putAll(env); + } catch ( NoSuchMethodException e ) { + // ok, just not on JDK 1.5 + } catch ( IllegalAccessException e ) { + // Unexpected error obtaining environment - using JDK 1.4 method + } catch ( InvocationTargetException e ) { + // Unexpected error obtaining environment - using JDK 1.4 method + } + } + + if(procEnvironment == null) { + procEnvironment = createEnvironmentMap(); + BufferedReader in = runProcEnvCommand(); + + String var = null; + String line; + while ((line = in.readLine()) != null) { + if (line.indexOf('=') == -1) { + // Chunk part of previous env var (UNIX env vars can + // contain embedded new lines). + if (var == null) { + var = LINE_SEPARATOR + line; + } else { + var += LINE_SEPARATOR + line; + } + } else { + // New env var...append the previous one if we have it. + if (var != null) { + EnvironmentUtils.addVariableToEnvironment(procEnvironment, var); + } + var = line; + } + } + // Since we "look ahead" before adding, there's one last env var. + if (var != null) { + EnvironmentUtils.addVariableToEnvironment(procEnvironment, var); + } + } + 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 + */ + protected BufferedReader runProcEnvCommand() throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + 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))); + } + + /** + * Determine the OS specific command line to get a list of environment + * variables. + * + * @return the command line + */ + protected CommandLine getProcEnvCommand() { + String executable; + String[] arguments = null; + if (OS.isFamilyOS2()) { + // OS/2 - use same mechanism as Windows 2000 + executable = "cmd"; + + arguments = new String[] {"/c", "set"}; + } else if (OS.isFamilyWindows()) { + // Determine if we're running under XP/2000/NT or 98/95 + if (OS.isFamilyWin9x()) { + executable = "command.com"; + // Windows 98/95 + } else { + executable = "cmd"; + // Windows XP/2000/NT/2003 + } + arguments = new String[] {"/c", "set"}; + } else if (OS.isFamilyZOS() || OS.isFamilyUnix()) { + // On most systems one could use: /bin/sh -c env + + // Some systems have /bin/env, others /usr/bin/env, just try + if (new File("/bin/env").canRead()) { + executable = "/bin/env"; + } else if (new File("/usr/bin/env").canRead()) { + executable = "/usr/bin/env"; + } else { + // rely on PATH + executable = "env"; + } + } else if (OS.isFamilyNetware() || OS.isFamilyOS400()) { + // rely on PATH + executable = "env"; + } else { + // MAC OS 9 and previous + // TODO: I have no idea how to get it, someone must fix it + executable = null; + } + CommandLine commandLine = null; + if(executable != null) { + commandLine = new CommandLine(executable); + commandLine.addArguments(arguments); + } + return commandLine; + } + + /** + * ByteArrayOutputStream#toString doesn't seem to work reliably on OS/390, + * at least not the way we use it in the execution context. + * + * @param bos + * the output stream that one wants to read + * @return the output stream as a string, read with special encodings in the + * case of z/os and os/400 + */ + private String toString(final ByteArrayOutputStream bos) { + if (OS.isFamilyZOS()) { + try { + return bos.toString("Cp1047"); + } catch (java.io.UnsupportedEncodingException e) { + // noop default encoding used + } + } else if (OS.isFamilyOS400()) { + try { + return bos.toString("Cp500"); + } catch (java.io.UnsupportedEncodingException e) { + // noop default encoding used + } + } + return bos.toString(); + } + + /** + * 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 The map for storage of environment variables, never + * null. + */ + private Map createEnvironmentMap() { + if (OS.isFamilyWindows()) { + return new TreeMap(new Comparator() { + public int compare(Object arg0, Object arg1) { + String key0 = (String) arg0; + String key1 = (String) arg1; + return key0.compareToIgnoreCase(key1); + } + }); + } else { + return new HashMap(); + } + } + +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/environment/EnvironmentUtils.java b/ApacheCommonsExec/src/org/apache/commons/exec/environment/EnvironmentUtils.java new file mode 100644 index 0000000..6b88d1f --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/environment/EnvironmentUtils.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec.environment; + +import java.io.IOException; +import java.util.Iterator; +import java.util.Map; + +import org.apache.commons.exec.OS; + +/** + * Wrapper for environment variables. + */ +public class EnvironmentUtils +{ + + private static final DefaultProcessingEnvironment PROCESSING_ENVIRONMENT_IMPLEMENTATION; + + static { + if (OS.isFamilyOpenVms()) { + PROCESSING_ENVIRONMENT_IMPLEMENTATION = new OpenVmsProcessingEnvironment(); + } else { + PROCESSING_ENVIRONMENT_IMPLEMENTATION = new DefaultProcessingEnvironment(); + } + } + + /** + * Disable constructor. + */ + private EnvironmentUtils() { + + } + + /** + * Get the variable list as an array. + * + * @param environment the environment to use, may be null + * @return array of key=value assignment strings or null if and only if + * the input map was null + */ + public static String[] toStrings(Map environment) { + if (environment == null) { + return null; + } + String[] result = new String[environment.size()]; + int i = 0; + for (Iterator iter = environment.entrySet().iterator(); iter.hasNext();) { + Map.Entry entry = (Map.Entry) iter.next(); + + result[i] = entry.getKey().toString() + "=" + entry.getValue().toString(); + i++; + } + return result; + } + + /** + * Find the list of environment variables for this process. The returned map preserves + * the casing of a variable's name on all platforms but obeys the casing rules of the + * current platform during lookup, e.g. key names will be case-insensitive on Windows + * platforms. + * + * @return a map containing the environment variables, may be empty but never null + * @throws IOException the operation failed + */ + public static Map getProcEnvironment() throws IOException { + 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(Map environment, String keyAndValue) { + 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. + * + * @param keyAndValue the key/value pair + * @return a String[] containing the key and value + */ + private static String[] parseEnvironmentVariable(final String keyAndValue) { + int index = keyAndValue.indexOf('='); + if (index == -1) { + throw new IllegalArgumentException( + "Environment variable for this platform " + + "must contain an equals sign ('=')"); + } + + String[] result = new String[2]; + result[0] = keyAndValue.substring(0, index); + result[1] = keyAndValue.substring(index + 1); + + return result; + } + +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/environment/OpenVmsProcessingEnvironment.java b/ApacheCommonsExec/src/org/apache/commons/exec/environment/OpenVmsProcessingEnvironment.java new file mode 100644 index 0000000..9f2ad16 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/environment/OpenVmsProcessingEnvironment.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.commons.exec.environment; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.exec.CommandLine; + +/** + * Helper class to determine the environment variable + * for VMS. + */ +public class OpenVmsProcessingEnvironment extends DefaultProcessingEnvironment { + + /** + * Find the list of environment variables for this process. + * + * @return a map containing the environment variables + * @throws IOException the operation failed + */ + protected Map createProcEnvironment() throws IOException { + if (procEnvironment == null) { + BufferedReader in = runProcEnvCommand(); + procEnvironment = addVMSenvironmentVariables(new HashMap(), in); + } + + return procEnvironment; + } + + /** + * Determine the OS specific command line to get a list of environment + * variables. + * + * @return the command line + */ + protected CommandLine getProcEnvCommand() { + CommandLine commandLine = new CommandLine("show"); + commandLine.addArgument("symbol/global"); // the parser assumes symbols are global + commandLine.addArgument("*"); + return commandLine; + } + + /** + * This method is VMS specific and used by getProcEnvironment(). Parses VMS + * symbols from in and adds them to environment. + * in is expected to be the output of "SHOW SYMBOL/GLOBAL *". + * + * @param environment the current environment + * @param in the reader from the process to determine VMS env variables + * @return the updated environment + * @throws IOException operation failed + */ + private Map addVMSenvironmentVariables(final Map environment, + final BufferedReader in) throws IOException { + String line; + while ((line = in.readLine()) != null) { + final String SEP = "=="; // global symbol separator + int sepidx = line.indexOf(SEP); + if (sepidx > 0){ + String name = line.substring(0, sepidx).trim(); + String value = line.substring(sepidx+SEP.length()).trim(); + value = value.substring(1,value.length()-1); // drop enclosing quotes + environment.put(name,value); + } + } + return environment; + } +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/launcher/CommandLauncher.java b/ApacheCommonsExec/src/org/apache/commons/exec/launcher/CommandLauncher.java new file mode 100644 index 0000000..5d55eb9 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/launcher/CommandLauncher.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec.launcher; + +import java.io.File; +import java.io.IOException; +import java.util.Map; + +import org.apache.commons.exec.CommandLine; + +/** + * Interface to shield the caller from the various platform-dependent + * implementations. + */ +public interface CommandLauncher { + + /** + * Launches the given command in a new process. + * + * @param cmd + * The command to execute + * @param env + * The environment for the new process. If null, the environment + * of the current process is used. + * + * @return the newly created process + * @throws IOException + * if attempting to run a command in a specific directory + */ + Process exec(final CommandLine cmd, final Map env) + throws IOException; + + /** + * Launches the given command in a new process, in the given working + * directory. + * + * @param cmd + * The command to execute + * @param env + * The environment for the new process. If null, the environment + * of the current process is used. + * @param workingDir + * The directory to start the command in. If null, the current + * directory is used + * + * @return the newly created process + * @throws IOException + * if trying to change directory + */ + Process exec(final CommandLine cmd, final Map env, + final File workingDir) throws IOException; + + + /** + * Checks whether exitValue signals a failure on the current + * system (OS specific). + *

+ * Note 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. + *

+ * + * @param exitValue the exit value (return code) to be checked + * @return true if exitValue signals a failure + */ + boolean isFailure(final int exitValue); +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/launcher/CommandLauncherFactory.java b/ApacheCommonsExec/src/org/apache/commons/exec/launcher/CommandLauncherFactory.java new file mode 100644 index 0000000..254da23 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/launcher/CommandLauncherFactory.java @@ -0,0 +1,48 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec.launcher; + +import org.apache.commons.exec.OS; + +/** + * Builds a command launcher for the OS and JVM we are running under. + */ +public final class CommandLauncherFactory { + + private CommandLauncherFactory() { + } + + /** + * Factory method to create an appropriate launcher. + * + * @return the command launcher + */ + public static CommandLauncher createVMLauncher() { + // Try using a JDK 1.3 launcher + CommandLauncher launcher; + + if (OS.isFamilyOpenVms()) { + launcher = new VmsCommandLauncher(); + } else { + launcher = new Java13CommandLauncher(); + } + + return launcher; + } +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/launcher/CommandLauncherImpl.java b/ApacheCommonsExec/src/org/apache/commons/exec/launcher/CommandLauncherImpl.java new file mode 100644 index 0000000..f04be3a --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/launcher/CommandLauncherImpl.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec.launcher; + +import java.io.File; +import java.io.IOException; +import java.util.Map; + +import org.apache.commons.exec.CommandLine; +import org.apache.commons.exec.environment.EnvironmentUtils; + +/** + * A command launcher for a particular JVM/OS platform. This class is a general + * purpose command launcher which can only launch commands in the current + * working directory. + */ +public abstract class CommandLauncherImpl implements CommandLauncher { + + public Process exec(final CommandLine cmd, final Map env) + throws IOException { + String[] envVar = EnvironmentUtils.toStrings(env); + return Runtime.getRuntime().exec(cmd.toStrings(), envVar); + } + + public abstract Process exec(final CommandLine cmd, final Map env, + final File workingDir) throws IOException; + + /** @see org.apache.commons.exec.launcher.CommandLauncher#isFailure(int) */ + public boolean isFailure(final int exitValue) + { + // non zero exit value signals failure + return exitValue != 0; + } +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/launcher/CommandLauncherProxy.java b/ApacheCommonsExec/src/org/apache/commons/exec/launcher/CommandLauncherProxy.java new file mode 100644 index 0000000..78fb180 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/launcher/CommandLauncherProxy.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec.launcher; + +import java.io.IOException; +import java.util.Map; + +import org.apache.commons.exec.CommandLine; + +/** + * A command launcher that proxies another command launcher. Sub-classes + * override exec(args, env, workdir) + */ +public abstract class CommandLauncherProxy extends CommandLauncherImpl { + + 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 + * + * @param cmd + * the command line to execute as an array of strings + * @param env + * the environment to set as an array of strings + * @throws IOException + * forwarded from the exec method of the command launcher + */ + public Process exec(final CommandLine cmd, final Map env) + throws IOException { + return myLauncher.exec(cmd, env); + } +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/launcher/Java13CommandLauncher.java b/ApacheCommonsExec/src/org/apache/commons/exec/launcher/Java13CommandLauncher.java new file mode 100644 index 0000000..152466d --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/launcher/Java13CommandLauncher.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec.launcher; + +import java.io.File; +import java.io.IOException; +import java.util.Map; + +import org.apache.commons.exec.CommandLine; +import org.apache.commons.exec.environment.EnvironmentUtils; + +/** + * A command launcher for JDK/JRE 1.3 (and higher). Uses the built-in + * Runtime.exec() command + */ +public class Java13CommandLauncher extends CommandLauncherImpl { + + /** + * Constructor + */ + public Java13CommandLauncher() { + } + + /** + * Launches the given command in a new process, in the given working + * directory + * + * @param cmd + * the command line to execute as an array of strings + * @param env + * the environment to set as an array of strings + * @param workingDir + * the working directory where the command should run + * @throws IOException + * probably forwarded from Runtime#exec + */ + public Process exec(final CommandLine cmd, final Map env, + final File workingDir) throws IOException { + + String[] envVars = EnvironmentUtils.toStrings(env); + + return Runtime.getRuntime().exec(cmd.toStrings(), + envVars, workingDir); + } +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/launcher/OS2CommandLauncher.java b/ApacheCommonsExec/src/org/apache/commons/exec/launcher/OS2CommandLauncher.java new file mode 100644 index 0000000..3469ba3 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/launcher/OS2CommandLauncher.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec.launcher; + +import java.io.File; +import java.io.IOException; +import java.util.Map; + +import org.apache.commons.exec.CommandLine; + +/** + * A command launcher for OS/2 that uses 'cmd.exe' when launching commands in + * directories other than the current working directory. + *

+ * Unlike Windows NT and friends, OS/2's cd doesn't support the /d switch to + * change drives and directories in one go. + *

+ * Please not that this class is currently unused because the Java13CommandLauncher + * is used for 0S/2 + */ +public class OS2CommandLauncher extends CommandLauncherProxy { + + public OS2CommandLauncher(final CommandLauncher launcher) { + super(launcher); + } + + /** + * Launches the given command in a new process, in the given working + * directory. + * + * @param cmd + * the command line to execute as an array of strings + * @param env + * the environment to set as an array of strings + * @param workingDir + * working directory where the command should run + * @throws IOException + * forwarded from the exec method of the command launcher + */ + public Process exec(final CommandLine cmd, final Map env, + final File workingDir) throws IOException { + if (workingDir == null) { + return exec(cmd, env); + } + + CommandLine newCmd = new CommandLine("cmd"); + newCmd.addArgument("/c"); + newCmd.addArguments(cmd.toStrings()); + + return exec(newCmd, env); + } +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/launcher/VmsCommandLauncher.java b/ApacheCommonsExec/src/org/apache/commons/exec/launcher/VmsCommandLauncher.java new file mode 100644 index 0000000..3190eb0 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/launcher/VmsCommandLauncher.java @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec.launcher; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.apache.commons.exec.CommandLine; +import org.apache.commons.exec.util.StringUtils; + +/** + * A command launcher for VMS that writes the command to a temporary DCL script + * before launching commands. This is due to limitations of both the DCL + * interpreter and the Java VM implementation. + */ +public class VmsCommandLauncher extends Java13CommandLauncher { + + /** + * Launches the given command in a new process. + */ + public Process exec(final CommandLine cmd, final Map env) + throws IOException { + CommandLine vmsCmd = new CommandLine( + createCommandFile(cmd, env).getPath() + ); + + return super.exec(vmsCmd, 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 workingDir is null or the logical + * JAVA$FORK_SUPPORT_CHDIR needs to be set to TRUE. + */ + public Process exec(final CommandLine cmd, final Map env, + final File workingDir) throws IOException { + CommandLine vmsCmd = new CommandLine( + createCommandFile(cmd, env).getPath() + ); + + return super.exec(vmsCmd, env, workingDir); + } + + /** @see org.apache.commons.exec.launcher.CommandLauncher#isFailure(int) */ + 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. + */ + private File createCommandFile(final CommandLine cmd, final Map env) + throws IOException { + File script = File.createTempFile("EXEC", ".TMP"); + script.deleteOnExit(); + PrintWriter out = null; + try { + out = new PrintWriter(new FileWriter(script.getAbsolutePath(),true)); + + // add the environment as global symbols for the DCL script + if (env != null) { + Set entries = env.entrySet(); + + for (Iterator iter = entries.iterator(); iter.hasNext();) { + Entry entry = (Entry) iter.next(); + out.print("$ "); + out.print(entry.getKey()); + out.print(" == "); // define as global symbol + out.println('\"'); + String value = (String) entry.getValue(); + // Any embedded " values need to be doubled + if (value.indexOf('\"') > 0){ + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < value.length(); i++) { + char c = value.charAt(i); + if (c == '\"') { + sb.append('\"'); + } + sb.append(c); + } + value=sb.toString(); + } + out.print(value); + out.println('\"'); + } + } + + final String command = cmd.getExecutable(); + if (cmd.isFile()){// We assume it is it a script file + out.print("$ @"); + // This is a bit crude, but seems to work + String parts[] = StringUtils.split(command,"/"); + out.print(parts[0]); // device + out.print(":["); + out.print(parts[1]); // top level directory + final int lastPart = parts.length-1; + for(int i=2; i< lastPart; i++){ + out.print("."); + out.print(parts[i]); + } + out.print("]"); + out.print(parts[lastPart]); + } else { + out.print("$ "); + out.print(command); + } + String[] args = cmd.getArguments(); + for (int i = 0; i < args.length; i++) { + out.println(" -"); + out.print(args[i]); + } + out.println(); + } finally { + if (out != null) { + out.close(); + } + } + return script; + } +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/launcher/WinNTCommandLauncher.java b/ApacheCommonsExec/src/org/apache/commons/exec/launcher/WinNTCommandLauncher.java new file mode 100644 index 0000000..6e4d189 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/launcher/WinNTCommandLauncher.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec.launcher; + +import java.io.File; +import java.io.IOException; +import java.util.Map; + +import org.apache.commons.exec.CommandLine; + +/** + * A command launcher for Windows XP/2000/NT that uses 'cmd.exe' when launching + * commands in directories other than the current working directory. + */ +public class WinNTCommandLauncher extends CommandLauncherProxy { + public WinNTCommandLauncher(final CommandLauncher launcher) { + super(launcher); + } + + /** + * Launches the given command in a new process, in the given working + * directory. + * + * @param cmd + * the command line to execute as an array of strings + * @param env + * the environment to set as an array of strings + * @param workingDir + * working directory where the command should run + * @throws IOException + * forwarded from the exec method of the command launcher + */ + public Process exec(final CommandLine cmd, final Map env, + final File workingDir) throws IOException { + if (workingDir == null) { + return exec(cmd, env); + } + + // Use cmd.exe to change to the specified directory before running + // the command + CommandLine newCmd = new CommandLine("cmd"); + newCmd.addArgument("/c"); + newCmd.addArguments(cmd.toStrings()); + + return exec(newCmd, env); + } +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/util/DebugUtils.java b/ApacheCommonsExec/src/org/apache/commons/exec/util/DebugUtils.java new file mode 100644 index 0000000..d28f748 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/util/DebugUtils.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec.util; + +/** + * Helper classes to provide debugging support. + * + * @author Siegfried Goeschl + */ +public class DebugUtils +{ + /** + * System property to determine how to handle exceptions. When + * set to "false" we rethrow the otherwise silently catched + * exceptions found in the original code. The default value + * is "true" + */ + public static final String COMMONS_EXEC_LENIENT = "org.apache.commons.exec.lenient"; + + /** + * System property to determine how to dump an exception. When + * set to "true" we print any exception to stderr. The default + * value is "false" + */ + public static final String COMMONS_EXEC_DEBUG = "org.apache.commons.exec.debug"; + + /** + * Handle an exception based on the system properties. + * + * @param msg message describing the problem + * @param e an exception being handled + */ + public static void handleException(String msg, Exception e) { + + if(isDebugEnabled()) { + System.err.println(msg); + e.printStackTrace(); + } + + if(!isLenientEnabled()) { + if(e instanceof RuntimeException) { + throw (RuntimeException) e; + } + else { + // can't pass root cause since the constructor is not available on JDK 1.3 + throw new RuntimeException(e.getMessage()); + } + } + } + + /** + * Determine if debugging is enabled based on the + * system property "COMMONS_EXEC_DEBUG". + * + * @return true if debug mode is enabled + */ + public static boolean isDebugEnabled() { + return "true".equalsIgnoreCase(System.getProperty(COMMONS_EXEC_DEBUG, "false")); + } + + /** + * Determine if lenient mode is enabled. + * + * @return true if lenient mode is enabled + */ + public static boolean isLenientEnabled() { + return "true".equalsIgnoreCase(System.getProperty(COMMONS_EXEC_LENIENT, "true")); + } + +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/util/MapUtilTest.java b/ApacheCommonsExec/src/org/apache/commons/exec/util/MapUtilTest.java new file mode 100644 index 0000000..5e040a7 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/util/MapUtilTest.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec.util; + +import org.apache.commons.exec.environment.EnvironmentUtils; + +import java.util.HashMap; +import java.util.Map; + +import junit.framework.TestCase; + +public class MapUtilTest extends TestCase +{ + /** + * Test copying of map + */ + public void testCopyMap() throws Exception { + + HashMap procEnvironment = new HashMap(); + procEnvironment.put("JAVA_HOME", "/usr/opt/java"); + + Map result = MapUtils.copy(procEnvironment); + assertTrue(result.size() == 1); + assertTrue(procEnvironment.size() == 1); + assertEquals("/usr/opt/java", result.get("JAVA_HOME")); + + result.remove("JAVA_HOME"); + assertTrue(result.size() == 0); + assertTrue(procEnvironment.size() == 1); + } + + /** + * Test merging of maps + */ + public void testMergeMap() throws Exception { + + Map procEnvironment = EnvironmentUtils.getProcEnvironment(); + HashMap applicationEnvironment = new HashMap(); + + applicationEnvironment.put("appMainClass", "foo.bar.Main"); + Map result = MapUtils.merge(procEnvironment, applicationEnvironment); + assertTrue((procEnvironment.size() + applicationEnvironment.size()) == result.size()); + assertEquals("foo.bar.Main", result.get("appMainClass")); + } + + /** + * Test prefixing of map + */ + public void testPrefixMap() throws Exception { + + HashMap procEnvironment = new HashMap(); + procEnvironment.put("JAVA_HOME", "/usr/opt/java"); + + Map result = MapUtils.prefix(procEnvironment, "env"); + assertTrue(procEnvironment.size() == result.size()); + assertEquals("/usr/opt/java", result.get("env.JAVA_HOME")); + } +} \ No newline at end of file diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/util/MapUtils.java b/ApacheCommonsExec/src/org/apache/commons/exec/util/MapUtils.java new file mode 100644 index 0000000..f31763f --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/util/MapUtils.java @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec.util; + +import java.util.Map; +import java.util.HashMap; +import java.util.Iterator; + +/** + * Helper classes to manipulate maps to pass substition map to the + * CommandLine. This class is not part of the public API and + * could change without warning. + * + * @author Siegfried Goeschl + */ +public class MapUtils +{ + /** + * Clones a map. + * + * @param source the source map + * @return the clone of the source map + */ + public static Map copy(Map source) { + + if(source == null) { + return null; + } + + Map result = new HashMap(); + result.putAll(source); + 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 behaviour of ANT. + * + * @param source the source map + * @param prefix the prefix used for all names + * @return the clone of the source map + */ + public static Map prefix(Map source, String prefix) { + + if(source == null) { + return null; + } + + Map result = new HashMap(); + + Iterator iter = source.entrySet().iterator(); + + while(iter.hasNext()) { + Map.Entry entry = (Map.Entry) iter.next(); + Object key = entry.getKey(); + Object value = entry.getValue(); + result.put(prefix + '.' + key.toString(), value); + } + + return result; + } + + /** + * Clones the lhs map and add all things from the + * rhs map. + * + * @param lhs the first map + * @param rhs the second map + * @return the merged map + */ + public static Map merge(Map lhs, Map rhs) { + + Map result = null; + + if((lhs == null) || (lhs.size() == 0)) { + result = copy(rhs); + } + else if((rhs == null) || (rhs.size() == 0)) { + result = copy(lhs); + } + else { + result = copy(lhs); + result.putAll(rhs); + } + + return result; + } +} diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/util/StringUtilTest.java b/ApacheCommonsExec/src/org/apache/commons/exec/util/StringUtilTest.java new file mode 100644 index 0000000..ce0f6c6 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/util/StringUtilTest.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec.util; + +import java.util.HashMap; +import java.util.Map; + +import junit.framework.TestCase; + +public class StringUtilTest extends TestCase +{ + /** + * Test no string substitution + */ + public void testNoStringSubstitution() throws Exception + { + Map 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()); + } + + /** + * Test a default string substitution, e.g. all placeholders + * are expanded. + */ + public void testDefaultStringSubstitution() throws Exception + { + Map 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()); + } + + /** + * Test an incomplete string substitution where not all placeholders + * are expanded. + */ + public void testIncompleteSubstitution() throws Exception { + + Map vars = new HashMap(); + vars.put("foo", "FOO"); + + assertEquals("This is a FOO & ${bar} test", StringUtils.stringSubstitution("This is a ${foo} & ${bar} test", vars, true).toString()); + + try + { + StringUtils.stringSubstitution("This is a ${foo} & ${bar} test", vars, false).toString(); + fail(); + } + catch(RuntimeException e) + { + // nothing to do + } + } + + /** + * Test a erroneous template. + */ + public void testErroneousTemplate() throws Exception + { + Map vars = new HashMap(); + vars.put("foo", "FOO"); + + assertEquals("This is a FOO & ${}} test", StringUtils.stringSubstitution("This is a ${foo} & ${}} test", vars, true).toString()); + } +} \ No newline at end of file diff --git a/ApacheCommonsExec/src/org/apache/commons/exec/util/StringUtils.java b/ApacheCommonsExec/src/org/apache/commons/exec/util/StringUtils.java new file mode 100644 index 0000000..cb3d527 --- /dev/null +++ b/ApacheCommonsExec/src/org/apache/commons/exec/util/StringUtils.java @@ -0,0 +1,258 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + * + */ + +package org.apache.commons.exec.util; + + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; +import java.io.File; + +/** + * Supplement of commons-lang, the stringSubstitution() was in a simpler + * implementation available in an older commons-lang implementation. + * + * This class is not part of the public API and could change without + * warning. + * + * @author Siegfried Goeschl + */ +public class StringUtils { + + private static final String SINGLE_QUOTE = "\'"; + private static final String DOUBLE_QUOTE = "\""; + private static final char SLASH_CHAR = '/'; + private static final char BACKSLASH_CHAR = '\\'; + + /** + * Perform a series of substitutions. The substitutions + * are performed by replacing ${variable} in the target + * string with the value of provided by the key "variable" + * in the provided hash table. + *

+ * A key consists of the following characters: + *

    + *
  • letter + *
  • digit + *
  • dot character + *
  • hyphen character + *
  • plus character + *
  • underscore character + *
+ * + * @param argStr the argument string to be processed + * @param vars name/value pairs used for substitution + * @param isLenient ignore a key not found in vars or throw a RuntimeException? + * @return String target string with replacements. + */ + public static StringBuffer stringSubstitution(String argStr, Map vars, boolean isLenient) { + + StringBuffer argBuf = new StringBuffer(); + + if (argStr == null || argStr.length() == 0) { + return argBuf; + } + + if (vars == null || vars.size() == 0) { + return argBuf.append(argStr); + } + + int argStrLength = argStr.length(); + + for (int cIdx = 0; cIdx < argStrLength;) { + + char ch = argStr.charAt(cIdx); + char del = ' '; + + switch (ch) { + + case '$': + StringBuffer nameBuf = new StringBuffer(); + del = argStr.charAt(cIdx + 1); + if (del == '{') { + cIdx++; + + for (++cIdx; cIdx < argStr.length(); ++cIdx) { + ch = argStr.charAt(cIdx); + if (ch == '_' || ch == '.' || ch == '-' || ch == '+' || Character.isLetterOrDigit(ch)) + nameBuf.append(ch); + else + break; + } + + if (nameBuf.length() >= 0) { + + String value; + Object temp = vars.get(nameBuf.toString()); + + if(temp instanceof File) { + // for a file we have to fix the separator chars to allow + // cross-platform compatibility + value = fixFileSeparatorChar(((File) temp).getAbsolutePath()); + } + else { + value = (temp != null ? temp.toString() : null); + } + + if (value != null) { + argBuf.append(value); + } else { + if (isLenient) { + // just append the unresolved variable declaration + argBuf.append("${").append(nameBuf.toString()).append("}"); + } else { + // complain that no variable was found + throw new RuntimeException("No value found for : " + nameBuf); + } + } + + del = argStr.charAt(cIdx); + + if (del != '}') { + throw new RuntimeException("Delimiter not found for : " + nameBuf); + } + } + + cIdx++; + } + else { + argBuf.append(ch); + ++cIdx; + } + + break; + + default: + argBuf.append(ch); + ++cIdx; + break; + } + } + + 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(String input, String splitChar) { + StringTokenizer tokens = new StringTokenizer(input, splitChar); + List strList = new ArrayList(); + while (tokens.hasMoreTokens()) { + strList.add(tokens.nextToken()); + } + return (String[]) strList.toArray(new String[strList.size()]); + } + + /** + * Fixes the file separator char for the target platform + * using the following replacement. + * + *
    + *
  • '/' ==> File.separatorChar + *
  • '\\' ==> File.separatorChar + *
+ * + * @param arg the argument to fix + * @return the transformed argument + */ + public static String fixFileSeparatorChar(String arg) { + return arg.replace(SLASH_CHAR, File.separatorChar).replace( + BACKSLASH_CHAR, File.separatorChar); + } + + /** + * Concatenates an array of string using a separator. + * + * @param strings the strings to concatenate + * @param separator the separator between two strings + * @return the concatenated strings + */ + public static String toString(String[] strings, String separator) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < strings.length; i++) { + if (i > 0) { + sb.append(separator); + } + sb.append(strings[i]); + } + return sb.toString(); + } + + /** + * Put quotes around the given String if necessary. + *

+ * 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. + *

+ * + * @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 StringBuffer buf = new StringBuffer(); + 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"); + } else { + return buf.append(SINGLE_QUOTE).append(cleanedArgument).append( + SINGLE_QUOTE).toString(); + } + } else if (cleanedArgument.indexOf(SINGLE_QUOTE) > -1 + || cleanedArgument.indexOf(" ") > -1) { + return buf.append(DOUBLE_QUOTE).append(cleanedArgument).append( + DOUBLE_QUOTE).toString(); + } else { + 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/ApacheCommonsExec/src/site/apt/commandline.apt b/ApacheCommonsExec/src/site/apt/commandline.apt new file mode 100644 index 0000000..bd93624 --- /dev/null +++ b/ApacheCommonsExec/src/site/apt/commandline.apt @@ -0,0 +1,150 @@ +~~ +~~ Licensed to the Apache Software Foundation (ASF) under one or more +~~ contributor license agreements. See the NOTICE file distributed with +~~ this work for additional information regarding copyright ownership. +~~ The ASF licenses this file to You 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. +~~ +~~ + + -------- +Apache Commons Exec - Building the command line + -------- + -------- +20 August 2010 + -------- + +Building the command line + +You have two ways to create the command line to be executed + + * parsing the entire command line string + + * building the command line incrementally + +* General Considerations + + No matter which approach you are using commons-exec does change your command + line arguments in the following two cases + + * when the executable contains forward or backward slashes + + * when a command line argument contains an unquoted string + + The following executable arguments + +---------------------------------------- +./bin/vim +---------------------------------------- + + will be translated under Windows to + +---------------------------------------- +.\\bin\\vim +---------------------------------------- + +* Parsing the entire command line string + + Parsing the command line string is easy to use but you might run into + problems when tackling complex scenarios. Therefore this functionality + was deprecated in the {{{http://ant.apache.org/manual/Tasks/exec.html}Ant Exec task}}. + + Let's have a look at few examples you would like to stick to parsing entire command + line strings + +** Spaces in command line arguments + + Here we would like to invoke a batch file which contains spaces in the path + +---------------------------------------- +cmd.exe /C c:\was51\Web Sphere\AppServer\bin\versionInfo.bat +---------------------------------------- + + Due to the space in the file name we have to quote the file name either with + single or double quotes otherwise it falls apart into two command line + arguments and . + +---------------------------------------- +String line = "cmd.exe /C 'c:\\was51\\Web Sphere\\AppServer\\bin\\versionInfo.bat'"; +---------------------------------------- + +* Building the Command Line Incrementally + + This is the recommended approach and caters also for pre-quoted command + line argument. + +** A simple example + + Now we would like to build the following command line + +---------------------------------------- +runMemorySud.cmd 10 30 -XX:+UseParallelGC -XX:ParallelGCThreads=2 +---------------------------------------- + + using the following code snippet + +---------------------------------------- +CommandLine cmdl = new CommandLine("runMemorySud.cmd"); +cmdl.addArgument("10"); +cmdl.addArgument("30"); +cmdl.addArgument("-XX:+UseParallelGC"); +cmdl.addArgument("-XX:ParallelGCThreads=2"); +---------------------------------------- + +** A complex example + + Now let's have a look at the following command line found somewhere in the + internet + +---------------------------------------- +dotnetfx.exe /q:a /c:"install.exe /l ""\Documents and Settings\myusername\Local Settings\Temp\netfx.log"" /q" +---------------------------------------- + + The following code snippet builds the command line using pre-quoted + arguments and variable expansion + +---------------------------------------- +File file = new File("/Documents and Settings/myusername/Local Settings/Temp/netfx.log"); +Map map = new HashMap(); +map.put("FILE", file); + +cmdl = new CommandLine("dotnetfx.exe"); +cmdl.setSubstitutionMap(map); +cmdl.addArgument("/q:a", false); +cmdl.addArgument("/c:\"install.exe /l \"\"${FILE}\"\" /q\"", false); +---------------------------------------- + +* For the Desperate + + When crafting a command line it would be really helpful to see what + happens to your command line arguments. The following scripts can be + invoked to print your command line arguments for Unix + +---------------------------------------- +while [ $# -gt 0 ] +do + echo "$1" + shift +done +---------------------------------------- + + and for Windows + +---------------------------------------- +:Loop +IF [%1]==[] GOTO Continue + @ECHO "%1" +SHIFT +GOTO Loop +:Continue +---------------------------------------- + diff --git a/ApacheCommonsExec/src/site/apt/index.apt b/ApacheCommonsExec/src/site/apt/index.apt new file mode 100644 index 0000000..1a8fc35 --- /dev/null +++ b/ApacheCommonsExec/src/site/apt/index.apt @@ -0,0 +1,57 @@ +~~ +~~ Licensed to the Apache Software Foundation (ASF) under one or more +~~ contributor license agreements. See the NOTICE file distributed with +~~ this work for additional information regarding copyright ownership. +~~ The ASF licenses this file to You 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. +~~ +~~ + + -------- +Apache Commons Exec + -------- + -------- +12 November 2008 + -------- + +Apache Commons Exec + +* Rationale + + Executing external processes from Java is a well-known problem area. It is inheriently platform dependent and requires + the developer to know and test for platform specific behaviors, for example using cmd.exe on Windows or limited buffer + sizes causing deadlocks. The JRE support for this is very limited, albeit better with the new Java SE 1.5 + ProcessBuilder class. + + Reliably executing external processes can also require knowledge of the environment variables before or after the + command is executed. In J2SE 1.1-1.4 there is not support for this, since the method, <<>>, for + retriving environment variables is deprecated. + + There are currently several different libraries that for their own purposes have implemented frameworks around + <<>> to handle the various issues outlined above. The proposed project should aim at coordinating and + learning from these initatives to create and maintain a simple, reusable and well-tested package. Since some of the + more problematic platforms are not readily available, it is my hope that the broad Apache community can be a + great help. + +* Scope of the package + + The package shall create and maintain a process execution package written in the Java language to be distributed + under the ASF license. The Java code might also be complemented with scripts (e.g. Perl scripts) to fully enable + execution on some operating systems. The package should aim for supporting a wide range of operating systems while + still having a consistent API for all platforms. + +* Releases + + The latest version v1.1, is JDK 1.3 compatible - + {{{http://commons.apache.org/exec/download_exec.cgi}Download now!}}. + + For previous releases, see the {{{http://archive.apache.org/dist/commons/exec/}Apache Archive}}. \ No newline at end of file diff --git a/ApacheCommonsExec/src/site/apt/technical.apt b/ApacheCommonsExec/src/site/apt/technical.apt new file mode 100644 index 0000000..bc38fda --- /dev/null +++ b/ApacheCommonsExec/src/site/apt/technical.apt @@ -0,0 +1,36 @@ +~~ +~~ Licensed to the Apache Software Foundation (ASF) under one or more +~~ contributor license agreements. See the NOTICE file distributed with +~~ this work for additional information regarding copyright ownership. +~~ The ASF licenses this file to You 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. +~~ +~~ + + -------- +Apache Commons Exec Technical Details + -------- + -------- +16 August 2010 + -------- + +Apache Commons Exec + +* An Implementation Overview + + Looking at commons-exec can be a bit daunting the first time therefore an + overview of the implementation helps. + +** DefaultExecutor + The main class is <> where you defined the command line + of the sub-process to be executed. + diff --git a/ApacheCommonsExec/src/site/apt/tutorial.apt b/ApacheCommonsExec/src/site/apt/tutorial.apt new file mode 100644 index 0000000..0b6781a --- /dev/null +++ b/ApacheCommonsExec/src/site/apt/tutorial.apt @@ -0,0 +1,178 @@ +~~ +~~ Licensed to the Apache Software Foundation (ASF) under one or more +~~ contributor license agreements. See the NOTICE file distributed with +~~ this work for additional information regarding copyright ownership. +~~ The ASF licenses this file to You 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. +~~ +~~ + + -------- +Apache Commons Exec Tutorial + -------- + -------- +15 September 2010 + -------- + +Apache Commons Exec + +* The First Encounter + + At this point we can safely assume that you would like to start some subprocesses from within your + Java application and you spent some time here to do it properly. You look at Commons Exec and think + "Wow - calling Runtime.exec() is easy and the Apache folks are wasting their and my time + with tons of code". + + Well, we learned it the hard way (in my case more than once) that using plain Runtime.exec() can be + a painful experience. Therefore you are invited to delve into commons-exec and have a look at the + hard lessons the easy way ... + +* Taming Your First Process + + Let's look at a real example - we would like to print PDF documents from within your Java + application. After googling a while it turns out to be a minor headache and using Adobe Acrobat + seems to be a good option. + + The command line under Windows should look like "AcroRd32.exe /p /h file" assuming that the + Acrobat Reader is found in the path. + ++---------------------------------------------------------------------------- +String line = "AcroRd32.exe /p /h " + file.getAbsolutePath(); +CommandLine cmdLine = CommandLine.parse(line); +DefaultExecutor executor = new DefaultExecutor(); +int exitValue = executor.execute(cmdLine); ++---------------------------------------------------------------------------- + + You successfully printed your first PDF document but at the end an exception is thrown - what + happend? Oops, Acrobat Reader returned an exit value of '1' on success which is usually + considered as an execution failure. So we have to tweak our code to fix this odd behaviour - + we define the exit value of "1" to be considered as successful execution. + ++---------------------------------------------------------------------------- +String line = "AcroRd32.exe /p /h " + file.getAbsolutePath(); +CommandLine cmdLine = CommandLine.parse(line); +DefaultExecutor executor = new DefaultExecutor(); +executor.setExitValue(1); +int exitValue = executor.execute(cmdLine); ++---------------------------------------------------------------------------- + +* To Watchdog Or Not To Watchdog + + You happily printed for a while but now your application blocks - your printing subprocess + hangs for some obvious or not so obvious reason. Starting is easy but what to do with a run-away + Acrobat Reader telling you that printing failed due to a lack of paper?! Luckily commons-exec + provides a watchdog which does the work for you. Here is the improved code which kills a + run-away process after sixty seconds. + ++---------------------------------------------------------------------------- +String line = "AcroRd32.exe /p /h " + file.getAbsolutePath(); +CommandLine cmdLine = CommandLine.parse(line); +DefaultExecutor executor = new DefaultExecutor(); +executor.setExitValue(1); +ExecuteWatchdog watchdog = new ExecuteWatchdog(60000); +executor.setWatchdog(watchdog); +int exitValue = executor.execute(cmdLine); ++---------------------------------------------------------------------------- + +* Quoting Is Your Friend + + Well, the code worked for quite a while until a new customer complained that + no documents are printed. It took half a day to find out that the following file + 'C:\\Document And Settings\\documents\\432432.pdf' could not be printed. Due to the + spaces and without further quoting the command line fell literally apart into + the following snippet + ++---------------------------------------------------------------------------- +> AcroRd32.exe /p /h C:\Document And Settings\documents\432432.pdf ++---------------------------------------------------------------------------- + + As a quick fix we added double quotes which tells commons-exec to handle + the file as a single command line argument instead of splitting it into + parts. + ++---------------------------------------------------------------------------- +String line = "AcroRd32.exe /p /h \"" + file.getAbsolutePath() + "\""; +CommandLine cmdLine = CommandLine.parse(line); +DefaultExecutor executor = new DefaultExecutor(); +executor.setExitValue(1); +ExecuteWatchdog watchdog = new ExecuteWatchdog(60000); +executor.setWatchdog(watchdog); +int exitValue = executor.execute(cmdLine); ++---------------------------------------------------------------------------- + +* Build the Command Line Incrementally + + The previous problem stems from the fact that commons-exec tried to split + a single command line string into a string array considering single and + double quotes. At the end of the day this is error-prone so we recommend + building the command line incrementally - according to the same reasoning + the Ant documentation does not recommend passing a single command line to + the target (see deprecated command attribute for + {{{http://ant.apache.org/manual/CoreTasks/exec.html}exec}} task) + ++---------------------------------------------------------------------------- +Map map = new HashMap(); +map.put("file", new File("invoice.pdf")); +CommandLine cmdLine = new CommandLine("AcroRd32.exe"); +cmdLine.addArgument("/p"); +cmdLine.addArgument("/h"); +cmdLine.addArgument("${file}"); +cmdLine.setSubstitutionMap(map); +DefaultExecutor executor = new DefaultExecutor(); +executor.setExitValue(1); +ExecuteWatchdog watchdog = new ExecuteWatchdog(60000); +executor.setWatchdog(watchdog); +int exitValue = executor.execute(cmdLine); ++---------------------------------------------------------------------------- + + Please note that we are passing an 'java.io.File' instance for expanding + the command line arguments - this allows to convert the resulting file name + on the fly to match your OS. + +* Unblock Your Execution + + Up to now we have a working example but it would not be good enough for + production - because it is blocking. + + Your worker thread will block until the print process has finished or + was killed by the watchdog. Therefore executing the print job + asynchronously will do the trick. In this example we create an instance + of 'ExecuteResultHandler' and pass it to the 'Executor' instance in order + to execute the process asynchronously. The 'resultHandler' picks up any + offending exception or the process exit code. + ++---------------------------------------------------------------------------- +CommandLine cmdLine = new CommandLine("AcroRd32.exe"); +cmdLine.addArgument("/p"); +cmdLine.addArgument("/h"); +cmdLine.addArgument("${file}"); +HashMap map = new HashMap(); +map.put("file", new File("invoice.pdf")); +commandLine.setSubstitutionMap(map); + +DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler(); + +ExecuteWatchdog watchdog = new ExecuteWatchdog(60*1000); +Executor executor = new DefaultExecutor(); +executor.setExitValue(1); +executor.setWatchdog(watchdog); +executor.execute(cmdLine, resultHandler); + +// some time later the result handler callback was invoked so we +// can safely request the exit value +int exitValue = resultHandler.waitFor(); ++---------------------------------------------------------------------------- + +* Get Your Hands Dirty + + A tutorial is nice but executing the tutorial code is even nicer. You find + the ready-to-run tutorial under {{{http://commons.apache.org/exec/xref-test/org/apache/commons/exec/TutorialTest.html}src/test/java/org/apache/commons/exec/TutorialTest.java}}. diff --git a/ApacheCommonsExec/src/site/fml/faq.fml b/ApacheCommonsExec/src/site/fml/faq.fml new file mode 100644 index 0000000..5695c46 --- /dev/null +++ b/ApacheCommonsExec/src/site/fml/faq.fml @@ -0,0 +1,85 @@ + + + + + + + General + + How mature is it? + +

The code was ported from Apache Ant and extensively + tested on various platforms. So there is no reason not to use it and it is very likely + better than any home-grown library.

+
+
+ + How do I create a complex command line using single and double quotes? + +

It is recommended to use CommandLine.addArgument() instead of CommandLine.parse(). Using + CommandLine.parse() the implementation tries to figure out the correct quoting using your + arguments and file names containing spaces. With CommandLine.addArgument() you can + enable/disable quoting depending on your requirements. Having said that this is the + recommended approach using Ant anyway.

+
+
+ + Are child processes automatically killed? + +

This functionality is largely depend on the operating system - on Unix it works + mostly and under Windows not at all (see + Bug 4770092). In terms of stability and cross-platform support try to start your applications directly and + avoid various wrapper scripts.

+
+
+ + Does commons-exec support java-gcj? + +

Well - one out of 55 regression tests fails. The + EnvironmentUtilTest.testGetProcEnvironment() test fails because it detects no environment + variables for the current process but there must be one since we require JAVA_HOME to be + set. Not sure if this is a plain bug in java-gcj-4.2.1 or requires a work around in + commons-exec

+
+
+ + + How to test commons-exec on my environment? + +

Assuming that you have an environment not listed on the test + matrix and want to make sure that everything works fine you can run easily run the + regression tests. Make a SVN checkout and run 'ant test-distribution' to create the test + distribution in './target'. On a production box downloading the ready-to-run test + distribution might be even more handy ( + http://people.apache.org/~sgoeschl/download/commons-exec/). Unpack the 'zip' or + 'tar.gz' file and start the tests. Independent from the result we very much appreciate + your feedback ... :-)

+
+ Why is the regression test broken on my Unix box + +

Please check if the shell scripts under "./src/test/script" are executable - assuming + that they are not executable the "testExecute*" and "testExecuteAsync*" test will + fail. We try very hard to keep the executable bit but they have somehow the tendency + to to be lost ... +

+
+
+
+
diff --git a/ApacheCommonsExec/src/site/site.xml b/ApacheCommonsExec/src/site/site.xml new file mode 100644 index 0000000..b64ff5e --- /dev/null +++ b/ApacheCommonsExec/src/site/site.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ApacheCommonsExec/src/site/xdoc/download_exec.xml b/ApacheCommonsExec/src/site/xdoc/download_exec.xml new file mode 100644 index 0000000..6255b11 --- /dev/null +++ b/ApacheCommonsExec/src/site/xdoc/download_exec.xml @@ -0,0 +1,138 @@ + + + + + + Download Commons Exec + Commons Documentation Team + + +
+ +

+ We recommend you use a mirror to download our release + builds, but you must verify the integrity of + the downloaded files using signatures downloaded from our main + distribution directories. Recent releases (48 hours) may not yet + be available from the mirrors. +

+ +

+ You are currently using [preferred]. If you + encounter a problem with this mirror, please select another + mirror. If all mirrors are failing, there are backup + mirrors (at the end of the mirrors list) that should be + available. +

+ [if-any logo][end] +

+ +
+

+ Other mirrors: + + +

+
+ +

+ The KEYS + link links to the code signing keys used to sign the product. + The PGP link downloads the OpenPGP compatible signature from our main site. + The MD5 link downloads the checksum from the main site. +

+
+
+
+ + + + + + + + + + + + +
commons-exec-1.1-bin.tar.gzmd5pgp
commons-exec-1.1-bin.zipmd5pgp
+
+ + + + + + + + + + + + +
commons-exec-1.1-src.tar.gzmd5pgp
commons-exec-1.1-src.zipmd5pgp
+
+
+
+

+ Older releases can be obtained from the archives. +

+ +
+ +
diff --git a/ApacheCommonsExec/src/site/xdoc/issue-tracking.xml b/ApacheCommonsExec/src/site/xdoc/issue-tracking.xml new file mode 100644 index 0000000..7dbd717 --- /dev/null +++ b/ApacheCommonsExec/src/site/xdoc/issue-tracking.xml @@ -0,0 +1,102 @@ + + + + + + Commons Exec Issue tracking + Commons Documentation Team + + + +
+

+ Commons Exec uses ASF JIRA for tracking issues. + See the Commons Exec JIRA project page. +

+ +

+ To use JIRA you may need to create an account + (if you have previously created/updated Commons issues using Bugzilla an account will have been automatically + created and you can use the Forgot Password + page to get a new password). +

+ +

+ If you would like to report a bug, or raise an enhancement request with + Commons Exec please do the following: +

    +
  1. Search existing open bugs. + If you find your issue listed then please add a comment with your details.
  2. +
  3. Search the mailing list archive(s). + You may find your issue or idea has already been discussed.
  4. +
  5. Decide if your issue is a bug or an enhancement.
  6. +
  7. Submit either a bug report + or enhancement request.
  8. +
+

+ +

+ Please also remember these points: +

    +
  • the more information you provide, the better we can help you
  • +
  • test cases are vital, particularly for any proposed enhancements
  • +
  • the developers of Commons Exec are all unpaid volunteers
  • +
+

+ +

+ For more information on subversion and creating patches see the + Apache Contributors Guide. +

+ +

+ You may also find these links useful: +

+

+
+ +
diff --git a/ApacheCommonsExec/src/site/xdoc/mail-lists.xml b/ApacheCommonsExec/src/site/xdoc/mail-lists.xml new file mode 100644 index 0000000..29ecbcd --- /dev/null +++ b/ApacheCommonsExec/src/site/xdoc/mail-lists.xml @@ -0,0 +1,202 @@ + + + + + + Commons Exec Mailing Lists + Commons Documentation Team + + + +
+

+ Commons Exec shares mailing lists with all the other + Commons Components. + To make it easier for people to only read messages related to components they are interested in, + the convention in Commons is to prefix the subject line of messages with the component's name, + for example: +

    +
  • [exec] Problem with the ...
  • +
+

+

+ Questions related to the usage of Commons Exec should be posted to the + User List. +
+ The Developer List + is for questions and discussion related to the development of Commons Exec. +
+ Please do not cross-post; developers are also subscribed to the user list. +

+

+ Note: please don't send patches or attachments to any of the mailing lists. + Patches are best handled via the Issue Tracking system. + Otherwise, please upload the file to a public server and include the URL in the mail. +

+
+ +
+

+ Please prefix the subject line of any messages for Commons Exec + with [exec] - thanks! +
+
+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameSubscribeUnsubscribePostArchiveOther Archives
+ Commons User List +

+ Questions on using Commons Exec. +

+
SubscribeUnsubscribePostmail-archives.apache.orgmarkmail.org
+ www.mail-archive.com
+ news.gmane.org +
+ Commons Developer List +

+ Discussion of development of Commons Exec. +

+
SubscribeUnsubscribePostmail-archives.apache.orgmarkmail.org
+ www.mail-archive.com
+ news.gmane.org +
+ Commons Issues List +

+ Only for e-mails automatically generated by the issue tracking system. +

+
SubscribeUnsubscriberead onlymail-archives.apache.orgmarkmail.org
+ www.mail-archive.com +
+ Commons Commits List +

+ Only for e-mails automatically generated by the source control sytem. +

+
SubscribeUnsubscriberead onlymail-archives.apache.orgmarkmail.org
+ www.mail-archive.com +
+ +
+
+

+ Other mailing lists which you may find useful include: +

+ + + + + + + + + + + + + + + + + + +
NameSubscribeUnsubscribePostArchiveOther Archives
+ Apache Announce List +

+ General announcements of Apache project releases. +

+
SubscribeUnsubscriberead onlymail-archives.apache.orgmarkmail.org
+ old.nabble.com
+ www.mail-archive.com
+ news.gmane.org +
+ +
+ +
diff --git a/ApacheCommonsExec/src/site/xdoc/testmatrix.xml b/ApacheCommonsExec/src/site/xdoc/testmatrix.xml new file mode 100644 index 0000000..621abb5 --- /dev/null +++ b/ApacheCommonsExec/src/site/xdoc/testmatrix.xml @@ -0,0 +1,210 @@ + + + + + Commons Exec Test Matrix + Siegfried Goeschl + + +
+

The following tables contains the test results of running the comons-exec regression tests + on different OS/JVMs

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Operating SystemJVMStatusReporter
Linux (2.6.34.7-56.fc1, x86, 64 bit)java version "1.6.0_20"
Java(TM) SE Runtime Environment (build + 1.6.0_20-b02)
Java HotSpot(TM) 64-Bit Server VM (build 16.3-b01, mixed mode)
PassedJames Carman
Linux (2.6.35-gentoo-r9, x86, 64 bit)java version "1.6.0_21"
Java(TM) SE Runtime Environment (build + 1.6.0_21-b06)
Java HotSpot(TM) 64-Bit Server VM (build 17.0-b16, mixed mode)
PassedJörg Schaible
Linux (2.6.35-gentoo-r9, x86, 64 bit)java version "1.5.0_22"
Java(TM) 2 Runtime Environment, Standard Edition (build + 1.5.0_22-b03)
Java HotSpot(TM) 64-Bit Server VM (build 1.5.0_22-b03, mixed + mode)
PassedJörg Schaible
Linux (2.6.35-gentoo-r9, x86, 64 bit)java version "1.4.2-03"
Java(TM) 2 Runtime Environment, Standard Edition (build + Blackdown-1.4.2-03)
Java HotSpot(TM) 64-Bit Server VM (build Blackdown-1.4.2-03, + mixed mode)
Failed
DefaultExecutorTest#testEnvironmentVariables
DefaultExecutorTest#testAddEnvironmentVariables
Jörg Schaible
Linux (2.6.35-gentoo-r9, x86, 64 bit)java version "1.5.0"
Java(TM) 2 Runtime Environment, Standard Edition (build pxa64dev-20100813 (SR12 FP1 + ))
IBM J9 VM (build 2.3, J2RE 1.5.0 IBM J9 2.3 Linux + amd64-64
j9vmxa6423-20100808 (JIT enabled)
PassedJörg Schaible
Linux (2.6.35-gentoo-r9, x86, 64 bit)java version "1.6.0"
Java(TM) SE Runtime Environment (build + pxa6460sr8fp1-20100624_01(SR8 FP1))
IBM J9 VM (build 2.4, JRE 1.6.0 IBM J9 2.4 + Linux amd64-64
jvmxa6460sr8ifx-20100609_59383 (JIT enabled, AOT enabled)
PassedJörg Schaible
Linux (2.6.35-gentoo-r9, x86, 64 bit)java version "1.6.0_18"
OpenJDK Runtime Environment (IcedTea6 1.8.1) (Gentoo + build 1.6.0_18-b18)
OpenJDK 64-Bit Server VM (build 16.0-b13, mixed mode)
PassedJörg Schaible
Linux (2.6.35-gentoo-r9, x86, 64 bit)java version "1.5.0"
JamVM version 1.5.4
Copyright (C) 2003-2010 Robert + Lougher GPL2
Execution Engine: inline-threaded interpreter
Compiled with: gcc + 4.4.3
Failed
DefaultExecutorTest#testExecuteAsyncWithTimelyUserTermination
Jörg Schaible
+
+ + + + + + + + + + + + + + + + + + + + +
Operating SystemJVMStatusReporter
Mac OS X (Darwin Kernel Version 10.4.0)java version "1.6.0_20"
Java(TM) SE Runtime Environment (build + 1.6.0_20-b02)
Java HotSpot(TM) 64-Bit Server VM (build 16.3-b01, mixed mode)
PassedJames Carman
Mac OS X (Darwin Kernel Version 10.4.0)java version "1.5.0_24"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_24-b02-357-10M3065)
Java HotSpot(TM) Client VM (build 1.5.0_24-149, mixed mode, sharing)
PassedSimon Tripodi
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Operating SystemJVMStatusReporter
Windows 7 Professional 64 bitjava version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02)
Java HotSpot(TM) 64-Bit Server VM (build 16.3-b01, mixed mode)
PassedJames Carman
Windows 7 Enterprisejava version "1.6.0_21"PassedNiall Pemberton
Windows 7 Enterprisejava version "1.5.0_22-b03"PassedNiall Pemberton
Windows 7 Enterprisejava version "1.4.2_19-b04"PassedNiall Pemberton
Windows 7 Enterprisejava version "1.3.1_18-b01"PassedNiall Pemberton
Windows Vista Businessjava version "1.6.0_21"
Java(TM) SE Runtime Environment (build 1.6.0_21-b07)
Java HotSpot(TM) 64-Bit Server VM (build 17.0-b17, mixed mode)
PassedGary Gregory
+
+ + + + + + + + + + + + + + + + + + + + +
Operating SystemJVMStatusReporter
OpenVMS V8.3 (AlphaServer ES40 - 4 CPUs)Fast VM (build 1.5.0-4, build J2SDK.v.1.5.0:03/31/2008-15:26, native threads, jit_150)Fails tests which try to terminate a subprocess +
    +
  • DefaultExecutorTest#testExecuteAsyncWithTimelyUserTermination
  • +
  • DefaultExecutorTest#testExecuteAsyncWithTooLateUserTermination
  • +
  • DefaultExecutorTest#testExecuteWatchdogSync - test hangs
  • +
  • DefaultExecutorTest#testExecuteWatchdogAsync
  • +
  • DefaultExecutorTest#testExecuteAsyncWithProcessDestroyer
  • +
  • DefaultExecutorTest#testExec41WithoutStreams
  • +
+
Sebastian Bazley
OpenVMS V8.3-1H1 (Integrity HP rx2600 (1.30GHz/3.0MB) - 2 CPUs)Java HotSpot(TM) Server VM (build 1.5.0-2 12/02/2006-21:30 IA64, mixed mode)Fails tests which try to terminate a subprocess +
    +
  • DefaultExecutorTest#testExecuteAsyncWithTimelyUserTermination
  • +
  • DefaultExecutorTest#testExecuteAsyncWithTooLateUserTermination
  • +
  • DefaultExecutorTest#testExecuteWatchdogSync - test hangs
  • +
  • DefaultExecutorTest#testExecuteWatchdogAsync
  • +
  • DefaultExecutorTest#testExecuteAsyncWithProcessDestroyer
  • +
  • DefaultExecutorTest#testExec41WithoutStreams
  • +
+
Sebastian Bazley
+
+ +
+ +
diff --git a/ApacheCommonsExec/src/test/bin/testme.bat b/ApacheCommonsExec/src/test/bin/testme.bat new file mode 100644 index 0000000..75fef8e --- /dev/null +++ b/ApacheCommonsExec/src/test/bin/testme.bat @@ -0,0 +1,20 @@ +@ECHO OFF +REM +REM Licensed to the Apache Software Foundation (ASF) under one or more +REM contributor license agreements. See the NOTICE file distributed with +REM this work for additional information regarding copyright ownership. +REM The ASF licenses this file to You under the Apache License, Version 2.0 +REM (the "License"); you may not use this file except in compliance with +REM the License. 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 + +mkdir target +"%JAVA_HOME%\bin\java" -cp .\lib\junit-3.8.1.jar;.\lib\commons-exec-${project.version}-tests.jar;.\lib\commons-exec-${project.version}.jar org.apache.commons.exec.TestRunner \ No newline at end of file diff --git a/ApacheCommonsExec/src/test/bin/testme.dcl b/ApacheCommonsExec/src/test/bin/testme.dcl new file mode 100644 index 0000000..8974f04 --- /dev/null +++ b/ApacheCommonsExec/src/test/bin/testme.dcl @@ -0,0 +1,25 @@ +$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +$! +$! Licensed to the Apache Software Foundation (ASF) under one or more +$! contributor license agreements. See the NOTICE file distributed with +$! this work for additional information regarding copyright ownership. +$! The ASF licenses this file to You 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. +$! +$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +$! +$! Run the test suite +$! +$ create/directory [.target] +$ java "-Dorg.apache.commons.exec.lenient=false" "-Dorg.apache.commons.exec.debug=false" - + -cp "./lib/junit-3.8.1.jar:./lib/commons-exec-${project.version}-tests.jar:./lib/commons-exec-${project.version}.jar" - + "org.apache.commons.exec.TestRunner" \ No newline at end of file diff --git a/ApacheCommonsExec/src/test/bin/testme.sh b/ApacheCommonsExec/src/test/bin/testme.sh new file mode 100644 index 0000000..d3e8d24 --- /dev/null +++ b/ApacheCommonsExec/src/test/bin/testme.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# + +chmod ug+x ./src/test/scripts/*.sh +mkdir target +$JAVA_HOME/bin/java -Dorg.apache.commons.exec.lenient=false -Dorg.apache.commons.exec.debug=false -cp ./lib/junit-3.8.1.jar:./lib/commons-exec-${project.version}-tests.jar:./lib/commons-exec-${project.version}.jar org.apache.commons.exec.TestRunner \ No newline at end of file diff --git a/ApacheCommonsExec/src/test/scripts/acrord32.bat b/ApacheCommonsExec/src/test/scripts/acrord32.bat new file mode 100644 index 0000000..7971e14 --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/acrord32.bat @@ -0,0 +1,21 @@ +@ECHO OFF + +REM Licensed to the Apache Software Foundation (ASF) under one or more +REM contributor license agreements. See the NOTICE file distributed with +REM this work for additional information regarding copyright ownership. +REM The ASF licenses this file to You under the Apache License, Version 2.0 +REM (the "License"); you may not use this file except in compliance with +REM the License. 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. + +echo "[acrord32] Printing the following document : '%3'" +ping -n 10 -w 1000 127.0.0.1 > nul +echo "[acrord32] Finished printing" +exit 1 diff --git a/ApacheCommonsExec/src/test/scripts/acrord32.sh b/ApacheCommonsExec/src/test/scripts/acrord32.sh new file mode 100644 index 0000000..dbe185a --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/acrord32.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# + +# Simulate printing a PDF document + +echo "[acrord32] Printing the following document : $3" +for i in {1..10} +do + sleep 1 +done +echo "[acrord32] Finished printing" +exit 1 + diff --git a/ApacheCommonsExec/src/test/scripts/environment.bat b/ApacheCommonsExec/src/test/scripts/environment.bat new file mode 100644 index 0000000..d462d42 --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/environment.bat @@ -0,0 +1,22 @@ +@ECHO OFF + +REM Little batch file to run nearly foerver +REM see http://malektips.com/dos0017.html +REM +REM Licensed to the Apache Software Foundation (ASF) under one or more +REM contributor license agreements. See the NOTICE file distributed with +REM this work for additional information regarding copyright ownership. +REM The ASF licenses this file to You under the Apache License, Version 2.0 +REM (the "License"); you may not use this file except in compliance with +REM the License. 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 print the environment variables +set \ No newline at end of file diff --git a/ApacheCommonsExec/src/test/scripts/environment.dcl b/ApacheCommonsExec/src/test/scripts/environment.dcl new file mode 100644 index 0000000..8ee0a9f --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/environment.dcl @@ -0,0 +1,22 @@ +$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +$! +$! Licensed to the Apache Software Foundation (ASF) under one or more +$! contributor license agreements. See the NOTICE file distributed with +$! this work for additional information regarding copyright ownership. +$! The ASF licenses this file to You 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. +$! +$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +$! +$! print the "environment" variables +$! +$ show symbol * \ No newline at end of file diff --git a/ApacheCommonsExec/src/test/scripts/environment.sh b/ApacheCommonsExec/src/test/scripts/environment.sh new file mode 100644 index 0000000..a875b5c --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/environment.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# + +# print the environment variables +env \ No newline at end of file diff --git a/ApacheCommonsExec/src/test/scripts/error.bat b/ApacheCommonsExec/src/test/scripts/error.bat new file mode 100644 index 0000000..3902b20 --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/error.bat @@ -0,0 +1,22 @@ +@ECHO OFF + +REM Licensed to the Apache Software Foundation (ASF) under one or more +REM contributor license agreements. See the NOTICE file distributed with +REM this work for additional information regarding copyright ownership. +REM The ASF licenses this file to You under the Apache License, Version 2.0 +REM (the "License"); you may not use this file except in compliance with +REM the License. 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 This test script will return an error exit code + +@echo FOO.%TEST_ENV_VAR%.%1 + +EXIT 1 diff --git a/ApacheCommonsExec/src/test/scripts/error.dcl b/ApacheCommonsExec/src/test/scripts/error.dcl new file mode 100644 index 0000000..061ad00 --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/error.dcl @@ -0,0 +1,25 @@ +$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +$! +$! Licensed to the Apache Software Foundation (ASF) under one or more +$! contributor license agreements. See the NOTICE file distributed with +$! this work for additional information regarding copyright ownership. +$! The ASF licenses this file to You 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. +$! +$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +$! +$! do something and return an error result code +$! +$ ENV_VAR=f$trnlnm("TEST_ENV_VAR") +$ write sys$output "FOO.''ENV_VAR'.''P1'" +$! +$ exit %x10000002 ! this is an Error, but does not print a message \ No newline at end of file diff --git a/ApacheCommonsExec/src/test/scripts/error.sh b/ApacheCommonsExec/src/test/scripts/error.sh new file mode 100644 index 0000000..8c498dd --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/error.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +# + +# do something and return en error result code + +echo FOO.$TEST_ENV_VAR.$1 +exit 1 diff --git a/ApacheCommonsExec/src/test/scripts/forever.bat b/ApacheCommonsExec/src/test/scripts/forever.bat new file mode 100644 index 0000000..7425f0b --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/forever.bat @@ -0,0 +1,27 @@ +@ECHO OFF + +REM Little batch file to run nearly foerver +REM see http://malektips.com/dos0017.html +REM +REM Licensed to the Apache Software Foundation (ASF) under one or more +REM contributor license agreements. See the NOTICE file distributed with +REM this work for additional information regarding copyright ownership. +REM The ASF licenses this file to You under the Apache License, Version 2.0 +REM (the "License"); you may not use this file except in compliance with +REM the License. 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 run an infinite loop so the script will never ever terminate on its behalf +REM and append a '.' after each second + +:LOOP + ECHO . >> .\target\forever.txt + @ping 127.0.0.1 -n 2 -w 1000 > nul +GOTO LOOP \ No newline at end of file diff --git a/ApacheCommonsExec/src/test/scripts/forever.dcl b/ApacheCommonsExec/src/test/scripts/forever.dcl new file mode 100644 index 0000000..452681f --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/forever.dcl @@ -0,0 +1,38 @@ +$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +$! +$! Licensed to the Apache Software Foundation (ASF) under one or more +$! contributor license agreements. See the NOTICE file distributed with +$! this work for additional information regarding copyright ownership. +$! The ASF licenses this file to You 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. +$! +$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +$! +$! run an infinite loop so the script will never ever terminate +$! +$! Suppress timeout warning +$ l_msg=f$environment("MESSAGE") +$ SET MESSAGE /NOFACILITY /NOIDENTIFICATION /NOSEVERITY /NOTEXT +$! +$ SET NOON +$ ON CONTROL_Y THEN GOTO DONE +$ close/nolog OUT +$ open/write OUT [.target]forever.txt ! create the output file +$LOOP: +$ write OUT "." +$ read /prompt="."/time_out=1 sys$command dummy +$ GOTO LOOP +$! +$DONE: +$ close/nolog OUT +$! Restore message settings +$ SET MESSAGE 'l_msg' \ No newline at end of file diff --git a/ApacheCommonsExec/src/test/scripts/forever.sh b/ApacheCommonsExec/src/test/scripts/forever.sh new file mode 100644 index 0000000..696d512 --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/forever.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# + +# run an infinite loop so the script will never ever terminate on its behalf +# and append a '.' after each second + +while test "notempty" +do + sleep 1 + echo '.\c' >> ./target/forever.txt +done \ No newline at end of file diff --git a/ApacheCommonsExec/src/test/scripts/invoker.sh b/ApacheCommonsExec/src/test/scripts/invoker.sh new file mode 100644 index 0000000..4eef894 --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/invoker.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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 "invoker.sh -- going to start daemon process" +cd ../../../target +nohup sleep 10 & +echo "invoker.sh -- daemon process was started" \ No newline at end of file diff --git a/ApacheCommonsExec/src/test/scripts/ping.bat b/ApacheCommonsExec/src/test/scripts/ping.bat new file mode 100644 index 0000000..2f0bb71 --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/ping.bat @@ -0,0 +1,24 @@ +@ECHO OFF + +REM Little batch file to run nearly foerver +REM see http://malektips.com/dos0017.html +REM +REM Licensed to the Apache Software Foundation (ASF) under one or more +REM contributor license agreements. See the NOTICE file distributed with +REM this work for additional information regarding copyright ownership. +REM The ASF licenses this file to You under the Apache License, Version 2.0 +REM (the "License"); you may not use this file except in compliance with +REM the License. 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 ping is started as subprocess which runs '%1' seconds + +echo "[ping.bat] Blocking for %1 seconds ..." +ping.exe -n %1 -w 1000 127.0.0.1 > nul \ No newline at end of file diff --git a/ApacheCommonsExec/src/test/scripts/ping.dcl b/ApacheCommonsExec/src/test/scripts/ping.dcl new file mode 100644 index 0000000..174024c --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/ping.dcl @@ -0,0 +1,23 @@ +$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +$! +$! Licensed to the Apache Software Foundation (ASF) under one or more +$! contributor license agreements. See the NOTICE file distributed with +$! this work for additional information regarding copyright ownership. +$! The ASF licenses this file to You 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. +$! +$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +$! +$! ping is started as subprocess which runs for 'P1' seconds +$! +$ write sys$output "[ping.dcl] Blocking for ''P1' seconds ..." +$ tcpip ping 127.0.0.1 /number_packets='P1 /wait=1 \ No newline at end of file diff --git a/ApacheCommonsExec/src/test/scripts/ping.sh b/ApacheCommonsExec/src/test/scripts/ping.sh new file mode 100644 index 0000000..84b5c61 --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/ping.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# + +# ping is started as subprocess which runs for '$1' seconds + +echo "[ping.sh] Blocking for $1 seconds ..." +# see EXEC-52 - option must appear after the hostname! +if test "$(uname -s)" = "HP-UX" +then + ping 127.0.0.1 -n $1 +else + ping -c $1 127.0.0.1 +fi diff --git a/ApacheCommonsExec/src/test/scripts/printargs.bat b/ApacheCommonsExec/src/test/scripts/printargs.bat new file mode 100644 index 0000000..721664d --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/printargs.bat @@ -0,0 +1,25 @@ +@ECHO OFF + +REM Licensed to the Apache Software Foundation (ASF) under one or more +REM contributor license agreements. See the NOTICE file distributed with +REM this work for additional information regarding copyright ownership. +REM The ASF licenses this file to You under the Apache License, Version 2.0 +REM (the "License"); you may not use this file except in compliance with +REM the License. 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 checking for emptiness was tricky - see http://www.robvanderwoude.com/parameters.php + +:Loop +IF [%1]==[] GOTO Continue + @ECHO "%1" +SHIFT +GOTO Loop +:Continue \ No newline at end of file diff --git a/ApacheCommonsExec/src/test/scripts/printargs.dcl b/ApacheCommonsExec/src/test/scripts/printargs.dcl new file mode 100644 index 0000000..9c94179 --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/printargs.dcl @@ -0,0 +1,30 @@ +$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +$! +$! Licensed to the Apache Software Foundation (ASF) under one or more +$! contributor license agreements. See the NOTICE file distributed with +$! this work for additional information regarding copyright ownership. +$! The ASF licenses this file to You 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. +$! +$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +$! +$! Print arguments +$! +$! Crude, but effective. Works even if argument contains un-doubled double-quotes +$ if f$length(P1) .gt. 0 then write sys$output P1 +$ if f$length(P2) .gt. 0 then write sys$output P2 +$ if f$length(P3) .gt. 0 then write sys$output P3 +$ if f$length(P4) .gt. 0 then write sys$output P4 +$ if f$length(P5) .gt. 0 then write sys$output P5 +$ if f$length(P6) .gt. 0 then write sys$output P6 +$ if f$length(P7) .gt. 0 then write sys$output P7 +$ if f$length(P8) .gt. 0 then write sys$output P8 \ No newline at end of file diff --git a/ApacheCommonsExec/src/test/scripts/printargs.sh b/ApacheCommonsExec/src/test/scripts/printargs.sh new file mode 100644 index 0000000..047e50e --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/printargs.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# + +# Helper script to print out the command line arguments + +while [ $# -gt 0 ] +do + echo "$1" + shift +done + diff --git a/ApacheCommonsExec/src/test/scripts/redirect.sh b/ApacheCommonsExec/src/test/scripts/redirect.sh new file mode 100644 index 0000000..dce5c99 --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/redirect.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# + +# read from stdin and output to stdout + +while read myline +do + echo "stdout: $myline" +done + +echo 1>&2 "stderr: Finished reading from stdin" + +exit 0 + diff --git a/ApacheCommonsExec/src/test/scripts/standalone.sh b/ApacheCommonsExec/src/test/scripts/standalone.sh new file mode 100644 index 0000000..eb68802 --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/standalone.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# + +mkdir target/ +cat pom.xml | gzip> ./target/mybackup.gz diff --git a/ApacheCommonsExec/src/test/scripts/stdin.bat b/ApacheCommonsExec/src/test/scripts/stdin.bat new file mode 100644 index 0000000..02518be --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/stdin.bat @@ -0,0 +1,19 @@ +@ECHO OFF + +REM Licensed to the Apache Software Foundation (ASF) under one or more +REM contributor license agreements. See the NOTICE file distributed with +REM this work for additional information regarding copyright ownership. +REM The ASF licenses this file to You under the Apache License, Version 2.0 +REM (the "License"); you may not use this file except in compliance with +REM the License. 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. + +set /p answer=What's your name? : +echo Hello %answer%! \ No newline at end of file diff --git a/ApacheCommonsExec/src/test/scripts/stdin.dcl b/ApacheCommonsExec/src/test/scripts/stdin.dcl new file mode 100644 index 0000000..14fb835 --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/stdin.dcl @@ -0,0 +1,23 @@ +$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +$! +$! Licensed to the Apache Software Foundation (ASF) under one or more +$! contributor license agreements. See the NOTICE file distributed with +$! this work for additional information regarding copyright ownership. +$! The ASF licenses this file to You 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. +$! +$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +$! +$! Read input and display it +$! +$ read /prompt="What's your name? : " sys$command answer +$ write sys$output "Hello ''answer'!" \ No newline at end of file diff --git a/ApacheCommonsExec/src/test/scripts/stdin.sh b/ApacheCommonsExec/src/test/scripts/stdin.sh new file mode 100644 index 0000000..5572c78 --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/stdin.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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 "What's your name? : " +read answer +echo "Hello $answer!" + diff --git a/ApacheCommonsExec/src/test/scripts/test.bat b/ApacheCommonsExec/src/test/scripts/test.bat new file mode 100644 index 0000000..ab67bc0 --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/test.bat @@ -0,0 +1,24 @@ +@ECHO OFF + +REM +REM Licensed to the Apache Software Foundation (ASF) under one or more +REM contributor license agreements. See the NOTICE file distributed with +REM this work for additional information regarding copyright ownership. +REM The ASF licenses this file to You under the Apache License, Version 2.0 +REM (the "License"); you may not use this file except in compliance with +REM the License. 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 print the given environment variable and command line parameter +REM since this is verified by the regression test + +@ECHO FOO.%TEST_ENV_VAR%.%1 diff --git a/ApacheCommonsExec/src/test/scripts/test.dcl b/ApacheCommonsExec/src/test/scripts/test.dcl new file mode 100644 index 0000000..2fe6d6a --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/test.dcl @@ -0,0 +1,25 @@ +$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +$! +$! Licensed to the Apache Software Foundation (ASF) under one or more +$! contributor license agreements. See the NOTICE file distributed with +$! this work for additional information regarding copyright ownership. +$! The ASF licenses this file to You 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. +$! +$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +$! +$! print the given environment variable and command line parameter +$! since this is verified by the regression test +$! +$ write sys$output "FOO.''TEST_ENV_VAR'.''P1'" +$! +$ exit 1 ! normal exit \ No newline at end of file diff --git a/ApacheCommonsExec/src/test/scripts/test.sh b/ApacheCommonsExec/src/test/scripts/test.sh new file mode 100644 index 0000000..83d9618 --- /dev/null +++ b/ApacheCommonsExec/src/test/scripts/test.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# + +# print the given environment variable and command line parameter +# since this is verified by the regression test + +echo FOO.$TEST_ENV_VAR.$1 diff --git a/ApacheCommonsExec/test4class.cld b/ApacheCommonsExec/test4class.cld new file mode 100644 index 0000000..7b0e036 --- /dev/null +++ b/ApacheCommonsExec/test4class.cld @@ -0,0 +1,1575 @@ + + + + + + + false + + + _stereo_type + Stereo Type + false + + + _simpleEntityName + Simple Name + false + + + _entityName + Name + false + + + _background + Background Color + false + + + _attrs + Attributes... + false + + + _operations + Operations... + false + + + _abstract + abstract + false + + + + org.apache.commons.exec.CommandLine + + -1 + -1 + 173 + 110 + + + + + + + arguments + Vector + false + + 255 + 255 + 206 + + + 0 + 0 + 0 + + true + + + + + + 2 + + + + + + + + executable + String + false + + + true + + + + + + 2 + + + + + + + + substitutionMap + Map + false + + + true + + + + + + 2 + + + + + + + + isFile + boolean + false + + + true + + + + + + 2 + + + + + + + + parse + CommandLine + + + line + String + + + false + true + + + true + + + + + + 2 + + + + + + + + parse + CommandLine + + + line + String + + + substitutionMap + Map + + + false + true + + + true + + + + + + 2 + + + + + + + + CommandLine + void + + + executable + String + + + false + false + + + true + + + + + + 2 + + + + + + + + CommandLine + void + + + executable + File + + + false + false + + + true + + + + + + 2 + + + + + + + + CommandLine + void + + + other + CommandLine + + + false + false + + + true + + + + + + 2 + + + + + + + + getExecutable + String + + false + false + + + true + + + + + + 2 + + + + + + + + isFile + boolean + + false + false + + + true + + + + + + 2 + + + + + + + + addArguments + CommandLine + + + arguments + String[] + + + false + false + + + true + + + + + + 2 + + + + + + + + addArguments + CommandLine + + + arguments + String[] + + + handleQuoting + boolean + + + false + false + + + true + + + + + + 2 + + + + + + + + addArguments + CommandLine + + + arguments + String + + + false + false + + + true + + + + + + 2 + + + + + + + + addArguments + CommandLine + + + arguments + String + + + handleQuoting + boolean + + + false + false + + + true + + + + + + 2 + + + + + + + + addArgument + CommandLine + + + argument + String + + + false + false + + + true + + + + + + 2 + + + + + + + + addArgument + CommandLine + + + argument + String + + + handleQuoting + boolean + + + false + false + + + true + + + + + + 2 + + + + + + + + getArguments + String[] + + false + false + + + true + + + + + + 2 + + + + + + + + getSubstitutionMap + Map + + false + false + + + true + + + + + + 2 + + + + + + + + setSubstitutionMap + void + + + substitutionMap + Map + + + false + false + + + true + + + + + + 2 + + + + + + + + toStrings + String[] + + false + false + + + true + + + + + + 2 + + + + + + + + toString + String + + false + false + + + true + + + + + + 2 + + + + + + + + expandArgument + String + + + argument + String + + + false + false + + + true + + + + + + 2 + + + + + + + + translateCommandline + String[] + + + toProcess + String + + + false + true + + + true + + + + + + 2 + + + + + + + + getExecutable + String + + + executable + String + + + false + false + + + true + + + + + + 2 + + + + + + + + + + true + + + + + + 2 + + + + + + + false + + + _stereo_type + Stereo Type + false + + + _simpleEntityName + Simple Name + false + + + _entityName + Name + false + + + _background + Background Color + false + + + _attrs + Attributes... + false + + + _operations + Operations... + false + + + _abstract + abstract + false + + + + org.apache.commons.exec.CommandLineTest + + -1 + -1 + 819 + 139 + + + + + + + assertEquals + void + + + expected + String[] + + + actual + String[] + + + false + false + + + true + + + + + + 2 + + + + + + + + testExecutable + void + + false + false + + + true + + + + + + 2 + + + + + + + + testExecutableZeroLengthString + void + + false + false + + + true + + + + + + 2 + + + + + + + + testExecutableWhitespaceString + void + + false + false + + + true + + + + + + 2 + + + + + + + + testNullExecutable + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArgument + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddNullArgument + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArgumentWithSpace + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArgumentWithQuote + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArgumentWithQuotesAround + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArgumentWithSingleQuote + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArgumentWithBothQuotes + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArguments + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArgumentsWithQuotes + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArgumentsWithQuotesAndSpaces + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArgumentsArray + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddArgumentsArrayNull + void + + false + false + + + true + + + + + + 2 + + + + + + + + testAddTwoArguments + void + + false + false + + + true + + + + + + 2 + + + + + + + + testParseCommandLine + void + + false + false + + + true + + + + + + 2 + + + + + + + + testParseCommandLineWithQuotes + void + + false + false + + + true + + + + + + 2 + + + + + + + + testParseCommandLineWithUnevenQuotes + void + + false + false + + + true + + + + + + 2 + + + + + + + + testParseCommandLineWithNull + void + + false + false + + + true + + + + + + 2 + + + + + + + + testParseCommandLineWithOnlyWhitespace + void + + false + false + + + true + + + + + + 2 + + + + + + + + testParseComplexCommandLine1 + void + + false + false + + + true + + + + + + 2 + + + + + + + + testParseComplexCommandLine2 + void + + false + false + + + true + + + + + + 2 + + + + + + + + testParseRealLifeCommandLine_1 + void + + false + false + + + true + + + + + + 2 + + + + + + + + testComplexAddArgument + void + + false + false + + + true + + + + + + 2 + + + + + + + + testComplexAddArguments1 + void + + false + false + + + true + + + + + + 2 + + + + + + + + testComplexAddArguments2 + void + + false + false + + + true + + + + + + 2 + + + + + + + + testCommandLineParsingWithExpansion1 + void + + false + false + + + true + + + + + + 2 + + + + + + + + testCommandLineParsingWithExpansion2 + void + + false + false + + + true + + + + + + 2 + + + + + + + + testCommandLineParsingWithExpansion3 + void + + false + false + + + true + + + + + + 2 + + + + + + + + testToString + void + + false + false + + + true + + + + + + 2 + + + + + + + + testToStringTroubleshooting + void + + false + false + + + true + + + + + + 2 + + + + + + + + _testExec36_1 + void + + false + false + + + true + + + + + + 2 + + + + + + + + _testExec36_2 + void + + false + false + + + true + + + + + + 2 + + + + + + + + _testExec36_3 + void + + false + false + + + true + + + + + + 2 + + + + + + + + testCopyConstructor + void + + false + false + + + true + + + + + + 2 + + + + + + + + + + true + + + + + + 2 + + + + + + + + + + true + + + + + 2 + + + + + \ No newline at end of file