PR: 5907 git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274992 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -530,6 +530,9 @@ Other changes: | |||
| * <exec> will now have a new attribute spawn (default false). | |||
| If set to true, the process will be spawned. Bugzilla Report 5907. | |||
| * <java> will now have a new attribute spawn (default false). | |||
| If set to true, the process will be spawned. Bugzilla Report 5907. | |||
| * <parallel> now supports a timeout which can be used to recover | |||
| from deadlocks, etc in the parallel threads. <parallel> also | |||
| now supports a <daemons> nested element. This can be used to | |||
| @@ -56,6 +56,14 @@ JVM. | |||
| (disabled by default)</td> | |||
| <td align="center" valign="top">No</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">spawn</td> | |||
| <td valign="top">if enabled allows to start a process which will outlive ant.<br/> | |||
| Requires fork=true, and not compatible | |||
| with timeout, input, output, error, result attributes.<br/> | |||
| (disabled by default)</td> | |||
| <td align="center" valign="top">No</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">jvm</td> | |||
| <td valign="top">the command used to invoke the Java Virtual Machine, | |||
| @@ -2,41 +2,44 @@ | |||
| <project name="java-test" basedir="." default="foo"> | |||
| <property name="app" | |||
| <property name="app" | |||
| value="org.apache.tools.ant.taskdefs.JavaTest$$EntryPoint" /> | |||
| <property name="app2" | |||
| <property name="app2" | |||
| value="org.apache.tools.ant.taskdefs.JavaTest$$ExceptingEntryPoint" /> | |||
| <property name="spawnapp" | |||
| value="org.apache.tools.ant.taskdefs.JavaTest$$SpawnEntryPoint" /> | |||
| <path id="test.classpath"> | |||
| <pathelement location="${build.tests}"/> | |||
| </path> | |||
| <target name="testNoJarNoClassname"> | |||
| <java/> | |||
| </target> | |||
| <target name="testJarNoFork"> | |||
| <java jar="test.jar" fork="false"/> | |||
| </target> | |||
| </target> | |||
| <target name="testJarAndClassName"> | |||
| <java jar="test.jar" classname="${app}" /> | |||
| </target> | |||
| <target name="testClassnameAndJar"> | |||
| <java classname="${app}" jar="test.jar" /> | |||
| </target> | |||
| </target> | |||
| <target name="testRun"> | |||
| <fail unless="tests-classpath.value" /> | |||
| <fail unless="tests-classpath.value" /> | |||
| <java classname="${app}" | |||
| classpath="${tests-classpath.value}"/> | |||
| </target> | |||
| <target name="testRunFail"> | |||
| <java classname="${app}" | |||
| <java classname="${app}" | |||
| classpath="${tests-classpath.value}" | |||
| > | |||
| <arg value="-1"/> | |||
| @@ -88,7 +91,7 @@ | |||
| fork="true"> | |||
| </java> | |||
| </target> | |||
| <target name="testResultPropertyZero"> | |||
| <java classname="${app}" | |||
| classpath="${tests-classpath.value}" | |||
| @@ -97,7 +100,7 @@ | |||
| </java> | |||
| <echo message="exitcode = ${exitcode}"/> | |||
| </target> | |||
| <target name="testResultPropertyNonZero"> | |||
| <java classname="${app}" | |||
| classpath="${tests-classpath.value}" | |||
| @@ -109,6 +112,13 @@ | |||
| </java> | |||
| <echo message="exitcode = ${exitcode}"/> | |||
| </target> | |||
| <target name="testSpawn"> | |||
| <java classname="${spawnapp}" fork="true" spawn="true" classpath="${tests-classpath.value}"> | |||
| <arg value="${timeToWait}"/> | |||
| <arg value="${logFile}" /> | |||
| </java> | |||
| </target> | |||
| <target name="foo" /> | |||
| </project> | |||
| @@ -94,6 +94,8 @@ public class Java extends Task { | |||
| private Long timeout = null; | |||
| private Redirector redirector = new Redirector(this); | |||
| private String resultProperty; | |||
| private boolean spawn = false; | |||
| private boolean incompatibleWithSpawn = false; | |||
| /** | |||
| * Do the execution. | |||
| * @throws BuildException if failOnError is set to true and the application | |||
| @@ -136,7 +138,17 @@ public class Java extends Task { | |||
| throw new BuildException("Cannot execute a jar in non-forked mode." | |||
| + " Please set fork='true'. "); | |||
| } | |||
| if (spawn && !fork) { | |||
| throw new BuildException("Cannot spawn a java process in non-forked mode." | |||
| + " Please set fork='true'. "); | |||
| } | |||
| if (spawn && incompatibleWithSpawn) { | |||
| getProject().log("spawn does not allow attributes related to input, " | |||
| + "output, error, result", Project.MSG_ERR); | |||
| getProject().log("spawn does not also not allow timeout", Project.MSG_ERR); | |||
| throw new BuildException("You have used an attribute which is " | |||
| + "not compatible with spawn"); | |||
| } | |||
| if (fork) { | |||
| log(cmdl.describeCommand(), Project.MSG_VERBOSE); | |||
| } else { | |||
| @@ -165,7 +177,12 @@ public class Java extends Task { | |||
| try { | |||
| if (fork) { | |||
| return run(cmdl.getCommandline()); | |||
| if (!spawn) { | |||
| return run(cmdl.getCommandline()); | |||
| } else { | |||
| spawn(cmdl.getCommandline()); | |||
| return 0; | |||
| } | |||
| } else { | |||
| try { | |||
| run(cmdl); | |||
| @@ -191,6 +208,16 @@ public class Java extends Task { | |||
| } | |||
| } | |||
| /** | |||
| * set whether or not you want the process to be spawned | |||
| * default is not spawned | |||
| * @param spawn if true you do not want ant to wait for the end of the process | |||
| * @since ant 1.6 | |||
| */ | |||
| public void setSpawn(boolean spawn) { | |||
| this.spawn = spawn; | |||
| } | |||
| /** | |||
| * Set the classpath to be used when running the Java class | |||
| * | |||
| @@ -373,6 +400,7 @@ public class Java extends Task { | |||
| */ | |||
| public void setFailonerror(boolean fail) { | |||
| failOnError = fail; | |||
| incompatibleWithSpawn = true; | |||
| } | |||
| /** | |||
| @@ -392,6 +420,7 @@ public class Java extends Task { | |||
| */ | |||
| public void setOutput(File out) { | |||
| redirector.setOutput(out); | |||
| incompatibleWithSpawn = true; | |||
| } | |||
| /** | |||
| @@ -401,6 +430,7 @@ public class Java extends Task { | |||
| */ | |||
| public void setInput(File input) { | |||
| redirector.setInput(input); | |||
| incompatibleWithSpawn = true; | |||
| } | |||
| /** | |||
| @@ -410,6 +440,7 @@ public class Java extends Task { | |||
| */ | |||
| public void setInputString(String inputString) { | |||
| redirector.setInputString(inputString); | |||
| incompatibleWithSpawn = true; | |||
| } | |||
| /** | |||
| @@ -422,6 +453,7 @@ public class Java extends Task { | |||
| */ | |||
| public void setLogError(boolean logError) { | |||
| redirector.setLogError(logError); | |||
| incompatibleWithSpawn = true; | |||
| } | |||
| /** | |||
| @@ -433,6 +465,7 @@ public class Java extends Task { | |||
| */ | |||
| public void setError(File error) { | |||
| redirector.setError(error); | |||
| incompatibleWithSpawn = true; | |||
| } | |||
| /** | |||
| @@ -444,6 +477,7 @@ public class Java extends Task { | |||
| */ | |||
| public void setOutputproperty(String outputProp) { | |||
| redirector.setOutputProperty(outputProp); | |||
| incompatibleWithSpawn = true; | |||
| } | |||
| /** | |||
| @@ -456,6 +490,7 @@ public class Java extends Task { | |||
| */ | |||
| public void setErrorProperty(String errorProperty) { | |||
| redirector.setErrorProperty(errorProperty); | |||
| incompatibleWithSpawn = true; | |||
| } | |||
| /** | |||
| @@ -510,6 +545,7 @@ public class Java extends Task { | |||
| */ | |||
| public void setAppend(boolean append) { | |||
| this.append = append; | |||
| incompatibleWithSpawn = true; | |||
| } | |||
| /** | |||
| @@ -521,6 +557,7 @@ public class Java extends Task { | |||
| */ | |||
| public void setTimeout(Long value) { | |||
| timeout = value; | |||
| incompatibleWithSpawn = true; | |||
| } | |||
| /** | |||
| @@ -665,6 +702,42 @@ public class Java extends Task { | |||
| } | |||
| } | |||
| /** | |||
| * Executes the given classname with the given arguments in a separate VM. | |||
| */ | |||
| private void spawn(String[] command) throws BuildException { | |||
| Execute exe | |||
| = new Execute(); | |||
| exe.setAntRun(getProject()); | |||
| if (dir == null) { | |||
| dir = getProject().getBaseDir(); | |||
| } else if (!dir.exists() || !dir.isDirectory()) { | |||
| throw new BuildException(dir.getAbsolutePath() | |||
| + " is not a valid directory", | |||
| getLocation()); | |||
| } | |||
| exe.setWorkingDirectory(dir); | |||
| String[] environment = env.getVariables(); | |||
| if (environment != null) { | |||
| for (int i = 0; i < environment.length; i++) { | |||
| log("Setting environment variable: " + environment[i], | |||
| Project.MSG_VERBOSE); | |||
| } | |||
| } | |||
| exe.setNewenvironment(newEnvironment); | |||
| exe.setEnvironment(environment); | |||
| exe.setCommandline(command); | |||
| try { | |||
| exe.spawn(); | |||
| } catch (IOException e) { | |||
| throw new BuildException(e, getLocation()); | |||
| } | |||
| } | |||
| /** | |||
| * Executes the given classname with the given arguments as it | |||
| * was a command line application. | |||
| @@ -57,6 +57,7 @@ package org.apache.tools.ant.taskdefs; | |||
| import junit.framework.*; | |||
| import java.io.*; | |||
| import org.apache.tools.ant.*; | |||
| import org.apache.tools.ant.util.FileUtils; | |||
| /** | |||
| * stress out java task | |||
| @@ -65,7 +66,8 @@ import org.apache.tools.ant.*; | |||
| * @author <a href="mailto:donal@savvion.com">Donal Quinlan</a> | |||
| * */ | |||
| public class JavaTest extends BuildFileTest { | |||
| private static final int TIME_TO_WAIT = 4; | |||
| private boolean runFatalTests=false; | |||
| public JavaTest(String name) { | |||
| @@ -176,7 +178,23 @@ public class JavaTest extends BuildFileTest { | |||
| executeTarget("testResultPropertyNonZero"); | |||
| assertEquals("-1",project.getProperty("exitcode")); | |||
| } | |||
| public void testSpawn() { | |||
| FileUtils fileutils = FileUtils.newFileUtils(); | |||
| File logFile = fileutils.createTempFile("spawn","log", project.getBaseDir()); | |||
| // this is guaranteed by FileUtils#createTempFile | |||
| assertTrue("log file not existing", !logFile.exists()); | |||
| project.setProperty("logFile", logFile.getAbsolutePath()); | |||
| project.setProperty("timeToWait", Long.toString(TIME_TO_WAIT)); | |||
| project.executeTarget("testSpawn"); | |||
| try { | |||
| Thread.sleep(TIME_TO_WAIT * 1000 + 400); | |||
| } catch (Exception ex) { | |||
| System.out.println("my sleep was interrupted"); | |||
| } | |||
| assertTrue("log file exists", logFile.exists()); | |||
| } | |||
| /** | |||
| * entry point class with no dependencies other | |||
| * than normal JRE runtime | |||
| @@ -225,4 +243,36 @@ public class JavaTest extends BuildFileTest { | |||
| throw new NullPointerException("Exception raised inside called program"); | |||
| } | |||
| } | |||
| /** | |||
| * test class for spawn | |||
| */ | |||
| public static class SpawnEntryPoint { | |||
| public static void main(String [] argv) { | |||
| int sleepTime = 10; | |||
| String logFile = "spawn.log"; | |||
| if (argv.length >= 1) { | |||
| sleepTime = Integer.parseInt(argv[0]); | |||
| } | |||
| if (argv.length >= 2) | |||
| { | |||
| logFile = argv[1]; | |||
| } | |||
| OutputStreamWriter out = null; | |||
| try { | |||
| Thread.sleep(sleepTime * 1000); | |||
| } catch (InterruptedException ex) { | |||
| System.out.println("my sleep was interrupted"); | |||
| } | |||
| try { | |||
| File dest = new File(logFile); | |||
| FileOutputStream fos = new FileOutputStream(dest); | |||
| out = new OutputStreamWriter(fos); | |||
| out.write("bye bye\n"); | |||
| } catch (Exception ex) {} | |||
| finally { | |||
| try {out.close();} catch (IOException ioe) {}} | |||
| } | |||
| } | |||
| } | |||