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. | |||