Browse Source

Simplify forking of new VMs by providing a fork method in ExecuteJava

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@277571 13f79535-47bb-0310-9956-ffa450edef68
master
Stefan Bodewig 20 years ago
parent
commit
eca527f22b
9 changed files with 205 additions and 43 deletions
  1. +78
    -2
      src/main/org/apache/tools/ant/taskdefs/ExecuteJava.java
  2. +1
    -17
      src/main/org/apache/tools/ant/taskdefs/Java.java
  3. +16
    -4
      src/main/org/apache/tools/ant/taskdefs/LogOutputStream.java
  4. +15
    -3
      src/main/org/apache/tools/ant/taskdefs/LogStreamHandler.java
  5. +18
    -6
      src/main/org/apache/tools/ant/taskdefs/Redirector.java
  6. +20
    -0
      src/main/org/apache/tools/ant/types/CommandlineJava.java
  7. +15
    -5
      src/main/org/apache/tools/ant/util/ConcatFileInputStream.java
  8. +14
    -4
      src/main/org/apache/tools/ant/util/LeadPipeInputStream.java
  9. +28
    -2
      src/testcases/org/apache/tools/ant/taskdefs/ExecuteJavaTest.java

+ 78
- 2
src/main/org/apache/tools/ant/taskdefs/ExecuteJava.java View File

@@ -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");
}
}

}

+ 1
- 17
src/main/org/apache/tools/ant/taskdefs/Java.java View File

@@ -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);
}

/**


+ 16
- 4
src/main/org/apache/tools/ant/taskdefs/LogOutputStream.java View File

@@ -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);
}




+ 15
- 3
src/main/org/apache/tools/ant/taskdefs/LogStreamHandler.java View File

@@ -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));
}

/**


+ 18
- 6
src/main/org/apache/tools/ant/taskdefs/Redirector.java View File

@@ -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);


+ 20
- 0
src/main/org/apache/tools/ant/types/CommandlineJava.java View File

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


+ 15
- 5
src/main/org/apache/tools/ant/util/ConcatFileInputStream.java View File

@@ -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);


+ 14
- 4
src/main/org/apache/tools/ant/util/LeadPipeInputStream.java View File

@@ -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);


+ 28
- 2
src/testcases/org/apache/tools/ant/taskdefs/ExecuteJavaTest.java View File

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


Loading…
Cancel
Save