/* * Copyright 2000-2005 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.apache.tools.ant.taskdefs; import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import org.apache.tools.ant.AntClassLoader; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.ProjectComponent; import org.apache.tools.ant.Task; import org.apache.tools.ant.taskdefs.condition.Os; 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.types.Permissions; import org.apache.tools.ant.util.JavaEnvUtils; import org.apache.tools.ant.util.TimeoutObserver; import org.apache.tools.ant.util.Watchdog; /** * * @since Ant 1.2 */ public class ExecuteJava implements Runnable, TimeoutObserver { private Commandline javaCommand = null; private Path classpath = null; private CommandlineJava.SysProperties sysProperties = null; private Permissions perm = 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; } /** * Permissions for the application run. * @since Ant 1.6 * @param permissions */ public void setPermissions(Permissions permissions) { perm = permissions; } /** * 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 ((main.getModifiers() & Modifier.STATIC) == 0) { throw new BuildException("main() method in " + classname + " is not declared static"); } 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 timeout, 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 (BuildException e) { throw e; } catch (SecurityException e) { throw e; } catch (ThreadDeath e) { throw e; } catch (Throwable e) { throw new BuildException(e); } finally { if (loader != null) { loader.resetThreadContextLoader(); loader.cleanup(); loader = null; } if (sysProperties != null) { sysProperties.restoreSystem(); } } } /** * @since Ant 1.5 */ public void run() { final Object[] argument = {javaCommand.getArguments()}; try { if (perm != null) { perm.setSecurityManager(); } 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 { if (perm != null) { perm.restoreSecurityManager(); } 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 synchronized boolean killedProcess() { return timedOut; } /** * Runs the Java command in a separate VM, this does not give you * the full flexibility of the Java task, but may be enough for * simple needs. * * @since Ant 1.6.3 */ public int fork(ProjectComponent pc) throws BuildException { CommandlineJava cmdl = new CommandlineJava(); cmdl.setClassname(javaCommand.getExecutable()); String[] args = javaCommand.getArguments(); for (int i = 0; i < args.length; i++) { cmdl.createArgument().setValue(args[i]); } if (classpath != null) { cmdl.createClasspath(pc.getProject()).append(classpath); } if (sysProperties != null) { cmdl.addSysproperties(sysProperties); } Redirector redirector = new Redirector(pc); Execute exe = new Execute(redirector.createHandler(), timeout == null ? null : new ExecuteWatchdog(timeout.longValue())); exe.setAntRun(pc.getProject()); exe.setCommandline(cmdl.getCommandline()); try { int rc = exe.execute(); redirector.complete(); timedOut = exe.killedProcess(); return rc; } catch (IOException e) { throw new BuildException(e); } } }