diff --git a/src/main/org/apache/tools/ant/taskdefs/Java.java b/src/main/org/apache/tools/ant/taskdefs/Java.java index 0bba65b9d..431255ba2 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Java.java +++ b/src/main/org/apache/tools/ant/taskdefs/Java.java @@ -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. * diff --git a/src/main/org/apache/tools/ant/types/Assertions.java b/src/main/org/apache/tools/ant/types/Assertions.java index 44575dd8c..75a46f72c 100644 --- a/src/main/org/apache/tools/ant/types/Assertions.java +++ b/src/main/org/apache/tools/ant/types/Assertions.java @@ -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. */ diff --git a/src/main/org/apache/tools/ant/types/Commandline.java b/src/main/org/apache/tools/ant/types/Commandline.java index c334a25a4..9133be8de 100644 --- a/src/main/org/apache/tools/ant/types/Commandline.java +++ b/src/main/org/apache/tools/ant/types/Commandline.java @@ -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. +

This class is there to support the srcfile and targetfile + elements of <execon> and <transform> - don't know + whether there might be additional use cases.

--SB */ - //

This class is there to support the srcfile and targetfile - // elements of <execon> and <transform> - don't know - // whether there might be additional use cases.

--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 { * addValue 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(); diff --git a/src/main/org/apache/tools/ant/types/CommandlineJava.java b/src/main/org/apache/tools/ant/types/CommandlineJava.java index d05675af7..0d0276d3f 100644 --- a/src/main/org/apache/tools/ant/types/CommandlineJava.java +++ b/src/main/org/apache/tools/ant/types/CommandlineJava.java @@ -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 Commandline. One is used for the + * A representation of a Java command line that is + * a composite of 2 Commandline. 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 Stephane Bailliez + * @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);