diff --git a/src/main/org/apache/tools/ant/taskdefs/ExecTask.java b/src/main/org/apache/tools/ant/taskdefs/ExecTask.java
index 4d90045b5..d949de471 100644
--- a/src/main/org/apache/tools/ant/taskdefs/ExecTask.java
+++ b/src/main/org/apache/tools/ant/taskdefs/ExecTask.java
@@ -88,7 +88,7 @@ public class ExecTask extends Task {
private File dir;
protected boolean failOnError = false;
protected boolean newEnvironment = false;
- private Integer timeout = null;
+ private Long timeout = null;
private Environment env = new Environment();
protected Commandline cmdl = new Commandline();
private FileOutputStream fos = null;
@@ -104,7 +104,7 @@ public class ExecTask extends Task {
/**
* Timeout in milliseconds after which the process will be killed.
*/
- public void setTimeout(Integer value) {
+ public void setTimeout(Long value) {
timeout = value;
}
@@ -377,7 +377,7 @@ public class ExecTask extends Task {
if (timeout == null) {
return null;
}
- return new ExecuteWatchdog(timeout.intValue());
+ return new ExecuteWatchdog(timeout.longValue());
}
/**
diff --git a/src/main/org/apache/tools/ant/taskdefs/ExecuteJava.java b/src/main/org/apache/tools/ant/taskdefs/ExecuteJava.java
index e2e1bae0e..50bbf4e1a 100644
--- a/src/main/org/apache/tools/ant/taskdefs/ExecuteJava.java
+++ b/src/main/org/apache/tools/ant/taskdefs/ExecuteJava.java
@@ -1,7 +1,7 @@
/*
* The Apache Software License, Version 1.1
*
- * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
+ * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -62,21 +62,28 @@ import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.Commandline;
import org.apache.tools.ant.types.CommandlineJava;
import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.TimeoutObserver;
+import org.apache.tools.ant.util.Watchdog;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.io.PrintStream;
-/*
+/**
*
* @author thomas.haas@softwired-inc.com
* @author Stefan Bodewig
*/
-public class ExecuteJava {
+public class ExecuteJava implements Runnable, TimeoutObserver {
private Commandline javaCommand = null;
private Path classpath = null;
private CommandlineJava.SysProperties sysProperties = null;
+ private Method main = null;
+ private Long timeout = null;
+ private Throwable caught = null;
+ private boolean timedOut = false;
+ private Thread thread = null;
public void setJavaCommand(Commandline javaCommand) {
this.javaCommand = javaCommand;
@@ -99,9 +106,15 @@ public class ExecuteJava {
public void setOutput(PrintStream out) {
}
+ /**
+ * @since 1.19, Ant 1.5
+ */
+ public void setTimeout(Long timeout) {
+ this.timeout = timeout;
+ }
+
public void execute(Project project) throws BuildException{
final String classname = javaCommand.getExecutable();
- final Object[] argument = { javaCommand.getArguments() };
AntClassLoader loader = null;
try {
@@ -120,21 +133,41 @@ public class ExecuteJava {
target = loader.forceLoadClass(classname);
AntClassLoader.initializeClass(target);
}
- final Method main = target.getMethod("main", param);
- main.invoke(null, argument);
+ main = target.getMethod("main", param);
+
+ if (timeout == null) {
+ run();
+ } else {
+ thread = new Thread(this, "ExecuteJava");
+ Watchdog w = new Watchdog(timeout.longValue());
+ w.addTimeoutObserver(this);
+ synchronized (this) {
+ thread.start();
+ w.start();
+ try {
+ wait();
+ } catch (InterruptedException e) {}
+ if (timedOut) {
+ project.log("Timeout: killed the sub-process",
+ Project.MSG_WARN);
+ } else {
+ thread = null;
+ w.stop();
+ }
+ }
+ }
+
+ if (caught != null) {
+ throw caught;
+ }
+
} catch (NullPointerException e) {
throw new BuildException("Could not find main() method in " + classname);
} catch (ClassNotFoundException e) {
throw new BuildException("Could not find " + classname + ". Make sure you have it in your classpath");
- } catch (InvocationTargetException e) {
- Throwable t = e.getTargetException();
- if (!(t instanceof SecurityException)) {
- throw new BuildException(t);
- }
- else {
- throw (SecurityException)t;
- }
- } catch (Exception e) {
+ } catch (SecurityException e) {
+ throw e;
+ } catch (Throwable e) {
throw new BuildException(e);
} finally {
if (loader != null) {
@@ -146,4 +179,43 @@ public class ExecuteJava {
}
}
}
+
+ /**
+ * @since 1.19, Ant 1.5
+ */
+ public void run() {
+ final Object[] argument = { javaCommand.getArguments() };
+ try {
+ main.invoke(null, argument);
+ } catch (InvocationTargetException e) {
+ Throwable t = e.getTargetException();
+ if (!(t instanceof InterruptedException)) {
+ caught = t;
+ } /* else { swallow, probably due to timeout } */
+ } catch (Throwable t) {
+ caught = t;
+ } finally {
+ synchronized (this) {
+ notifyAll();
+ }
+ }
+ }
+
+ /**
+ * @since 1.19, Ant 1.5
+ */
+ public synchronized void timeoutOccured(Watchdog w) {
+ if (thread != null) {
+ timedOut = true;
+ thread.interrupt();
+ }
+ notifyAll();
+ }
+
+ /**
+ * @since 1.19, Ant 1.5
+ */
+ public boolean killedProcess() {
+ return timedOut;
+ }
}
diff --git a/src/main/org/apache/tools/ant/taskdefs/ExecuteWatchdog.java b/src/main/org/apache/tools/ant/taskdefs/ExecuteWatchdog.java
index 3bd15c946..c49971464 100644
--- a/src/main/org/apache/tools/ant/taskdefs/ExecuteWatchdog.java
+++ b/src/main/org/apache/tools/ant/taskdefs/ExecuteWatchdog.java
@@ -98,7 +98,7 @@ public class ExecuteWatchdog implements TimeoutObserver {
*
* @param timeout the timeout for the process in milliseconds. It must be greather than 0.
*/
- public ExecuteWatchdog(int timeout) {
+ public ExecuteWatchdog(long timeout) {
watchdog = new Watchdog(timeout);
watchdog.addTimeoutObserver(this);
}
diff --git a/src/main/org/apache/tools/ant/taskdefs/Java.java b/src/main/org/apache/tools/ant/taskdefs/Java.java
index 6c2cd0d44..2bd2bb4d5 100644
--- a/src/main/org/apache/tools/ant/taskdefs/Java.java
+++ b/src/main/org/apache/tools/ant/taskdefs/Java.java
@@ -91,6 +91,7 @@ public class Java extends Task {
private PrintStream outStream = null;
private boolean failOnError = false;
private boolean append = false;
+ private Long timeout = null;
/**
* Do the execution.
@@ -309,6 +310,15 @@ public class Java extends Task {
this.append = append;
}
+ /**
+ * Timeout in milliseconds after which the process will be killed.
+ *
+ * @since 1.37, Ant 1.5
+ */
+ public void setTimeout(Long value) {
+ timeout = value;
+ }
+
protected void handleOutput(String line) {
if (outStream != null) {
outStream.println(line);
@@ -336,6 +346,7 @@ public class Java extends Task {
exe.setJavaCommand(command.getJavaCommand());
exe.setClasspath(command.getClasspath());
exe.setSystemProperties(command.getSystemProperties());
+ exe.setTimeout(timeout);
if (out != null) {
try {
outStream =
@@ -366,10 +377,11 @@ public class Java extends Task {
if (out == null) {
exe = new Execute(new LogStreamHandler(this, Project.MSG_INFO,
Project.MSG_WARN),
- null);
+ createWatchdog());
} else {
fos = new FileOutputStream(out.getAbsolutePath(), append);
- exe = new Execute(new PumpStreamHandler(fos), null);
+ exe = new Execute(new PumpStreamHandler(fos),
+ createWatchdog());
}
exe.setAntRun(project);
@@ -395,7 +407,11 @@ public class Java extends Task {
exe.setCommandline(command);
try {
- return exe.execute();
+ int rc = exe.execute();
+ if(exe.killedProcess()) {
+ log("Timeout: killed the sub-process",Project.MSG_WARN);
+ }
+ return rc;
} catch (IOException e) {
throw new BuildException(e, location);
}
@@ -427,4 +443,17 @@ public class Java extends Task {
public void clearArgs() {
cmdl.clearJavaArgs();
}
+
+ /**
+ * Create the Watchdog to kill a runaway process.
+ *
+ * @since 1.37, Ant 1.5
+ */
+ protected ExecuteWatchdog createWatchdog() throws BuildException {
+ if (timeout == null) {
+ return null;
+ }
+ return new ExecuteWatchdog(timeout.longValue());
+ }
+
}
diff --git a/src/main/org/apache/tools/ant/util/TimeoutObserver.java b/src/main/org/apache/tools/ant/util/TimeoutObserver.java
index 09551c5c2..dd38b8202 100644
--- a/src/main/org/apache/tools/ant/util/TimeoutObserver.java
+++ b/src/main/org/apache/tools/ant/util/TimeoutObserver.java
@@ -57,7 +57,7 @@ package org.apache.tools.ant.util;
/**
* Interface for classes that want to be notified by Watchdog.
*
- * @since 1.5
+ * @since Ant 1.5
*
* @see org.apache.tools.ant.util.Watchdog
*
diff --git a/src/main/org/apache/tools/ant/util/Watchdog.java b/src/main/org/apache/tools/ant/util/Watchdog.java
index fcafc446b..358fa2589 100644
--- a/src/main/org/apache/tools/ant/util/Watchdog.java
+++ b/src/main/org/apache/tools/ant/util/Watchdog.java
@@ -113,7 +113,7 @@ public class Watchdog implements Runnable {
long now;
while (!stopped && until > (now = System.currentTimeMillis())) {
try {
- wait(until - now);
+ wait(until - now);
} catch (InterruptedException e) {}
}
if (!stopped) {
diff --git a/src/testcases/org/apache/tools/ant/taskdefs/ExecuteJavaTest.java b/src/testcases/org/apache/tools/ant/taskdefs/ExecuteJavaTest.java
new file mode 100644
index 000000000..80ec943b6
--- /dev/null
+++ b/src/testcases/org/apache/tools/ant/taskdefs/ExecuteJavaTest.java
@@ -0,0 +1,148 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2002 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ *
Used to be an inner class of ExecuteWatchdogTest. + * + * @author Stephane Bailliez + */ +public class TimeProcess { + public static void main(String[] args) throws Exception { + int time = Integer.parseInt(args[0]); + if (time < 1) { + throw new IllegalArgumentException("Invalid time: " + time); + } + Thread.sleep(time); + } +}