Browse Source

I always worry when I change something fundamental, and the amount of refactoring here to get assertions in 'cleanly' means the change here is larger than one would expect. The key problem is that the existing code created presized arrays, but sizing these arrays meant resolving every single option and counting the #of commands -effectively creating the command line twice. Once to size it, once to save the results. this was silly and unwieldy, though it made sense given how this command grew and grew.

Most of the diff is changing CommandLine and CommmandLineJava to append their info to a supplied ListIterator, so that we dont need to create string arrays and keep on appending them. All the old stuff is still there, but used less -certainly not used at all by CommandLineJava.

No assertion tests yet...


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@275002 13f79535-47bb-0310-9956-ffa450edef68
master
Steve Loughran 22 years ago
parent
commit
2c905033e5
4 changed files with 343 additions and 71 deletions
  1. +12
    -1
      src/main/org/apache/tools/ant/taskdefs/Java.java
  2. +55
    -1
      src/main/org/apache/tools/ant/types/Assertions.java
  3. +92
    -24
      src/main/org/apache/tools/ant/types/Commandline.java
  4. +184
    -45
      src/main/org/apache/tools/ant/types/CommandlineJava.java

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

@@ -67,6 +67,7 @@ import org.apache.tools.ant.types.Environment;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.PropertySet;
import org.apache.tools.ant.types.Reference;
import org.apache.tools.ant.types.Assertions;

/**
* Launcher for Java applications. Allows use of
@@ -94,6 +95,7 @@ public class Java extends Task {
private Long timeout = null;
private Redirector redirector = new Redirector(this);
private String resultProperty;

private boolean spawn = false;
private boolean incompatibleWithSpawn = false;
/**
@@ -329,7 +331,7 @@ public class Java extends Task {
protected void maybeSetResultPropertyValue(int result) {
String res = Integer.toString(result);
if (resultProperty != null) {
project.setNewProperty(resultProperty, res);
getProject().setNewProperty(resultProperty, res);
}
}

@@ -560,6 +562,15 @@ public class Java extends Task {
incompatibleWithSpawn = true;
}

/**
* assertions to enable in this program (if fork=true)
* @since Ant 1.6
* @param asserts assertion set
*/
public void setAssertions(Assertions asserts) {
cmdl.setAssertions(asserts);
}

/**
* Pass output sent to System.out to specified output file.
*


+ 55
- 1
src/main/org/apache/tools/ant/types/Assertions.java View File

@@ -111,7 +111,7 @@ public class Assertions extends DataType {
/**
* list of type BaseAssertion
*/
private List assertionList = new ArrayList();
private ArrayList assertionList = new ArrayList();


/**
@@ -172,6 +172,47 @@ public class Assertions extends DataType {
}
}

/**
* how many assertions are made...will resolve references before returning
* @return total # of commands to make
*/
public int size() {
Assertions clause = getFinalReference();
return clause.getFinalSize();
}


/**
* what is the final size of this object
* @return
*/
private int getFinalSize() {
return assertionList.size()+ (enableSystemAssertions!=null?1:0);
}

/**
* add the assertions to a list in a format suitable
* for adding to a command line
* @param commandList
*/
public void applyAssertions(List commandList) {
Assertions clause = getFinalReference();
//do the system assertions
if (Boolean.TRUE.equals(clause.enableSystemAssertions)) {
commandList.add("-enablesystemassertions");
} else if (Boolean.FALSE.equals(clause.enableSystemAssertions)) {
commandList.add("-disablesystemassertions");
}

//now any inner assertions
Iterator it = clause.assertionList.iterator();
while (it.hasNext()) {
BaseAssertion assertion = (BaseAssertion) it.next();
String arg = assertion.toCommand();
commandList.add(arg);
}
}

/**
* apply all the assertions to the command.
* @param command
@@ -205,6 +246,19 @@ public class Assertions extends DataType {
argument.setValue(arg);
}

/**
* clone the objects.
* This is not a full depth clone; the list of assertions is cloned,
* but it does not clone the underlying assertions.
* @return a cli
* @throws CloneNotSupportedException
*/
protected Object clone() throws CloneNotSupportedException {
Assertions that=(Assertions) super.clone();
that.assertionList=(ArrayList) assertionList.clone();
return that;
}

/**
* base class for our assertion elements.
*/


