/* * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2003 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 "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 * . */ package org.apache.tools.ant.taskdefs; import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.apache.tools.ant.AntClassLoader; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; 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; /** * * @author thomas.haas@softwired-inc.com * @author Stefan Bodewig * @since Ant 1.2 */ 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; } /** * Set the classpath to be used when running the Java class * * @param p an Ant Path object containing the classpath. */ public void setClasspath(Path p) { classpath = p; } public void setSystemProperties(CommandlineJava.SysProperties s) { sysProperties = s; } /** * All output (System.out as well as System.err) will be written * to this Stream. * * @deprecated manage output at the task level */ public void setOutput(PrintStream out) { } /** * @since Ant 1.5 */ public void setTimeout(Long timeout) { this.timeout = timeout; } public void execute(Project project) throws BuildException { final String classname = javaCommand.getExecutable(); AntClassLoader loader = null; try { if (sysProperties != null) { sysProperties.setSystem(); } final Class[] param = {Class.forName("[Ljava.lang.String;")}; Class target = null; if (classpath == null) { target = Class.forName(classname); } else { loader = project.createClassLoader(classpath); loader.setParent(project.getCoreLoader()); loader.setParentFirst(false); loader.addJavaLibraries(); loader.setIsolated(true); loader.setThreadContextLoader(); loader.forceLoadClass(classname); target = Class.forName(classname, true, loader); } main = target.getMethod("main", param); if (main == null) { throw new BuildException("Could not find main() method in " + classname); } if (timeout == null) { run(); } else { thread = new Thread(this, "ExecuteJava"); Task currentThreadTask = project.getThreadTask(Thread.currentThread()); project.registerThreadTask(thread, currentThreadTask); // if we run into a timout, the run-away thread shall not // make the VM run forever - if no timeout occurs, Ant's // main thread will still be there to let the new thread // finish thread.setDaemon(true); Watchdog w = new Watchdog(timeout.longValue()); w.addTimeoutObserver(this); synchronized (this) { thread.start(); w.start(); try { wait(); } catch (InterruptedException e) { // ignore } if (timedOut) { project.log("Timeout: sub-process interrupted", Project.MSG_WARN); } else { thread = null; w.stop(); } } } if (caught != null) { throw caught; } } catch (ClassNotFoundException e) { throw new BuildException("Could not find " + classname + "." + " Make sure you have it in your" + " classpath"); } catch (SecurityException e) { throw e; } catch (Throwable e) { throw new BuildException(e); } finally { if (loader != null) { loader.resetThreadContextLoader(); loader.cleanup(); } if (sysProperties != null) { sysProperties.restoreSystem(); } } } /** * @since 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 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; } }