diff --git a/WHATSNEW b/WHATSNEW index f4755661d..baf403c75 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -530,6 +530,9 @@ Other changes: * will now have a new attribute spawn (default false). If set to true, the process will be spawned. Bugzilla Report 5907. +* will now have a new attribute spawn (default false). +If set to true, the process will be spawned. Bugzilla Report 5907. + * now supports a timeout which can be used to recover from deadlocks, etc in the parallel threads. also now supports a nested element. This can be used to diff --git a/docs/manual/CoreTasks/java.html b/docs/manual/CoreTasks/java.html index f0d022268..457757aba 100644 --- a/docs/manual/CoreTasks/java.html +++ b/docs/manual/CoreTasks/java.html @@ -56,6 +56,14 @@ JVM. (disabled by default) No + + spawn + if enabled allows to start a process which will outlive ant.
+ Requires fork=true, and not compatible + with timeout, input, output, error, result attributes.
+ (disabled by default) + No + jvm the command used to invoke the Java Virtual Machine, diff --git a/src/etc/testcases/taskdefs/java.xml b/src/etc/testcases/taskdefs/java.xml index c920e36c0..0e5defdf0 100644 --- a/src/etc/testcases/taskdefs/java.xml +++ b/src/etc/testcases/taskdefs/java.xml @@ -2,41 +2,44 @@ - - - + + + - + - - - + + + - + - - + + - + - @@ -88,7 +91,7 @@ fork="true"> - + - + - + + + + + + + + diff --git a/src/main/org/apache/tools/ant/taskdefs/Java.java b/src/main/org/apache/tools/ant/taskdefs/Java.java index 86017432f..0bba65b9d 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Java.java +++ b/src/main/org/apache/tools/ant/taskdefs/Java.java @@ -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. diff --git a/src/testcases/org/apache/tools/ant/taskdefs/JavaTest.java b/src/testcases/org/apache/tools/ant/taskdefs/JavaTest.java index 8038222f3..b72baa90a 100644 --- a/src/testcases/org/apache/tools/ant/taskdefs/JavaTest.java +++ b/src/testcases/org/apache/tools/ant/taskdefs/JavaTest.java @@ -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 Donal Quinlan * */ 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) {}} + + } + } }