+ 92
- 24
src/main/org/apache/tools/ant/types/Commandline.java View File

@@ -57,6 +57,11 @@ package org.apache.tools.ant.types;
import java.io.File;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.LinkedList;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.ProjectComponent;
import org.apache.tools.ant.util.StringUtils;
@@ -86,7 +91,14 @@ import org.apache.tools.ant.util.StringUtils;
*/
public class Commandline implements Cloneable {

/**
* The arguments of the command
*/
private Vector arguments = new Vector();

/**
* the program to execute
*/
private String executable = null;

protected static final String DISCLAIMER =
@@ -96,9 +108,14 @@ public class Commandline implements Cloneable {
+ "not part of the command."
+ StringUtils.LINE_SEP;

public Commandline(String to_process) {
/**
* create a command line from a string
* @param toProcess the line: the first element becomes the executable, the rest
* the arguments
*/
public Commandline(String toProcess) {
super();
String[] tmp = translateCommandline(to_process);
String[] tmp = translateCommandline(toProcess);
if (tmp != null && tmp.length > 0) {
setExecutable(tmp[0]);
for (int i = 1; i < tmp.length; i++) {
@@ -107,6 +124,9 @@ public class Commandline implements Cloneable {
}
}

/**
* Create an empty command line
*/
public Commandline() {
super();
}
@@ -183,10 +203,10 @@ public class Commandline implements Cloneable {

/**
* Class to keep track of the position of an Argument.
<p>This class is there to support the srcfile and targetfile
elements of &lt;execon&gt; and &lt;transform&gt; - don't know
whether there might be additional use cases.</p> --SB
*/
// <p>This class is there to support the srcfile and targetfile
// elements of &lt;execon&gt; and &lt;transform&gt; - don't know
// whether there might be additional use cases.</p> --SB
public class Marker {

private int position;
@@ -248,7 +268,8 @@ public class Commandline implements Cloneable {
}

/**
* Sets the executable to run.
* Sets the executable to run. All file separators in the string
* are converted to the platform specific value
*/
public void setExecutable(String executable) {
if (executable == null || executable.length() == 0) {
@@ -259,11 +280,19 @@ public class Commandline implements Cloneable {
}


/**
* get the executable
* @return the program to run -null if not yet set
*/
public String getExecutable() {
return executable;
}


/**
* append the arguments to the existing command
* @param line an array of arguments to append
*/
public void addArguments(String[] line) {
for (int i = 0; i < line.length; i++) {
createArgument().setValue(line[i]);
@@ -274,14 +303,23 @@ public class Commandline implements Cloneable {
* Returns the executable and all defined arguments.
*/
public String[] getCommandline() {
final String[] args = getArguments();
if (executable == null) {
return args;
List commands=new LinkedList();
ListIterator list = commands.listIterator();
addCommandToList(list);
final String[] result = new String[commands.size()];
return (String[])commands.toArray(result);
}

/**
* add the entire command, including (optional) executable to a list
* @param list
* @since Ant 1.6
*/
public void addCommandToList(ListIterator list) {
if(executable!=null) {
list.add(executable);
}
final String[] result = new String[args.length + 1];
result[0] = executable;
System.arraycopy(args, 0, result, 1, args.length);
return result;
addArgumentsToList(list);
}


@@ -290,23 +328,34 @@ public class Commandline implements Cloneable {
* <code>addValue</code> or the argument object.
*/
public String[] getArguments() {
Vector result = new Vector(arguments.size() * 2);
List result = new ArrayList(arguments.size() * 2);
addArgumentsToList(result.listIterator());
String [] res = new String[result.size()];
return (String[])result.toArray(res);
}

/**
* append all the arguments to the tail of a supplied list
* @param list
* @since Ant 1.6
*/
public void addArgumentsToList(ListIterator list) {
for (int i = 0; i < arguments.size(); i++) {
Argument arg = (Argument) arguments.elementAt(i);
String[] s = arg.getParts();
if (s != null) {
for (int j = 0; j < s.length; j++) {
result.addElement(s[j]);
list.add(s[j]);
}
}
}

String [] res = new String[result.size()];
result.copyInto(res);
return res;
}


/**
* stringify operator returns the command line as a string
* @return the command line
*/
public String toString() {
return toString(getCommandline());
}
@@ -324,7 +373,8 @@ public class Commandline implements Cloneable {
public static String quoteArgument(String argument) {
if (argument.indexOf("\"") > -1) {
if (argument.indexOf("\'") > -1) {
throw new BuildException("Can\'t handle single and double quotes in same argument");
throw new BuildException("Can\'t handle single and double"
+" quotes in same argument");
} else {
return '\'' + argument + '\'';
}
@@ -338,6 +388,8 @@ public class Commandline implements Cloneable {
/**
* Quotes the parts of the given array in way that makes them
* usable as command line arguments.
* @return empty string for null or no command, else every argument split
* by spaces and quoted by quoting rules
*/
public static String toString(String [] line) {
// empty path return empty string
@@ -356,8 +408,15 @@ public class Commandline implements Cloneable {
return result.toString();
}

public static String[] translateCommandline(String to_process) {
if (to_process == null || to_process.length() == 0) {
/**
* crack a command line
* @param toProcess the command line to process
* @return the command line broken into strings.
* An empty or null toProcess parameter results in a zero sized array
*/
public static String[] translateCommandline(String toProcess) {
if (toProcess == null || toProcess.length() == 0) {
//no command? no string
return new String[0];
}

@@ -367,7 +426,7 @@ public class Commandline implements Cloneable {
final int inQuote = 1;
final int inDoubleQuote = 2;
int state = normal;
StringTokenizer tok = new StringTokenizer(to_process, "\"\' ", true);
StringTokenizer tok = new StringTokenizer(toProcess, "\"\' ", true);
Vector v = new Vector();
StringBuffer current = new StringBuffer();
boolean lastTokenHasBeenQuoted = false;
@@ -414,7 +473,7 @@ public class Commandline implements Cloneable {
}

if (state == inQuote || state == inDoubleQuote) {
throw new BuildException("unbalanced quotes in " + to_process);
throw new BuildException("unbalanced quotes in " + toProcess);
}

String[] args = new String[v.size()];
@@ -422,10 +481,19 @@ public class Commandline implements Cloneable {
return args;
}

/**
* size operator. This actually creates the command line, so it is not
* a zero cost operation.
* @return number of elements in the command, including the executable
*/
public int size() {
return getCommandline().length;
}

/**
* a deep clone of the contained object.
* @return
*/
public Object clone() {
try {
Commandline c = (Commandline) super.clone();


+ 184
- 45
src/main/org/apache/tools/ant/types/CommandlineJava.java View File

@@ -57,18 +57,24 @@ package org.apache.tools.ant.types;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.ListIterator;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.util.JavaEnvUtils;

/**
* A representation of a Java command line that is nothing more
* than a composite of 2 <tt>Commandline</tt>. One is used for the
* A representation of a Java command line that is
* a composite of 2 <tt>Commandline</tt>. One is used for the
* vm/options and one for the classname/arguments. It provides
* specific methods for a java command line.
*
* @author thomas.haas@softwired-inc.com
* @author <a href="mailto:sbailliez@apache.org">Stephane Bailliez</a>
* @author steve loughran
*/
public class CommandlineJava implements Cloneable {

@@ -88,6 +94,10 @@ public class CommandlineJava implements Cloneable {
private Path bootclasspath = null;
private String vmVersion;
private String maxMemory = null;
/**
* any assertions to make? Currently only supported in forked JVMs
*/
private Assertions assertions=null;

/**
* Indicate whether it will execute a jar file or not, in this case
@@ -102,37 +112,58 @@ public class CommandlineJava implements Cloneable {
Properties sys = null;
private Vector propertySets = new Vector();

/**
* get the properties as an array; this is an override of the
* superclass, as it evaluates all the properties
* @return the array of definitions; may be null
* @throws BuildException
*/
public String[] getVariables() throws BuildException {
String[] props = super.getVariables();
Properties p = mergePropertySets();

if (props == null) {
if (p.size() == 0) {
return null;
} else {
props = new String[0];
}
List definitions=new LinkedList();
ListIterator list=definitions.listIterator();
addDefinitionsToList(list);
if(definitions.size()==0) {
return null;
} else {
return (String[])definitions.toArray(new String[0]);
}
}

String[] result = new String[props.length + p.size()];
int i = 0;
for (; i < props.length; i++) {
result[i] = "-D" + props[i];
/**
* add all definitions (including property sets) to a list
* @param listIt list iterator supporting add method
*/
public void addDefinitionsToList(ListIterator listIt) {
String[] props = super.getVariables();
if(props!=null) {
for (int i=0; i < props.length; i++) {
listIt.add("-D" + props[i]);
}
}
for (Enumeration enum = p.keys(); enum.hasMoreElements();) {
Properties propertySets = mergePropertySets();
for (Enumeration enum = propertySets.keys(); enum.hasMoreElements();) {
String key = (String) enum.nextElement();
String value = p.getProperty(key);
result[i++] = "-D" + key + "=" + value;
String value = propertySets.getProperty(key);
listIt.add("-D" + key + "=" + value);
}

return result;
}

/**
* get the size of the sysproperties instance. This merges all
* property sets, so is not an O(1) operation.
* @return
*/
public int size() {
Properties p = mergePropertySets();
return variables.size() + p.size();
}

/**
* cache the system properties and set the system properties to the
* new values
* @throws BuildException if Security prevented this operation
*/
public void setSystem() throws BuildException {
try {
sys = System.getProperties();
@@ -152,6 +183,11 @@ public class CommandlineJava implements Cloneable {
}
}

/**
* restore the system properties to the cached value
* @throws BuildException if Security prevented this operation, or
* there was no system properties to restore
*/
public void restoreSystem() throws BuildException {
if (sys == null) {
throw new BuildException("Unbalanced nesting of SysProperties");
@@ -165,6 +201,10 @@ public class CommandlineJava implements Cloneable {
}
}

/**
* deep clone
* @return a cloned instance of SysProperties
*/
public Object clone() {
try {
SysProperties c = (SysProperties) super.clone();
@@ -176,10 +216,18 @@ public class CommandlineJava implements Cloneable {
}
}

/**
* add a propertyset to the total set
* @param ps the new property set
*/
public void addSyspropertyset(PropertySet ps) {
propertySets.addElement(ps);
}

/**
* merge all property sets into a single Properties object
* @return the merged object
*/
private Properties mergePropertySets() {
Properties p = new Properties();
for (Enumeration e = propertySets.elements();
@@ -199,30 +247,71 @@ public class CommandlineJava implements Cloneable {
setVmversion(JavaEnvUtils.getJavaVersion());
}

/**
* create a new argument to the java program
* @return an argument to be configured
*/
public Commandline.Argument createArgument() {
return javaCommand.createArgument();
}

/**
* create a new JVM argument
* @return an argument to be configured
*/
public Commandline.Argument createVmArgument() {
return vmCommand.createArgument();
}

/**
* add a system property
* @param sysp a property to be set in the JVM
*/
public void addSysproperty(Environment.Variable sysp) {
sysProperties.addVariable(sysp);
}

/**
* add a set of system properties
* @param sysp a set of properties
*/
public void addSyspropertyset(PropertySet sysp) {
sysProperties.addSyspropertyset(sysp);
}

/**
* set the executable used to start the new JVM
* @param vm
*/
public void setVm(String vm) {
vmCommand.setExecutable(vm);
}

/**
* set the JVM version required
* @param value
*/
public void setVmversion(String value) {
vmVersion = value;
}


/**
* get the current assertions
* @return assertions or null
*/
public Assertions getAssertions() {
return assertions;
}

/**
* add an assertion set to the command
* @param assertions assertions to make
*/
public void setAssertions(Assertions assertions) {
this.assertions = assertions;
}

/**
* set a jar file to execute via the -jar option.
* @param jarpathname the pathname of the jar to execute
@@ -290,27 +379,39 @@ public class CommandlineJava implements Cloneable {
* @return the list of all arguments necessary to run the vm.
*/
public String[] getCommandline() {
String[] result = new String[size()];
int pos = 0;
String[] vmArgs = getActualVMCommand().getCommandline();
System.arraycopy(vmArgs, 0, result, pos, vmArgs.length);
pos += vmArgs.length;
//create the list
List commands=new LinkedList();
final ListIterator listIterator = commands.listIterator();
//fill it
addCommandsToList(listIterator);
//convert to an array
return (String[])commands.toArray(new String[0]);
}

/**
* add all the commands to a list identified by the iterator passed in
* @param listIterator an iterator that supports the add method
* @since Ant1.6
*/
private void addCommandsToList(final ListIterator listIterator) {
//create the command to run Java, including user specified options
getActualVMCommand().addCommandToList(listIterator);
// properties are part of the vm options...
if (sysProperties.size() > 0) {
System.arraycopy(sysProperties.getVariables(), 0,
result, pos, sysProperties.size());
pos += sysProperties.size();
sysProperties.addDefinitionsToList(listIterator);
//boot classpath
if (haveBootclasspath(true)) {
listIterator.add("-Xbootclasspath:" + bootclasspath.toString());
}

// classpath and bootclasspath are vm options too..
if (haveBootclasspath(false)) {
result[pos++] = "-Xbootclasspath:" + bootclasspath.toString();
//main classpath
if (haveClasspath()) {
listIterator.add("-classpath");
listIterator.add(
classpath.concatSystemClasspath("ignore").toString());
}

if (haveClasspath()) {
result[pos++] = "-classpath";
result[pos++] =
classpath.concatSystemClasspath("ignore").toString();
//now any assertions are added
if (getAssertions() != null) {
getAssertions().applyAssertions(this);
}

// JDK usage command line says that -jar must be the first option, as there is
@@ -318,15 +419,11 @@ public class CommandlineJava implements Cloneable {
// option, it is appended here as specified in the docs even though there is
// in fact no order.
if (executeJar) {
result[pos++] = "-jar";
listIterator.add("-jar");
}

// this is the classname to run as well as its arguments.
// in case of 'executeJar', the executable is a jar file.
System.arraycopy(javaCommand.getCommandline(), 0,
result, pos, javaCommand.size());

return result;
javaCommand.addCommandToList(listIterator);
}

/**
@@ -339,7 +436,7 @@ public class CommandlineJava implements Cloneable {


/**
* get a string description
* get a string description.
* @return the command line as a string
*/
public String toString() {
@@ -369,6 +466,10 @@ public class CommandlineJava implements Cloneable {
return Commandline.describeCommand(getJavaCommand());
}

/**
* Get the VM command parameters, including memory settings
* @return
*/
private Commandline getActualVMCommand() {
Commandline actualVMCommand = (Commandline) vmCommand.clone();
if (maxMemory != null) {
@@ -382,9 +483,11 @@ public class CommandlineJava implements Cloneable {
}

/**
* The size of the java command line.
* The size of the java command line. This is a fairly intensive
* operation, as it has to evaluate the size of many components.
* @return the total number of arguments in the java command line.
* @see #getCommandline()
* @deprecated please dont use this -it effectively creates the entire command.
*/
public int size() {
int size = getActualVMCommand().size() + javaCommand.size() + sysProperties.size();
@@ -400,39 +503,72 @@ public class CommandlineJava implements Cloneable {
if (executeJar) {
size++;
}
//assertions take up space too
if(getAssertions()!=null) {
size+=getAssertions().size();
}
return size;
}

/**
* get the Java command to be used.
* @return the java command -not a clone.
*/
public Commandline getJavaCommand() {
return javaCommand;
}

/**
* Get the VM command, including memory.
* @return A deep clone of the instance's VM command, with memory settings added
*/
public Commandline getVmCommand() {
return getActualVMCommand();
}

/**
* get the classpath for the command
* @return the classpath or null
*/
public Path getClasspath() {
return classpath;
}

/**
* get the boot classpath
* @return boot classpath or null
*/
public Path getBootclasspath() {
return bootclasspath;
}

/**
* cache current system properties and set them to those in this
* java command
* @throws BuildException if Security prevented this operation
*/
public void setSystemProperties() throws BuildException {
sysProperties.setSystem();
}

/**
* @throws BuildException if Security prevented this operation, or
* there was no system properties to restore
*/
public void restoreSystemProperties() throws BuildException {
sysProperties.restoreSystem();
}

/**
* get the system properties object
* @return
*/
public SysProperties getSystemProperties() {
return sysProperties;
}

/**
* clone the object; do a deep clone of all fields in the class
* clone the object; clone of all fields in the class
* @return a CommandlineJava object
*/
public Object clone() {
@@ -447,6 +583,9 @@ public class CommandlineJava implements Cloneable {
if (bootclasspath != null) {
c.bootclasspath = (Path) bootclasspath.clone();
}
if( assertions != null ) {
c.assertions = (Assertions) assertions.clone();
}
return c;
} catch (CloneNotSupportedException e) {
throw new BuildException(e);


Loading…
Cancel
Save