git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@277571 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -1,5 +1,5 @@ | |||
| /* | |||
| * Copyright 2000-2004 The Apache Software Foundation | |||
| * 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. | |||
| @@ -15,9 +15,10 @@ | |||
| * | |||
| */ | |||
| 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; | |||
| @@ -25,11 +26,14 @@ 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; | |||
| @@ -226,4 +230,76 @@ public class ExecuteJava implements Runnable, TimeoutObserver { | |||
| 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()); | |||
| if (Os.isFamily("openvms")) { | |||
| setupCommandLineForVMS(exe, cmdl.getCommandline()); | |||
| } else { | |||
| exe.setCommandline(cmdl.getCommandline()); | |||
| } | |||
| try { | |||
| int rc = exe.execute(); | |||
| redirector.complete(); | |||
| timedOut = exe.killedProcess(); | |||
| return rc; | |||
| } catch (IOException e) { | |||
| throw new BuildException(e); | |||
| } | |||
| } | |||
| /** | |||
| * On VMS platform, we need to create a special java options file | |||
| * containing the arguments and classpath for the java command. | |||
| * The special file is supported by the "-V" switch on the VMS JVM. | |||
| * | |||
| * @param exe | |||
| * @param command | |||
| */ | |||
| public static void setupCommandLineForVMS(Execute exe, String[] command) { | |||
| //Use the VM launcher instead of shell launcher on VMS | |||
| exe.setVMLauncher(true); | |||
| File vmsJavaOptionFile = null; | |||
| try { | |||
| String [] args = new String[command.length - 1]; | |||
| System.arraycopy(command, 1, args, 0, command.length - 1); | |||
| vmsJavaOptionFile = JavaEnvUtils.createVmsJavaOptionFile(args); | |||
| //we mark the file to be deleted on exit. | |||
| //the alternative would be to cache the filename and delete | |||
| //after execution finished, which is much better for long-lived runtimes | |||
| //though spawning complicates things... | |||
| vmsJavaOptionFile.deleteOnExit(); | |||
| String [] vmsCmd = {command[0], "-V", vmsJavaOptionFile.getPath()}; | |||
| exe.setCommandline(vmsCmd); | |||
| } catch (IOException e) { | |||
| throw new BuildException("Failed to create a temporary file for \"-V\" switch"); | |||
| } | |||
| } | |||
| } | |||
| @@ -840,23 +840,7 @@ public class Java extends Task { | |||
| * @param command | |||
| */ | |||
| private void setupCommandLineForVMS(Execute exe, String[] command) { | |||
| //Use the VM launcher instead of shell launcher on VMS | |||
| exe.setVMLauncher(true); | |||
| File vmsJavaOptionFile = null; | |||
| try { | |||
| String [] args = new String[command.length - 1]; | |||
| System.arraycopy(command, 1, args, 0, command.length - 1); | |||
| vmsJavaOptionFile = JavaEnvUtils.createVmsJavaOptionFile(args); | |||
| //we mark the file to be deleted on exit. | |||
| //the alternative would be to cache the filename and delete | |||
| //after execution finished, which is much better for long-lived runtimes | |||
| //though spawning complicates things... | |||
| vmsJavaOptionFile.deleteOnExit(); | |||
| String [] vmsCmd = {command[0], "-V", vmsJavaOptionFile.getPath()}; | |||
| exe.setCommandline(vmsCmd); | |||
| } catch (IOException e) { | |||
| throw new BuildException("Failed to create a temporary file for \"-V\" switch"); | |||
| } | |||
| ExecuteJava.setupCommandLineForVMS(exe, command); | |||
| } | |||
| /** | |||
| @@ -1,5 +1,5 @@ | |||
| /* | |||
| * Copyright 2000-2004 The Apache Software Foundation | |||
| * 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. | |||
| @@ -21,6 +21,7 @@ import java.io.ByteArrayOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.OutputStream; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.ProjectComponent; | |||
| import org.apache.tools.ant.Task; | |||
| @@ -48,7 +49,7 @@ public class LogOutputStream extends OutputStream { | |||
| = new ByteArrayOutputStream(INTIAL_SIZE); | |||
| private boolean skip = false; | |||
| private Task task; | |||
| private ProjectComponent pc; | |||
| private int level = Project.MSG_INFO; | |||
| /** | |||
| @@ -58,7 +59,18 @@ public class LogOutputStream extends OutputStream { | |||
| * @param level loglevel used to log data written to this stream. | |||
| */ | |||
| public LogOutputStream(Task task, int level) { | |||
| this.task = task; | |||
| this((ProjectComponent) task, level); | |||
| } | |||
| /** | |||
| * Creates a new instance of this class. | |||
| * | |||
| * @param task the task for whom to log | |||
| * @param level loglevel used to log data written to this stream. | |||
| * @since Ant 1.6.3 | |||
| */ | |||
| public LogOutputStream(ProjectComponent pc, int level) { | |||
| this.pc = pc; | |||
| this.level = level; | |||
| } | |||
| @@ -114,7 +126,7 @@ public class LogOutputStream extends OutputStream { | |||
| * @param line the line to log. | |||
| */ | |||
| protected void processLine(String line, int level) { | |||
| task.log(line, level); | |||
| pc.log(line, level); | |||
| } | |||
| @@ -1,5 +1,5 @@ | |||
| /* | |||
| * Copyright 2000,2002,2004 The Apache Software Foundation | |||
| * Copyright 2000,2002,2004-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. | |||
| @@ -19,6 +19,7 @@ package org.apache.tools.ant.taskdefs; | |||
| import java.io.IOException; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.ProjectComponent; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| @@ -36,8 +37,19 @@ public class LogStreamHandler extends PumpStreamHandler { | |||
| * @param errlevel the loglevel used to log standard error | |||
| */ | |||
| public LogStreamHandler(Task task, int outlevel, int errlevel) { | |||
| super(new LogOutputStream(task, outlevel), | |||
| new LogOutputStream(task, errlevel)); | |||
| this((ProjectComponent) task, outlevel, errlevel); | |||
| } | |||
| /** | |||
| * Creates log stream handler | |||
| * | |||
| * @param pc the project component for whom to log | |||
| * @param outlevel the loglevel used to log standard output | |||
| * @param errlevel the loglevel used to log standard error | |||
| */ | |||
| public LogStreamHandler(ProjectComponent pc, int outlevel, int errlevel) { | |||
| super(new LogOutputStream(pc, outlevel), | |||
| new LogOutputStream(pc, errlevel)); | |||
| } | |||
| /** | |||
| @@ -31,8 +31,9 @@ import java.io.ByteArrayOutputStream; | |||
| import java.util.Arrays; | |||
| import java.util.Vector; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.ProjectComponent; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.filters.util.ChainReaderHelper; | |||
| import org.apache.tools.ant.util.StringUtils; | |||
| @@ -46,7 +47,7 @@ import org.apache.tools.ant.util.KeepAliveOutputStream; | |||
| /** | |||
| * The Redirector class manages the setup and connection of | |||
| * input and output redirection for an Ant task. | |||
| * input and output redirection for an Ant project component. | |||
| * | |||
| * @since Ant 1.6 | |||
| */ | |||
| @@ -125,7 +126,7 @@ public class Redirector { | |||
| private boolean createEmptyFiles = true; | |||
| /** The task for which this redirector is working */ | |||
| private Task managingTask; | |||
| private ProjectComponent managingTask; | |||
| /** The stream for output data */ | |||
| private OutputStream outputStream = null; | |||
| @@ -172,6 +173,17 @@ public class Redirector { | |||
| * @param managingTask the task for which the redirector is to work | |||
| */ | |||
| public Redirector(Task managingTask) { | |||
| this((ProjectComponent) managingTask); | |||
| } | |||
| /** | |||
| * Create a redirector instance for the given task | |||
| * | |||
| * @param managingTask the project component for which the | |||
| * redirector is to work | |||
| * @since Ant 1.6.3 | |||
| */ | |||
| public Redirector(ProjectComponent managingTask) { | |||
| this.managingTask = managingTask; | |||
| } | |||
| @@ -498,7 +510,7 @@ public class Redirector { | |||
| || !(outputEncoding.equalsIgnoreCase(inputEncoding))) { | |||
| try { | |||
| LeadPipeInputStream snk = new LeadPipeInputStream(); | |||
| snk.setManagingTask(managingTask); | |||
| snk.setManagingComponent(managingTask); | |||
| InputStream outPumpIn = snk; | |||
| @@ -527,7 +539,7 @@ public class Redirector { | |||
| || !(errorEncoding.equalsIgnoreCase(inputEncoding))) { | |||
| try { | |||
| LeadPipeInputStream snk = new LeadPipeInputStream(); | |||
| snk.setManagingTask(managingTask); | |||
| snk.setManagingComponent(managingTask); | |||
| InputStream errPumpIn = snk; | |||
| @@ -563,7 +575,7 @@ public class Redirector { | |||
| } catch (IOException eyeOhEx) { | |||
| throw new BuildException(eyeOhEx); | |||
| } | |||
| ((ConcatFileInputStream) inputStream).setManagingTask(managingTask); | |||
| ((ConcatFileInputStream) inputStream).setManagingComponent(managingTask); | |||
| } else if (inputString != null) { | |||
| managingTask.log("Using input \"" + inputString + "\"", | |||
| Project.MSG_VERBOSE); | |||
| @@ -191,6 +191,16 @@ public class CommandlineJava implements Cloneable { | |||
| propertySets.addElement(ps); | |||
| } | |||
| /** | |||
| * add a propertyset to the total set | |||
| * @param ps the new property set | |||
| * @since Ant 1.6.3 | |||
| */ | |||
| public void addSysproperties(SysProperties ps) { | |||
| variables.addAll(ps.variables); | |||
| propertySets.addAll(ps.propertySets); | |||
| } | |||
| /** | |||
| * merge all property sets into a single Properties object | |||
| * @return the merged object | |||
| @@ -204,6 +214,7 @@ public class CommandlineJava implements Cloneable { | |||
| } | |||
| return p; | |||
| } | |||
| } | |||
| /** | |||
| @@ -246,6 +257,15 @@ public class CommandlineJava implements Cloneable { | |||
| sysProperties.addSyspropertyset(sysp); | |||
| } | |||
| /** | |||
| * add a set of system properties | |||
| * @param sysp a set of properties | |||
| * @since Ant 1.6.3 | |||
| */ | |||
| public void addSysproperties(SysProperties sysp) { | |||
| sysProperties.addSysproperties(sysp); | |||
| } | |||
| /** | |||
| * Set the executable used to start the new JVM. | |||
| * @param vm the executable to use | |||
| @@ -23,8 +23,9 @@ import java.io.BufferedInputStream; | |||
| import java.io.IOException; | |||
| import java.io.FileInputStream; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.ProjectComponent; | |||
| import org.apache.tools.ant.Task; | |||
| /** | |||
| * Special <CODE>InputStream</CODE> that will | |||
| @@ -37,7 +38,7 @@ public class ConcatFileInputStream extends InputStream { | |||
| private boolean eof = false; | |||
| private File[] file; | |||
| private InputStream currentStream; | |||
| private Task managingTask; | |||
| private ProjectComponent managingPc; | |||
| /** | |||
| * Construct a new <CODE>ConcatFileInputStream</CODE> | |||
| @@ -71,7 +72,16 @@ public class ConcatFileInputStream extends InputStream { | |||
| * @param task the managing <CODE>Task</CODE>. | |||
| */ | |||
| public void setManagingTask(Task task) { | |||
| this.managingTask = task; | |||
| setManagingComponent(task); | |||
| } | |||
| /** | |||
| * Set a managing <CODE>Task</CODE> for | |||
| * this <CODE>ConcatFileInputStream</CODE>. | |||
| * @param task the managing <CODE>Task</CODE>. | |||
| */ | |||
| public void setManagingComponent(ProjectComponent pc) { | |||
| this.managingPc = pc; | |||
| } | |||
| /** | |||
| @@ -80,8 +90,8 @@ public class ConcatFileInputStream extends InputStream { | |||
| * @param loglevel the <CODE>int</CODE> logging level. | |||
| */ | |||
| public void log(String message, int loglevel) { | |||
| if (managingTask != null) { | |||
| managingTask.log(message, loglevel); | |||
| if (managingPc != null) { | |||
| managingPc.log(message, loglevel); | |||
| } else { | |||
| if (loglevel > Project.MSG_WARN) { | |||
| System.out.println(message); | |||
| @@ -21,6 +21,7 @@ import java.io.IOException; | |||
| import java.io.PipedInputStream; | |||
| import java.io.PipedOutputStream; | |||
| import org.apache.tools.ant.ProjectComponent; | |||
| import org.apache.tools.ant.Task; | |||
| import org.apache.tools.ant.Project; | |||
| @@ -29,7 +30,7 @@ import org.apache.tools.ant.Project; | |||
| * when the writing <CODE>Thread</CODE> is no longer alive. | |||
| */ | |||
| public class LeadPipeInputStream extends PipedInputStream { | |||
| private Task managingTask; | |||
| private ProjectComponent managingPc; | |||
| /** | |||
| * Construct a new <CODE>LeadPipeInputStream</CODE>. | |||
| @@ -73,7 +74,16 @@ public class LeadPipeInputStream extends PipedInputStream { | |||
| * @param task the managing <CODE>Task</CODE>. | |||
| */ | |||
| public void setManagingTask(Task task) { | |||
| this.managingTask = task; | |||
| setManagingComponent(task); | |||
| } | |||
| /** | |||
| * Set a managing <CODE>ProjectComponent</CODE> for | |||
| * this <CODE>LeadPipeInputStream</CODE>. | |||
| * @param pc the managing <CODE>ProjectComponent</CODE>. | |||
| */ | |||
| public void setManagingComponent(ProjectComponent pc) { | |||
| this.managingPc = pc; | |||
| } | |||
| /** | |||
| @@ -82,8 +92,8 @@ public class LeadPipeInputStream extends PipedInputStream { | |||
| * @param loglevel the <CODE>int</CODE> logging level. | |||
| */ | |||
| public void log(String message, int loglevel) { | |||
| if (managingTask != null) { | |||
| managingTask.log(message, loglevel); | |||
| if (managingPc != null) { | |||
| managingPc.log(message, loglevel); | |||
| } else { | |||
| if (loglevel > Project.MSG_WARN) { | |||
| System.out.println(message); | |||
| @@ -1,5 +1,5 @@ | |||
| /* | |||
| * Copyright 2002,2004 The Apache Software Foundation | |||
| * Copyright 2002,2004-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. | |||
| @@ -40,6 +40,7 @@ public class ExecuteJavaTest extends TestCase { | |||
| private ExecuteJava ej; | |||
| private Project project; | |||
| private Path cp; | |||
| public ExecuteJavaTest(String name) { | |||
| super(name); | |||
| @@ -50,7 +51,8 @@ public class ExecuteJavaTest extends TestCase { | |||
| ej.setTimeout(new Long(TIME_OUT)); | |||
| project = new Project(); | |||
| project.setBasedir("."); | |||
| ej.setClasspath(new Path(project, getTestClassPath())); | |||
| cp = new Path(project, getTestClassPath()); | |||
| ej.setClasspath(cp); | |||
| } | |||
| private Commandline getCommandline(int timetorun) throws Exception { | |||
| @@ -85,6 +87,30 @@ public class ExecuteJavaTest extends TestCase { | |||
| } | |||
| public void testNoTimeOutForked() throws Exception { | |||
| Commandline cmd = getCommandline(TIME_OUT/2); | |||
| ej.setJavaCommand(cmd); | |||
| ej.fork(cp); | |||
| assertTrue("process should not have been killed", !ej.killedProcess()); | |||
| } | |||
| // test that the watchdog ends the process | |||
| public void testTimeOutForked() throws Exception { | |||
| Commandline cmd = getCommandline(TIME_OUT*2); | |||
| ej.setJavaCommand(cmd); | |||
| long now = System.currentTimeMillis(); | |||
| ej.fork(cp); | |||
| long elapsed = System.currentTimeMillis() - now; | |||
| assertTrue("process should have been killed", ej.killedProcess()); | |||
| assertTrue("elapse time of "+elapsed | |||
| +" ms is less than timeout value of "+TIME_OUT_TEST+" ms", | |||
| elapsed >= TIME_OUT_TEST); | |||
| assertTrue("elapse time of "+elapsed | |||
| +" ms is greater than run value of "+(TIME_OUT*2)+" ms", | |||
| elapsed < TIME_OUT*2); | |||
| } | |||
| /** | |||
| * Dangerous method to obtain the classpath for the test. This is | |||
| * severely tighted to the build.xml properties. | |||