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) {}} | |||
} | |||
} | |||
} |