summaryrefslogtreecommitdiffstats
path: root/ant1.5/src/java/net/sf/antcontrib/logic
diff options
context:
space:
mode:
authormattinger <[email protected]>2007-03-07 21:39:57 +0000
committermattinger <[email protected]>2007-03-07 21:39:57 +0000
commit69da5b36470f85cc514a5661298cf6d5bfc01116 (patch)
tree313bb58f47fdfde3d40b1706266ec0a742fb798c /ant1.5/src/java/net/sf/antcontrib/logic
parent1bce0a66a11f4cbf8d6bcc46fbd9a36cb7ebe64a (diff)
Code and build re-organized to produce ant-version specific jar files and library sets
git-svn-id: file:///home/sven/projects/JOGL/temp/ant-contrib/svn/ant-contrib-code/branches/ant-1.7.0-upgrade@100 32d7a393-a5a9-423c-abd3-5d954feb1f2f
Diffstat (limited to 'ant1.5/src/java/net/sf/antcontrib/logic')
-rw-r--r--ant1.5/src/java/net/sf/antcontrib/logic/AntCallBack.java73
-rw-r--r--ant1.5/src/java/net/sf/antcontrib/logic/AntFetch.java70
-rw-r--r--ant1.5/src/java/net/sf/antcontrib/logic/Assert.java116
-rw-r--r--ant1.5/src/java/net/sf/antcontrib/logic/ForEach.java424
-rw-r--r--ant1.5/src/java/net/sf/antcontrib/logic/IfTask.java222
-rw-r--r--ant1.5/src/java/net/sf/antcontrib/logic/OutOfDate.java681
-rw-r--r--ant1.5/src/java/net/sf/antcontrib/logic/Relentless.java98
-rw-r--r--ant1.5/src/java/net/sf/antcontrib/logic/RunTargetTask.java51
-rw-r--r--ant1.5/src/java/net/sf/antcontrib/logic/Switch.java208
-rw-r--r--ant1.5/src/java/net/sf/antcontrib/logic/Throw.java51
-rw-r--r--ant1.5/src/java/net/sf/antcontrib/logic/TimestampSelector.java284
-rw-r--r--ant1.5/src/java/net/sf/antcontrib/logic/TryCatchTask.java243
-rw-r--r--ant1.5/src/java/net/sf/antcontrib/logic/condition/BooleanConditionBase.java83
-rw-r--r--ant1.5/src/java/net/sf/antcontrib/logic/condition/IsGreaterThan.java87
-rw-r--r--ant1.5/src/java/net/sf/antcontrib/logic/condition/IsLessThan.java87
-rw-r--r--ant1.5/src/java/net/sf/antcontrib/logic/condition/IsPropertyFalse.java47
-rw-r--r--ant1.5/src/java/net/sf/antcontrib/logic/condition/IsPropertyTrue.java47
17 files changed, 2872 insertions, 0 deletions
diff --git a/ant1.5/src/java/net/sf/antcontrib/logic/AntCallBack.java b/ant1.5/src/java/net/sf/antcontrib/logic/AntCallBack.java
new file mode 100644
index 0000000..9a68619
--- /dev/null
+++ b/ant1.5/src/java/net/sf/antcontrib/logic/AntCallBack.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.antcontrib.logic;
+
+import java.util.StringTokenizer;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.CallTarget;
+
+/**
+ * Subclass of Ant which allows us to fetch
+ * properties which are set in the scope of the called
+ * target, and set them in the scope of the calling target.
+ * Normally, these properties are thrown away as soon as the
+ * called target completes execution.
+ *
+ * @author inger
+ * @author Dale Anson, [email protected]
+ * @ant.task name="antcallback"
+ */
+public class AntCallBack extends CallTarget {
+
+ /** the name of the property to fetch from the new project */
+ private String returnName = null;
+
+ /**
+ * Do the execution.
+ *
+ * @exception BuildException Description of the Exception
+ */
+ public void execute() throws BuildException {
+ super.execute();
+
+ // copy back the props if possible
+ if ( returnName != null ) {
+ StringTokenizer st = new StringTokenizer( returnName, "," );
+ while ( st.hasMoreTokens() ) {
+ String name = st.nextToken().trim();
+ String value = super.getProject().getProperty(returnName);
+ if ( value != null ) {
+ getProject().setUserProperty( name, value );
+ }
+ }
+ }
+ }
+
+ /**
+ * Set the property or properties that are set in the new project to be
+ * transfered back to the original project. As with all properties, if the
+ * property already exists in the original project, it will not be overridden
+ * by a different value from the new project.
+ *
+ * @param r the name of a property in the new project to set in the original
+ * project. This may be a comma separate list of properties.
+ */
+ public void setReturn( String r ) {
+ returnName = r;
+ }
+}
+
diff --git a/ant1.5/src/java/net/sf/antcontrib/logic/AntFetch.java b/ant1.5/src/java/net/sf/antcontrib/logic/AntFetch.java
new file mode 100644
index 0000000..ad1e3ea
--- /dev/null
+++ b/ant1.5/src/java/net/sf/antcontrib/logic/AntFetch.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.antcontrib.logic;
+
+import java.util.StringTokenizer;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Ant;
+
+/**
+ * Subclass of CallTarget which allows us to fetch
+ * properties which are set in the scope of the called
+ * target, and set them in the scope of the calling target.
+ * Normally, these properties are thrown away as soon as the
+ * called target completes execution.
+ *
+ * @author inger
+ * @author Dale Anson, [email protected]
+ * @ant.task name="antfetch"
+ */
+public class AntFetch extends Ant {
+ /** the name of the property to fetch from the new project */
+ private String returnName = null;
+
+ /**
+ * Do the execution.
+ *
+ * @exception BuildException Description of the Exception
+ */
+ public void execute() throws BuildException {
+ super.execute();
+ // copy back the props if possible
+ if ( returnName != null ) {
+ StringTokenizer st = new StringTokenizer( returnName, "," );
+ while ( st.hasMoreTokens() ) {
+ String name = st.nextToken().trim();
+ String value = super.getProject().getProperty(returnName);
+ if ( value != null ) {
+ getProject().setUserProperty( name, value );
+ }
+ }
+ }
+ }
+
+ /**
+ * Set the property or properties that are set in the new project to be
+ * transfered back to the original project. As with all properties, if the
+ * property already exists in the original project, it will not be overridden
+ * by a different value from the new project.
+ *
+ * @param r the name of a property in the new project to set in the original
+ * project. This may be a comma separate list of properties.
+ */
+ public void setReturn( String r ) {
+ returnName = r;
+ }
+}
diff --git a/ant1.5/src/java/net/sf/antcontrib/logic/Assert.java b/ant1.5/src/java/net/sf/antcontrib/logic/Assert.java
new file mode 100644
index 0000000..0978002
--- /dev/null
+++ b/ant1.5/src/java/net/sf/antcontrib/logic/Assert.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.antcontrib.logic;
+
+import net.sf.antcontrib.logic.condition.BooleanConditionBase;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Exit;
+import org.apache.tools.ant.taskdefs.Sequential;
+import org.apache.tools.ant.taskdefs.condition.Condition;
+import org.apache.tools.ant.taskdefs.condition.Equals;
+
+
+/**
+ *
+ * @ant.task name="assert"
+ */
+public class Assert
+ extends BooleanConditionBase {
+
+ private String message;
+ private boolean failOnError = true;
+ private boolean execute = true;
+ private Sequential sequential;
+ private String name;
+ private String value;
+
+ public Sequential createSequential() {
+ this.sequential = (Sequential) getProject().createTask("sequential");
+ return this.sequential;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ public BooleanConditionBase createBool() {
+ return this;
+ }
+
+ public void setExecute(boolean execute) {
+ this.execute = execute;
+ }
+
+ public void setFailOnError(boolean failOnError) {
+ this.failOnError = failOnError;
+ }
+
+ public void execute() {
+ String enable = getProject().getProperty("ant.enable.asserts");
+ boolean assertsEnabled = Project.toBoolean(enable);
+
+ if (assertsEnabled) {
+ if (name != null) {
+ if (value == null) {
+ throw new BuildException("The 'value' attribute must accompany the 'name' attribute.");
+ }
+ String propVal = getProject().replaceProperties("${" + name + "}");
+ Equals e = new Equals();
+ e.setArg1(propVal);
+ e.setArg2(value);
+ addEquals(e);
+ }
+
+ if (countConditions() == 0) {
+ throw new BuildException("There is no condition specified.");
+ }
+ else if (countConditions() > 1) {
+ throw new BuildException("There must be exactly one condition specified.");
+ }
+
+ Condition c = (Condition) getConditions().nextElement();
+ if (! c.eval()) {
+ if (failOnError) {
+ Exit fail = (Exit) getProject().createTask("fail");
+ fail.setMessage(message);
+ fail.execute();
+ }
+ }
+ else {
+ if (execute) {
+ this.sequential.execute();
+ }
+ }
+ }
+ else {
+ if (execute) {
+ this.sequential.execute();
+ }
+ }
+ }
+
+
+}
diff --git a/ant1.5/src/java/net/sf/antcontrib/logic/ForEach.java b/ant1.5/src/java/net/sf/antcontrib/logic/ForEach.java
new file mode 100644
index 0000000..99aaceb
--- /dev/null
+++ b/ant1.5/src/java/net/sf/antcontrib/logic/ForEach.java
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.antcontrib.logic;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.TaskContainer;
+import org.apache.tools.ant.taskdefs.Ant;
+import org.apache.tools.ant.taskdefs.CallTarget;
+import org.apache.tools.ant.taskdefs.Property;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Mapper;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.FileNameMapper;
+
+import net.sf.antcontrib.util.ThreadPool;
+import net.sf.antcontrib.util.ThreadPoolThread;
+
+/***
+ * Task definition for the foreach task. The foreach task iterates
+ * over a list, a list of filesets, or both.
+ *
+ * <pre>
+ *
+ * Usage:
+ *
+ * Task declaration in the project:
+ * <code>
+ * &lt;taskdef name="foreach" classname="net.sf.antcontrib.logic.ForEach" /&gt;
+ * </code>
+ *
+ * Call Syntax:
+ * <code>
+ * &lt;foreach list="values" target="targ" param="name"
+ * [parallel="true|false"]
+ * [delimiter="delim"] /&gt;
+ * </code>
+ *
+ * Attributes:
+ * list --> The list of values to process, with the delimiter character,
+ * indicated by the "delim" attribute, separating each value
+ * target --> The target to call for each token, passing the token as the
+ * parameter with the name indicated by the "param" attribute
+ * param --> The name of the parameter to pass the tokens in as to the
+ * target
+ * delimiter --> The delimiter string that separates the values in the "list"
+ * parameter. The default is ","
+ * parallel --> Should all targets execute in parallel. The default is false.
+ * trim --> Should we trim the list item before calling the target?
+ *
+ * </pre>
+ * @author <a href="mailto:[email protected]">Matthew Inger</a>
+ * @ant.task name="foreach"
+ */
+public class ForEach extends Task
+{
+ private String list;
+ private String param;
+ private String delimiter;
+ private String target;
+ private boolean inheritAll;
+ private boolean inheritRefs;
+ private Vector params;
+ private Vector references;
+ private Path currPath;
+ private boolean parallel;
+ private boolean trim;
+ private int maxThreads;
+ private Mapper mapper;
+
+ /***
+ * Default Constructor
+ */
+ public ForEach()
+ {
+ super();
+ this.list = null;
+ this.param = null;
+ this.delimiter = ",";
+ this.target = null;
+ this.inheritAll = false;
+ this.inheritRefs = false;
+ this.params = new Vector();
+ this.references = new Vector();
+ this.parallel = false;
+ this.maxThreads = 5;
+ }
+
+ private void executeParallel(Vector tasks)
+ {
+ ThreadPool pool = new ThreadPool(maxThreads);
+ Enumeration e = tasks.elements();
+ Runnable r = null;
+ Vector threads = new Vector();
+
+ // start each task in it's own thread, using the
+ // pool to ensure that we don't exceed the maximum
+ // amount of threads
+ while (e.hasMoreElements())
+ {
+ // Create the Runnable object
+ final Task task = (Task)e.nextElement();
+ r = new Runnable()
+ {
+ public void run()
+ {
+ task.execute();
+ }
+ };
+
+ // Get a thread, and start the task.
+ // If there is no thread available, this will
+ // block until one becomes available
+ try
+ {
+ ThreadPoolThread tpt = pool.borrowThread();
+ tpt.setRunnable(r);
+ tpt.start();
+ threads.addElement(tpt);
+ }
+ catch (Exception ex)
+ {
+ throw new BuildException(ex);
+ }
+
+ }
+
+ // Wait for all threads to finish before we
+ // are allowed to return.
+ Enumeration te = threads.elements();
+ Thread t= null;
+ while (te.hasMoreElements())
+ {
+ t = (Thread)te.nextElement();
+ if (t.isAlive())
+ {
+ try
+ {
+ t.join();
+ }
+ catch (InterruptedException ex)
+ {
+ throw new BuildException(ex);
+ }
+ }
+ }
+ }
+
+ private void executeSequential(Vector tasks)
+ {
+ TaskContainer tc = (TaskContainer) getProject().createTask("sequential");
+ Enumeration e = tasks.elements();
+ Task t = null;
+ while (e.hasMoreElements())
+ {
+ t = (Task)e.nextElement();
+ tc.addTask(t);
+ }
+
+ ((Task)tc).execute();
+ }
+
+ public void execute()
+ throws BuildException
+ {
+ if (list == null && currPath == null) {
+ throw new BuildException("You must have a list or path to iterate through");
+ }
+ if (param == null)
+ throw new BuildException("You must supply a property name to set on each iteration in param");
+ if (target == null)
+ throw new BuildException("You must supply a target to perform");
+
+ Vector values = new Vector();
+
+ // Take Care of the list attribute
+ if (list != null)
+ {
+ StringTokenizer st = new StringTokenizer(list, delimiter);
+
+ while (st.hasMoreTokens())
+ {
+ String tok = st.nextToken();
+ if (trim) tok = tok.trim();
+ values.addElement(tok);
+ }
+ }
+
+ String[] pathElements = new String[0];
+ if (currPath != null) {
+ pathElements = currPath.list();
+ }
+
+ for (int i=0;i<pathElements.length;i++)
+ {
+ if (mapper != null)
+ {
+ FileNameMapper m = mapper.getImplementation();
+ String mapped[] = m.mapFileName(pathElements[i]);
+ for (int j=0;j<mapped.length;j++)
+ values.addElement(mapped[j]);
+ }
+ else
+ {
+ values.addElement(new File(pathElements[i]));
+ }
+ }
+
+ Vector tasks = new Vector();
+
+ int sz = values.size();
+ CallTarget ct = null;
+ Object val = null;
+ Property p = null;
+
+ for (int i = 0; i < sz; i++) {
+ val = values.elementAt(i);
+ ct = createCallTarget();
+ p = ct.createParam();
+ p.setName(param);
+
+ if (val instanceof File)
+ p.setLocation((File)val);
+ else
+ p.setValue((String)val);
+
+ tasks.addElement(ct);
+ }
+
+ if (parallel && maxThreads > 1)
+ {
+ executeParallel(tasks);
+ }
+ else
+ {
+ executeSequential(tasks);
+ }
+ }
+
+ public void setTrim(boolean trim)
+ {
+ this.trim = trim;
+ }
+
+ public void setList(String list)
+ {
+ this.list = list;
+ }
+
+ public void setDelimiter(String delimiter)
+ {
+ this.delimiter = delimiter;
+ }
+
+ public void setParam(String param)
+ {
+ this.param = param;
+ }
+
+ public void setTarget(String target)
+ {
+ this.target = target;
+ }
+
+ public void setParallel(boolean parallel)
+ {
+ this.parallel = parallel;
+ }
+
+ /**
+ * Corresponds to <code>&lt;antcall&gt;</code>'s <code>inheritall</code>
+ * attribute.
+ */
+ public void setInheritall(boolean b) {
+ this.inheritAll = b;
+ }
+
+ /**
+ * Corresponds to <code>&lt;antcall&gt;</code>'s <code>inheritrefs</code>
+ * attribute.
+ */
+ public void setInheritrefs(boolean b) {
+ this.inheritRefs = b;
+ }
+
+
+ /***
+ * Set the maximum amount of threads we're going to allow
+ * at once to execute
+ * @param maxThreads
+ */
+ public void setMaxThreads(int maxThreads)
+ {
+ this.maxThreads = maxThreads;
+ }
+
+
+ /**
+ * Corresponds to <code>&lt;antcall&gt;</code>'s nested
+ * <code>&lt;param&gt;</code> element.
+ */
+ public void addParam(Property p) {
+ params.addElement(p);
+ }
+
+ /**
+ * Corresponds to <code>&lt;antcall&gt;</code>'s nested
+ * <code>&lt;reference&gt;</code> element.
+ */
+ public void addReference(Ant.Reference r) {
+ references.addElement(r);
+ }
+
+ /**
+ * @deprecated Use createPath instead.
+ */
+ public void addFileset(FileSet set)
+ {
+ log("The nested fileset element is deprectated, use a nested path "
+ + "instead",
+ Project.MSG_WARN);
+ createPath().addFileset(set);
+ }
+
+ public Path createPath() {
+ if (currPath == null) {
+ currPath = new Path(getProject());
+ }
+ return currPath;
+ }
+
+ public Mapper createMapper()
+ {
+ mapper = new Mapper(getProject());
+ return mapper;
+ }
+
+ private CallTarget createCallTarget() {
+ CallTarget ct = (CallTarget) getProject().createTask("antcall");
+ ct.setOwningTarget(getOwningTarget());
+ ct.init();
+ ct.setTarget(target);
+ ct.setInheritAll(inheritAll);
+ ct.setInheritRefs(inheritRefs);
+ Enumeration e = params.elements();
+ while (e.hasMoreElements()) {
+ Property param = (Property) e.nextElement();
+ Property toSet = ct.createParam();
+ toSet.setName(param.getName());
+ if (param.getValue() != null) {
+ toSet.setValue(param.getValue());
+ }
+ if (param.getFile() != null) {
+ toSet.setFile(param.getFile());
+ }
+ if (param.getResource() != null) {
+ toSet.setResource(param.getResource());
+ }
+ if (param.getPrefix() != null) {
+ toSet.setPrefix(param.getPrefix());
+ }
+ if (param.getRefid() != null) {
+ toSet.setRefid(param.getRefid());
+ }
+ if (param.getEnvironment() != null) {
+ toSet.setEnvironment(param.getEnvironment());
+ }
+ if (param.getClasspath() != null) {
+ toSet.setClasspath(param.getClasspath());
+ }
+ }
+
+ e = references.elements();
+ while (e.hasMoreElements()) {
+ ct.addReference((Ant.Reference) e.nextElement());
+ }
+
+ return ct;
+ }
+
+ protected void handleOutput(String line)
+ {
+ try {
+ super.handleOutput(line);
+ }
+ // This is needed so we can run with 1.5 and 1.5.1
+ catch (IllegalAccessError e) {
+ super.handleOutput(line);
+ }
+ }
+
+ protected void handleErrorOutput(String line)
+ {
+ try {
+ super.handleErrorOutput(line);
+ }
+ // This is needed so we can run with 1.5 and 1.5.1
+ catch (IllegalAccessError e) {
+ super.handleErrorOutput(line);
+ }
+ }
+
+}
+
+
diff --git a/ant1.5/src/java/net/sf/antcontrib/logic/IfTask.java b/ant1.5/src/java/net/sf/antcontrib/logic/IfTask.java
new file mode 100644
index 0000000..a343a6a
--- /dev/null
+++ b/ant1.5/src/java/net/sf/antcontrib/logic/IfTask.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.antcontrib.logic;
+
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Sequential;
+import org.apache.tools.ant.taskdefs.condition.Condition;
+import org.apache.tools.ant.taskdefs.condition.ConditionBase;
+
+/**
+ * Perform some tasks based on whether a given condition holds true or
+ * not.
+ *
+ * <p>This task is heavily based on the Condition framework that can
+ * be found in Ant 1.4 and later, therefore it cannot be used in
+ * conjunction with versions of Ant prior to 1.4.</p>
+ *
+ * <p>This task doesn't have any attributes, the condition to test is
+ * specified by a nested element - see the documentation of your
+ * <code>&lt;condition&gt;</code> task (see
+ * <a href="http://jakarta.apache.org/ant/manual/CoreTasks/condition.html">the
+ * online documentation</a> for example) for a complete list of nested
+ * elements.</p>
+ *
+ * <p>Just like the <code>&lt;condition&gt;</code> task, only a single
+ * condition can be specified - you combine them using
+ * <code>&lt;and&gt;</code> or <code>&lt;or&gt;</code> conditions.</p>
+ *
+ * <p>In addition to the condition, you can specify three different
+ * child elements, <code>&lt;elseif&gt;</code>, <code>&lt;then&gt;</code> and
+ * <code>&lt;else&gt;</code>. All three subelements are optional.
+ *
+ * Both <code>&lt;then&gt;</code> and <code>&lt;else&gt;</code> must not be
+ * used more than once inside the if task. Both are
+ * containers for Ant tasks, just like Ant's
+ * <code>&lt;parallel&gt;</code> and <code>&lt;sequential&gt;</code>
+ * tasks - in fact they are implemented using the same class as Ant's
+ * <code>&lt;sequential&gt;</code> task.</p>
+ *
+ * The <code>&lt;elseif&gt;</code> behaves exactly like an <code>&lt;if&gt;</code>
+ * except that it cannot contain the <code>&lt;else&gt;</code> element
+ * inside of it. You may specify as may of these as you like, and the
+ * order they are specified is the order they are evaluated in. If the
+ * condition on the <code>&lt;if&gt;</code> is false, then the first
+ * <code>&lt;elseif&gt;</code> who's conditional evaluates to true
+ * will be executed. The <code>&lt;else&gt;</code> will be executed
+ * only if the <code>&lt;if&gt;</code> and all <code>&lt;elseif&gt;</code>
+ * conditions are false.
+ *
+ * <p>Use the following task to define the <code>&lt;if&gt;</code>
+ * task before you use it the first time:</p>
+ *
+ * <pre><code>
+ * &lt;taskdef name="if" classname="net.sf.antcontrib.logic.IfTask" /&gt;
+ * </code></pre>
+ *
+ * <h3>Crude Example</h3>
+ *
+ * <pre><code>
+ * &lt;if&gt;
+ * &lt;equals arg1=&quot;${foo}&quot; arg2=&quot;bar&quot; /&gt;
+ * &lt;then&gt;
+ * &lt;echo message=&quot;The value of property foo is bar&quot; /&gt;
+ * &lt;/then&gt;
+ * &lt;else&gt;
+ * &lt;echo message=&quot;The value of property foo is not bar&quot; /&gt;
+ * &lt;/else&gt;
+ * &lt;/if&gt;
+ * </code>
+ *
+ * <code>
+ * &lt;if&gt;
+ * &lt;equals arg1=&quot;${foo}&quot; arg2=&quot;bar&quot; /&gt;
+ * &lt;then&gt;
+ * &lt;echo message=&quot;The value of property foo is 'bar'&quot; /&gt;
+ * &lt;/then&gt;
+ *
+ * &lt;elseif&gt;
+ * &lt;equals arg1=&quot;${foo}&quot; arg2=&quot;foo&quot; /&gt;
+ * &lt;then&gt;
+ * &lt;echo message=&quot;The value of property foo is 'foo'&quot; /&gt;
+ * &lt;/then&gt;
+ * &lt;/elseif&gt;
+ *
+ * &lt;else&gt;
+ * &lt;echo message=&quot;The value of property foo is not 'foo' or 'bar'&quot; /&gt;
+ * &lt;/else&gt;
+ * &lt;/if&gt;
+ * </code></pre>
+ *
+ * @author <a href="mailto:[email protected]">Stefan Bodewig</a>
+ * @ant.task name="if"
+ */
+public class IfTask extends ConditionBase {
+
+ public static final class ElseIf
+ extends ConditionBase
+ {
+ private Sequential thenTasks = null;
+
+ public void addThen(Sequential t)
+ {
+ if (thenTasks != null)
+ {
+ throw new BuildException("You must not nest more than one <then> into <elseif>");
+ }
+ thenTasks = t;
+ }
+
+ public boolean eval()
+ throws BuildException
+ {
+ if (countConditions() > 1) {
+ throw new BuildException("You must not nest more than one condition into <elseif>");
+ }
+ if (countConditions() < 1) {
+ throw new BuildException("You must nest a condition into <elseif>");
+ }
+ Condition c = (Condition) getConditions().nextElement();
+
+ return c.eval();
+ }
+
+ public void execute()
+ throws BuildException
+ {
+ if (thenTasks != null)
+ {
+ thenTasks.execute();
+ }
+ }
+ }
+
+ private Sequential thenTasks = null;
+ private Vector elseIfTasks = new Vector();
+ private Sequential elseTasks = null;
+
+ /***
+ * A nested Else if task
+ */
+ public void addElseIf(ElseIf ei)
+ {
+ elseIfTasks.addElement(ei);
+ }
+
+ /**
+ * A nested &lt;then&gt; element - a container of tasks that will
+ * be run if the condition holds true.
+ *
+ * <p>Not required.</p>
+ */
+ public void addThen(Sequential t) {
+ if (thenTasks != null) {
+ throw new BuildException("You must not nest more than one <then> into <if>");
+ }
+ thenTasks = t;
+ }
+
+ /**
+ * A nested &lt;else&gt; element - a container of tasks that will
+ * be run if the condition doesn't hold true.
+ *
+ * <p>Not required.</p>
+ */
+ public void addElse(Sequential e) {
+ if (elseTasks != null) {
+ throw new BuildException("You must not nest more than one <else> into <if>");
+ }
+ elseTasks = e;
+ }
+
+ public void execute() throws BuildException {
+ if (countConditions() > 1) {
+ throw new BuildException("You must not nest more than one condition into <if>");
+ }
+ if (countConditions() < 1) {
+ throw new BuildException("You must nest a condition into <if>");
+ }
+ Condition c = (Condition) getConditions().nextElement();
+ if (c.eval()) {
+ if (thenTasks != null) {
+ thenTasks.execute();
+ }
+ }
+ else
+ {
+ boolean done = false;
+ int sz = elseIfTasks.size();
+ for (int i=0;i<sz && ! done;i++)
+ {
+
+ ElseIf ei = (ElseIf)(elseIfTasks.elementAt(i));
+ if (ei.eval())
+ {
+ done = true;
+ ei.execute();
+ }
+ }
+
+ if (!done && elseTasks != null)
+ {
+ elseTasks.execute();
+ }
+ }
+ }
+}
diff --git a/ant1.5/src/java/net/sf/antcontrib/logic/OutOfDate.java b/ant1.5/src/java/net/sf/antcontrib/logic/OutOfDate.java
new file mode 100644
index 0000000..fcd7f3f
--- /dev/null
+++ b/ant1.5/src/java/net/sf/antcontrib/logic/OutOfDate.java
@@ -0,0 +1,681 @@
+/*
+ * Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.antcontrib.logic;
+
+import java.io.File;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Parallel;
+import org.apache.tools.ant.taskdefs.Sequential;
+import org.apache.tools.ant.taskdefs.condition.Condition;
+import org.apache.tools.ant.types.Mapper;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.util.FileUtils;
+
+import org.apache.tools.ant.types.EnumeratedAttribute;
+
+/**
+* Task to help in calling tasks if generated files are older
+* than source files.
+* Sets a given property or runs an internal task.
+*
+* Based on
+* org.apache.org.apache.tools.ant.taskdefs.UpToDate
+*
+* @author peter reilly
+ * @ant.task name="outofdate"
+*/
+
+public class OutOfDate extends Task implements Condition {
+
+ /**
+ * Enumerated type for collection attribute
+ *
+ * @see EnumeratedAttribute
+ */
+ public static class CollectionEnum extends EnumeratedAttribute {
+ /** Constants for the enumerations */
+ public static final int
+ SOURCES = 0, TARGETS = 1, ALLSOURCES = 2, ALLTARGETS = 3;
+
+ /**
+ * get the values
+ * @return an array of the allowed values for this attribute.
+ */
+ public String[] getValues() {
+ return new String[] {"sources", "targets", "allsources", "alltargets"};
+ }
+ }
+
+ // attributes and nested elements
+ private Task doTask = null;
+ private String property;
+ private String value = "true";
+ private boolean force = false;
+ private int verbosity = Project.MSG_VERBOSE;
+ private Vector mappers = new Vector();
+ private Path targetpaths = null;
+ private Path sourcepaths = null;
+ private String outputSources = null;
+ private String outputSourcesPath = null;
+ private String outputTargets = null;
+ private String outputTargetsPath = null;
+ private String allTargets = null;
+ private String allTargetsPath = null;
+ private String separator = " ";
+ private DeleteTargets deleteTargets = null;
+ private int collection = CollectionEnum.SOURCES;
+
+ // variables
+ private Hashtable targetSet = new Hashtable();
+ private Hashtable sourceSet = new Hashtable();
+ private Hashtable allTargetSet = new Hashtable();
+ private Hashtable allSourceSet = new Hashtable();
+
+ /**
+ * Set the collection attribute, controls what is
+ * returned by the iterator method.
+ * <dl>
+ * <li>"sources" the sources that are newer than the corresponding targets.</li>
+ * <li>"targets" the targets that are older or not present than the corresponding
+ * sources.</li>
+ * <li>"allsources" all the sources</li>
+ * <li>"alltargets" all the targets</li>
+ * </dl>
+ * @param collection "sources" the changes
+ */
+ public void setCollection(CollectionEnum collection) {
+ this.collection = collection.getIndex();
+ }
+
+ /**
+ * Defines the FileNameMapper to use (nested mapper element).
+ * @return Mappper to be configured
+ */
+ public Mapper createMapper() {
+ MyMapper mapper = new MyMapper(getProject());
+ mappers.addElement(mapper);
+ return mapper;
+ }
+
+ /**
+ * The property to set if any of the target files are outofdate with
+ * regard to any of the source files.
+ *
+ * @param property the name of the property to set if Target is outofdate.
+ */
+ public void setProperty(String property) {
+ this.property = property;
+ }
+
+ /**
+ * The separator to use to separate the files
+ * @param separator separator used in outout properties
+ */
+
+ public void setSeparator(String separator) {
+ this.separator = separator;
+ }
+
+ /**
+ * The value to set the named property to the target files
+ * are outofdate
+ *
+ * @param value the value to set the property
+ */
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ /**
+ * whether to allways be outofdate
+ * @param force true means that outofdate is always set, default
+ * false
+ */
+ public void setForce(boolean force) {
+ this.force = force;
+ }
+
+ /**
+ * whether to have verbose output
+ * @param verbose true means that outofdate outputs debug info
+ */
+ public void setVerbose(boolean verbose) {
+ if (verbose) {
+ this.verbosity = Project.MSG_INFO;
+ } else {
+ this.verbosity = Project.MSG_VERBOSE;
+ }
+ }
+
+ /**
+ * Add to the target files
+ *
+ * @return a path to be configured
+ */
+ public Path createTargetfiles() {
+ if (targetpaths == null) {
+ targetpaths = new Path(getProject());
+ }
+ return targetpaths;
+ }
+
+ /**
+ * Add to the source files
+ *
+ * @return a path to be configured
+ */
+ public Path createSourcefiles() {
+ if (sourcepaths == null) {
+ sourcepaths = new Path(getProject());
+ }
+ return sourcepaths;
+ }
+
+ /**
+ * A property to contain the output source files
+ *
+ * @param outputSources the name of the property
+ */
+ public void setOutputSources(String outputSources) {
+ this.outputSources = outputSources;
+ }
+
+ /**
+ * A property to contain the output target files
+ *
+ * @param outputTargets the name of the property
+ */
+ public void setOutputTargets(String outputTargets) {
+ this.outputTargets = outputTargets;
+ }
+
+ /**
+ * A reference to contain the path of target files that
+ * are outofdate
+ *
+ * @param outputTargetsPath the name of the reference
+ */
+ public void setOutputTargetsPath(String outputTargetsPath) {
+ this.outputTargetsPath = outputTargetsPath;
+ }
+
+ /**
+ * A refernce to contain the path of all the targets
+ *
+ * @param allTargetsPath the name of the reference
+ */
+ public void setAllTargetsPath(String allTargetsPath) {
+ this.allTargetsPath = allTargetsPath;
+ }
+
+ /**
+ * A property to contain all the target filenames
+ *
+ * @param allTargets the name of the property
+ */
+ public void setAllTargets(String allTargets) {
+ this.allTargets = allTargets;
+ }
+
+ /**
+ * A reference to the path containing all the sources files.
+ *
+ * @param outputSourcesPath the name of the reference
+ */
+ public void setOutputSourcesPath(String outputSourcesPath) {
+ this.outputSourcesPath = outputSourcesPath;
+ }
+
+ /**
+ * optional nested delete element
+ * @return an element to be configured
+ */
+ public DeleteTargets createDeleteTargets() {
+ deleteTargets = new DeleteTargets();
+ return deleteTargets;
+ }
+
+ /**
+ * Embedded do parallel
+ * @param doTask the parallel to embed
+ */
+ public void addParallel(Parallel doTask) {
+ if (this.doTask != null) {
+ throw new BuildException(
+ "You must not nest more that one <parallel> or <sequential>"
+ + " into <outofdate>");
+ }
+ this.doTask = doTask;
+ }
+
+ /**
+ * Embedded do sequential.
+ * @param doTask the sequential to embed
+ */
+ public void addSequential(Sequential doTask) {
+ if (this.doTask != null) {
+ throw new BuildException(
+ "You must not nest more that one <parallel> or <sequential>"
+ + " into <outofdate>");
+ }
+ this.doTask = doTask;
+ }
+
+ /**
+ * Evaluate (all) target and source file(s) to
+ * see if the target(s) is/are outoutdate.
+ * @return true if any of the targets are outofdate
+ */
+ public boolean eval() {
+ boolean ret = false;
+ FileUtils fileUtils = FileUtils.newFileUtils();
+ if (sourcepaths == null) {
+ throw new BuildException(
+ "You must specify a <sourcefiles> element.");
+ }
+
+ if (targetpaths == null && mappers.size() == 0) {
+ throw new BuildException(
+ "You must specify a <targetfiles> or <mapper> element.");
+ }
+
+ // Source Paths
+ String[] spaths = sourcepaths.list();
+
+ for (int i = 0; i < spaths.length; i++) {
+ File sourceFile = new File(spaths[i]);
+ if (!sourceFile.exists()) {
+ throw new BuildException(sourceFile.getAbsolutePath()
+ + " not found.");
+ }
+ }
+
+ // Target Paths
+
+ if (targetpaths != null) {
+ String[] paths = targetpaths.list();
+ if (paths.length == 0) {
+ ret = true;
+ }
+ else {
+ for (int i = 0; i < paths.length; ++i) {
+ if (targetNeedsGen(paths[i], spaths)) {
+ ret = true;
+ }
+ }
+ }
+ }
+
+ // Mapper Paths
+ for (Enumeration e = mappers.elements(); e.hasMoreElements();) {
+ MyMapper mapper = (MyMapper) e.nextElement();
+
+ File relativeDir = mapper.getDir();
+ File baseDir = new File(getProject().getProperty("basedir"));
+ if (relativeDir == null) {
+ relativeDir = baseDir;
+ }
+ String[] rpaths = new String[spaths.length];
+ for (int i = 0; i < spaths.length; ++i) {
+ rpaths[i] = fileUtils.removeLeadingPath(relativeDir, new File(spaths[i]));
+ }
+
+ FileNameMapper fileNameMapper = mapper.getImplementation();
+ for (int i = 0; i < spaths.length; ++i) {
+ String[] mapped = fileNameMapper.mapFileName(rpaths[i]);
+ if (mapped != null) {
+ for (int j = 0; j < mapped.length; ++j) {
+ if (outOfDate(new File(spaths[i]),
+ fileUtils.resolveFile(
+ baseDir, mapped[j]))) {
+ ret = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (allTargets != null) {
+ this.getProject().setNewProperty(
+ allTargets, setToString(allTargetSet));
+ }
+
+ if (allTargetsPath != null) {
+ this.getProject().addReference(
+ allTargetsPath, setToPath(allTargetSet));
+ }
+
+ if (outputSources != null) {
+ this.getProject().setNewProperty(
+ outputSources, setToString(sourceSet));
+ }
+
+ if (outputTargets != null) {
+ this.getProject().setNewProperty(
+ outputTargets, setToString(targetSet));
+ }
+
+ if (outputSourcesPath != null) {
+ this.getProject().addReference(
+ outputSourcesPath, setToPath(sourceSet));
+ }
+
+ if (outputTargetsPath != null) {
+ this.getProject().addReference(
+ outputTargetsPath, setToPath(targetSet));
+ }
+
+ if (force) {
+ ret = true;
+ }
+
+ if (ret && deleteTargets != null) {
+ deleteTargets.execute();
+ }
+
+ if (ret) {
+ if (property != null) {
+ this.getProject().setNewProperty(property, value);
+ }
+ }
+
+ return ret;
+ }
+
+ private boolean targetNeedsGen(String target, String[] spaths) {
+ boolean ret = false;
+ File targetFile = new File(target);
+ for (int i = 0; i < spaths.length; i++) {
+ if (outOfDate(new File(spaths[i]), targetFile)) {
+ ret = true;
+ }
+ }
+ // Special case : there are no source files, make sure the
+ // targets exist
+ if (spaths.length == 0) {
+ if (outOfDate(null, targetFile)) {
+ ret = true;
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Call evalute and return an iterator over the result
+ * @return an iterator over the result
+ */
+ public Iterator iterator() {
+ // Perhaps should check the result and return
+ // an empty set if it returns false
+ eval();
+
+ switch (collection) {
+ case CollectionEnum.SOURCES:
+ return sourceSet.values().iterator();
+ case CollectionEnum.TARGETS:
+ return targetSet.values().iterator();
+ case CollectionEnum.ALLSOURCES:
+ return allSourceSet.values().iterator();
+ case CollectionEnum.ALLTARGETS:
+ return allTargetSet.values().iterator();
+ default:
+ return sourceSet.values().iterator();
+ }
+ }
+
+ /**
+ * Sets property to true and/or executes embedded do
+ * if any of the target file(s) do not have a more recent timestamp
+ * than (each of) the source file(s).
+ */
+ public void execute() {
+ if (!eval()) {
+ return;
+ }
+
+ if (doTask != null) {
+ doTask.perform();
+ }
+
+ }
+
+
+ private boolean outOfDate(File sourceFile, File targetFile) {
+ boolean ret = false;
+ if (sourceFile != null) {
+ allSourceSet.put(sourceFile, sourceFile);
+ }
+ allTargetSet.put(targetFile, targetFile);
+ if (!targetFile.exists()) {
+ ret = true;
+ }
+ if ((!ret) && (sourceFile != null)) {
+ ret = sourceFile.lastModified() > targetFile.lastModified();
+ }
+ if (ret) {
+ if ((sourceFile != null && sourceSet.get(sourceFile) == null)
+ || targetSet.get(targetFile) == null) {
+ log("SourceFile " + sourceFile + " outofdate "
+ + "with regard to " + targetFile, verbosity);
+ }
+ if (sourceFile != null) {
+ sourceSet.put(sourceFile, sourceFile);
+ }
+ targetSet.put(targetFile, targetFile);
+ }
+ return ret;
+ }
+
+ private String setToString(Hashtable set) {
+ StringBuffer b = new StringBuffer();
+ for (Enumeration e = set.keys(); e.hasMoreElements();) {
+ File v = (File) e.nextElement();
+ if (b.length() != 0) {
+ b.append(separator);
+ }
+ String s = v.getAbsolutePath();
+ // DOTO: The following needs more work!
+ // Handle paths contains sep
+ if (s.indexOf(separator) != -1) {
+ if (s.indexOf("\"") != -1) {
+ s = "'" + s + "'";
+ } else {
+ s = "\"" + s + "\"";
+ }
+ }
+ b.append(s);
+ }
+ return b.toString();
+ }
+
+ private Path setToPath(Hashtable set) {
+ Path ret = new Path(getProject());
+ for (Enumeration e = set.keys(); e.hasMoreElements();) {
+ File v = (File) e.nextElement();
+ Path.PathElement el = ret.createPathElement();
+ el.setLocation(v);
+ }
+ return ret;
+ }
+
+ /**
+ * nested delete targets
+ */
+ public class DeleteTargets {
+ private boolean all = false;
+ private boolean quiet = false;
+ private boolean failOnError = false;
+
+ private int myLogging = Project.MSG_INFO;
+
+ /**
+ * whether to delete all the targets
+ * or just those that are newer than the
+ * corresponding sources.
+ * @param all true to delete all, default false
+ */
+ public void setAll(boolean all) {
+ this.all = all;
+ }
+
+ /**
+ * @param quiet if true suppress messages on deleting files
+ */
+ public void setQuiet(boolean quiet) {
+ this.quiet = quiet;
+ myLogging = quiet ? Project.MSG_VERBOSE : Project.MSG_INFO;
+ }
+
+ /**
+ * @param failOnError if true halt if there is a failure to delete
+ */
+ public void setFailOnError(boolean failOnError) {
+ this.failOnError = failOnError;
+ }
+
+ private void execute() {
+ if (myLogging != Project.MSG_INFO) {
+ myLogging = verbosity;
+ }
+
+ // Quiet overrides failOnError
+ if (quiet) {
+ failOnError = false;
+ }
+
+ Path toBeDeleted = null;
+ if (all) {
+ toBeDeleted = setToPath(allTargetSet);
+ } else {
+ toBeDeleted = setToPath(targetSet);
+ }
+
+ String[] names = toBeDeleted.list();
+ for (int i = 0; i < names.length; ++i) {
+ File file = new File(names[i]);
+ if (!file.exists()) {
+ continue;
+ }
+ if (file.isDirectory()) {
+ removeDir(file);
+ continue;
+ }
+ log("Deleting " + file.getAbsolutePath(), myLogging);
+ if (!file.delete()) {
+ String message =
+ "Unable to delete file " + file.getAbsolutePath();
+ if (failOnError) {
+ throw new BuildException(message);
+ } else {
+ log(message, myLogging);
+ }
+ }
+ }
+ }
+
+ private static final int DELETE_RETRY_SLEEP_MILLIS = 10;
+ /**
+ * Attempt to fix possible race condition when deleting
+ * files on WinXP. If the delete does not work,
+ * wait a little and try again.
+ */
+ private boolean delete(File f) {
+ if (!f.delete()) {
+ try {
+ Thread.sleep(DELETE_RETRY_SLEEP_MILLIS);
+ return f.delete();
+ } catch (InterruptedException ex) {
+ return f.delete();
+ }
+ }
+ return true;
+ }
+
+ private void removeDir(File d) {
+ String[] list = d.list();
+ if (list == null) {
+ list = new String[0];
+ }
+ for (int i = 0; i < list.length; i++) {
+ String s = list[i];
+ File f = new File(d, s);
+ if (f.isDirectory()) {
+ removeDir(f);
+ } else {
+ log("Deleting " + f.getAbsolutePath(), myLogging);
+ if (!f.delete()) {
+ String message = "Unable to delete file "
+ + f.getAbsolutePath();
+ if (failOnError) {
+ throw new BuildException(message);
+ } else {
+ log(message, myLogging);
+ }
+ }
+ }
+ }
+ log("Deleting directory " + d.getAbsolutePath(), myLogging);
+ if (!delete(d)) {
+ String message = "Unable to delete directory "
+ + d.getAbsolutePath();
+ if (failOnError) {
+ throw new BuildException(message);
+ } else {
+ log(message, myLogging);
+ }
+ }
+ }
+ }
+
+ /**
+ * Wrapper for mapper - includes dir
+ */
+ public static class MyMapper extends Mapper {
+ private File dir = null;
+ /**
+ * Creates a new <code>MyMapper</code> instance.
+ *
+ * @param project the current project
+ */
+ public MyMapper(Project project) {
+ super(project);
+ }
+
+ /**
+ * @param dir the directory that the from files are relative to
+ */
+ public void setDir(File dir) {
+ this.dir = dir;
+ }
+
+ /**
+ * @return the directory that the from files are relative to
+ */
+ public File getDir() {
+ return dir;
+ }
+ }
+}
+
+
diff --git a/ant1.5/src/java/net/sf/antcontrib/logic/Relentless.java b/ant1.5/src/java/net/sf/antcontrib/logic/Relentless.java
new file mode 100644
index 0000000..d750b61
--- /dev/null
+++ b/ant1.5/src/java/net/sf/antcontrib/logic/Relentless.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2004-2005 Ant-Contrib project. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.antcontrib.logic;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.TaskContainer;
+
+import java.util.Iterator;
+import java.util.Vector;
+
+/** Relentless is an Ant task that will relentlessly execute other tasks,
+ * ignoring any failures until all tasks have completed. If any of the
+ * executed tasks fail, then Relentless will fail; otherwise it will succeed.
+ *
+ * @author Christopher Heiny
+ * @version $Id: Relentless.java 12 2006-08-09 17:48:45Z mattinger $
+ * @ant.task name="relentless"
+ */
+public class Relentless extends Task implements TaskContainer {
+ /** We keep the list of tasks we will execute here.
+ */
+ private Vector taskList = new Vector();
+
+ /** Flag indicating how much output to generate.
+ */
+ private boolean terse = false;
+
+ /** Creates a new Relentless task. */
+ public Relentless() {
+ }
+
+ /** This method will be called when it is time to execute the task.
+ */
+ public void execute() throws BuildException {
+ int failCount = 0;
+ int taskNo = 0;
+ if ( taskList.size() == 0 ) {
+ throw new BuildException( "No tasks specified for <relentless>." );
+ }
+ log("Relentlessly executing: " + this.getDescription());
+ Iterator iter = taskList.iterator();
+ while ( iter.hasNext() ) {
+ Task t = (Task) iter.next();
+ taskNo++;
+ String desc = t.getDescription();
+ if ( desc == null ) {
+ desc = "task " + taskNo;
+ }
+ if (!terse) log("Executing: " + desc);
+ try {
+ t.perform();
+ } catch (BuildException x) {
+ log("Task " + desc + " failed: " + x.getMessage());
+ failCount++;
+ }
+ }
+ if ( failCount > 0 ) {
+ throw new BuildException( "Relentless execution: " + failCount + " of " + taskList.size() + " tasks failed." );
+ }
+ else {
+ log("All tasks completed successfully.");
+ }
+ }
+
+ /** Ant will call this to inform us of nested tasks.
+ */
+ public void addTask(org.apache.tools.ant.Task task) {
+ taskList.add(task);
+ }
+
+ /** Set this to true to reduce the amount of output generated.
+ */
+ public void setTerse(boolean terse) {
+ this.terse = terse;
+ }
+
+ /** Retrieve the terse property, indicating how much output we will generate.
+ */
+ public boolean isTerse() {
+ return terse;
+ }
+
+}
diff --git a/ant1.5/src/java/net/sf/antcontrib/logic/RunTargetTask.java b/ant1.5/src/java/net/sf/antcontrib/logic/RunTargetTask.java
new file mode 100644
index 0000000..4549a2f
--- /dev/null
+++ b/ant1.5/src/java/net/sf/antcontrib/logic/RunTargetTask.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.antcontrib.logic;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+/**
+ * Ant task that runs a target without creating a new project.
+ *
+ * @author Nicola Ken Barozzi [email protected]
+ * @ant.task name="runtarget"
+ */
+public class RunTargetTask extends Task {
+
+ private String target = null;
+
+ /**
+ * The target attribute
+ *
+ * @param target the name of a target to execute
+ */
+ public void setTarget(String target) {
+ this.target = target;
+ }
+
+ /**
+ * execute the target
+ *
+ * @exception BuildException if a target is not specified
+ */
+ public void execute() throws BuildException {
+ if (target == null) {
+ throw new BuildException("target property required");
+ }
+
+ getProject().executeTarget(target);
+ }
+}
diff --git a/ant1.5/src/java/net/sf/antcontrib/logic/Switch.java b/ant1.5/src/java/net/sf/antcontrib/logic/Switch.java
new file mode 100644
index 0000000..2534f77
--- /dev/null
+++ b/ant1.5/src/java/net/sf/antcontrib/logic/Switch.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.antcontrib.logic;
+
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Sequential;
+
+/***
+ * Task definition for the ANT task to switch on a particular value.
+ *
+ * <pre>
+ *
+ * Usage:
+ *
+ * Task declaration in the project:
+ * <code>
+ * &lt;taskdef name="switch" classname="net.sf.antcontrib.logic.Switch" /&gt;
+ * </code>
+ *
+ * Task calling syntax:
+ * <code>
+ * &lt;switch value="value" [caseinsensitive="true|false"] &gt;
+ * &lt;case value="val"&gt;
+ * &lt;property name="propname" value="propvalue" /&gt; |
+ * &lt;antcall target="targetname" /&gt; |
+ * any other tasks
+ * &lt;/case&gt;
+ * [
+ * &lt;default&gt;
+ * &lt;property name="propname" value="propvalue" /&gt; |
+ * &lt;antcall target="targetname" /&gt; |
+ * any other tasks
+ * &lt;/default&gt;
+ * ]
+ * &lt;/switch&gt;
+ * </code>
+ *
+ *
+ * Attributes:
+ * value -&gt; The value to switch on
+ * caseinsensitive -&gt; Should we do case insensitive comparisons?
+ * (default is false)
+ *
+ * Subitems:
+ * case --&gt; An individual case to consider, if the value that
+ * is being switched on matches to value attribute of
+ * the case, then the nested tasks will be executed.
+ * default --&gt; The default case for when no match is found.
+ *
+ *
+ * Crude Example:
+ *
+ * <code>
+ * &lt;switch value=&quot;${foo}&quot;&gt;
+ * &lt;case value=&quot;bar&quot;&gt;
+ * &lt;echo message=&quot;The value of property foo is bar&quot; /&gt;
+ * &lt;/case&gt;
+ * &lt;case value=&quot;baz&quot;&gt;
+ * &lt;echo message=&quot;The value of property foo is baz&quot; /&gt;
+ * &lt;/case&gt;
+ * &lt;default&gt;
+ * &lt;echo message=&quot;The value of property foo is not sensible&quot; /&gt;
+ * &lt;/default&gt;
+ * &lt;/switch&gt;
+ * </code>
+ *
+ * </pre>
+ *
+ * @author <a href="mailto:[email protected]">Matthew Inger</a>
+ * @author <a href="mailto:[email protected]">Stefan Bodewig</a>
+ * @ant.task name="switch"
+ */
+public class Switch extends Task
+{
+ private String value;
+ private Vector cases;
+ private Sequential defaultCase;
+ private boolean caseInsensitive;
+
+ /***
+ * Default Constructor
+ */
+ public Switch()
+ {
+ cases = new Vector();
+ }
+
+ public void execute()
+ throws BuildException
+ {
+ if (value == null)
+ throw new BuildException("Value is missing");
+ if (cases.size() == 0 && defaultCase == null)
+ throw new BuildException("No cases supplied");
+
+ Sequential selectedCase = defaultCase;
+
+ int sz = cases.size();
+ for (int i=0;i<sz;i++)
+ {
+ Case c = (Case)(cases.elementAt(i));
+
+ String cvalue = c.value;
+ if (cvalue == null) {
+ throw new BuildException("Value is required for case.");
+ }
+ String mvalue = value;
+
+ if (caseInsensitive)
+ {
+ cvalue = cvalue.toUpperCase();
+ mvalue = mvalue.toUpperCase();
+ }
+
+ if (cvalue.equals(mvalue) && c != defaultCase)
+ selectedCase = c;
+ }
+
+ if (selectedCase == null) {
+ throw new BuildException("No case matched the value " + value
+ + " and no default has been specified.");
+ }
+ selectedCase.perform();
+ }
+
+ /***
+ * Sets the value being switched on
+ */
+ public void setValue(String value)
+ {
+ this.value = value;
+ }
+
+ public void setCaseInsensitive(boolean c)
+ {
+ caseInsensitive = c;
+ }
+
+ public final class Case extends Sequential
+ {
+ private String value;
+
+ public Case()
+ {
+ super();
+ }
+
+ public void setValue(String value)
+ {
+ this.value = value;
+ }
+
+ public void execute()
+ throws BuildException
+ {
+ super.execute();
+ }
+
+ public boolean equals(Object o)
+ {
+ boolean res = false;
+ Case c = (Case)o;
+ if (c.value.equals(value))
+ res = true;
+ return res;
+ }
+ }
+
+ /***
+ * Creates the &lt;case&gt; tag
+ */
+ public Switch.Case createCase()
+ throws BuildException
+ {
+ Switch.Case res = new Switch.Case();
+ cases.addElement(res);
+ return res;
+ }
+
+ /***
+ * Creates the &lt;default&gt; tag
+ */
+ public void addDefault(Sequential res)
+ throws BuildException
+ {
+ if (defaultCase != null)
+ throw new BuildException("Cannot specify multiple default cases");
+
+ defaultCase = res;
+ }
+
+}
diff --git a/ant1.5/src/java/net/sf/antcontrib/logic/Throw.java b/ant1.5/src/java/net/sf/antcontrib/logic/Throw.java
new file mode 100644
index 0000000..94470d0
--- /dev/null
+++ b/ant1.5/src/java/net/sf/antcontrib/logic/Throw.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.antcontrib.logic;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Exit;
+import org.apache.tools.ant.types.Reference;
+
+/**
+ * Extension of <code>&lt;fail&gt;</code> that can throw an exception
+ * that is a reference in the project.
+ *
+ * <p>This may be useful inside the <code>&lt;catch&gt;</code> block
+ * of a <code>&lt;trycatch&gt;</code> task if you want to rethrow the
+ * exception just caught.</p>
+ * @ant.task name="throw"
+ */
+public class Throw extends Exit {
+
+ private Reference ref;
+
+ /**
+ * The reference that points to a BuildException.
+ */
+ public void setRefid(Reference ref) {
+ this.ref = ref;
+ }
+
+ public void execute() throws BuildException {
+ Object reffed = ref != null
+ ? ref.getReferencedObject(getProject())
+ : null;
+ if (reffed != null && reffed instanceof BuildException) {
+ throw (BuildException) reffed;
+ }
+ super.execute();
+ }
+}
diff --git a/ant1.5/src/java/net/sf/antcontrib/logic/TimestampSelector.java b/ant1.5/src/java/net/sf/antcontrib/logic/TimestampSelector.java
new file mode 100644
index 0000000..315d9ac
--- /dev/null
+++ b/ant1.5/src/java/net/sf/antcontrib/logic/TimestampSelector.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.antcontrib.logic;
+
+import java.io.File;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+
+
+/***
+ *
+ * <pre>
+ *
+ * Usage:
+ *
+ * Task declaration in the project:
+ * <code>
+ * &lt;taskdef name="latesttimestamp" classname="net.sf.antcontrib.logic.TimestampSelector" /&gt;
+ * </code>
+ *
+ * Call Syntax:
+ * <code>
+ * &lt;timestampselector
+ * [property="prop" | outputsetref="id"]
+ * [count="num"]
+ * [age="eldest|youngest"]
+ * [pathSep=","]
+ * [pathref="ref"] &gt;
+ * &lt;path&gt;
+ * ...
+ * &lt;/path&gt;
+ * &lt;/latesttimestamp&gt;
+ * </code>
+ *
+ * Attributes:
+ * outputsetref --> The reference of the output Path set which will contain the
+ * files with the latest timestamps.
+ * property --> The name of the property to set with file having the latest
+ * timestamp. If you specify the "count" attribute, you will get
+ * the lastest N files. These will be the absolute pathnames
+ * count --> How many of the latest files do you wish to find
+ * pathSep --> What to use as the path separator when using the "property"
+ * attribute, in conjunction with the "count" attribute
+ * pathref --> The reference of the path which is the input set of files.
+ *
+ * </pre>
+ * @author <a href="mailto:[email protected]">Matthew Inger</a>
+ * @ant.task name="timestampselector"
+ */
+public class TimestampSelector extends Task
+{
+ private static final String AGE_ELDEST = "eldest";
+ private static final String AGE_YOUNGEST = "youngest";
+
+ private String property;
+ private Path path;
+ private String outputSetId;
+ private int count = 1;
+ private char pathSep = ',';
+ private String age = AGE_YOUNGEST;
+
+
+ /***
+ * Default Constructor
+ */
+ public TimestampSelector()
+ {
+ super();
+ }
+
+
+ public void doFileSetExecute(String paths[])
+ throws BuildException
+ {
+
+ }
+
+ // Sorts entire array
+ public void sort(Vector array)
+ {
+ sort(array, 0, array.size() - 1);
+ }
+
+ // Sorts partial array
+ protected void sort(Vector array, int start, int end)
+ {
+ int p;
+ if (end > start)
+ {
+ p = partition(array, start, end);
+ sort(array, start, p-1);
+ sort(array, p+1, end);
+ }
+ }
+
+ protected int compare(File a, File b)
+ {
+ if (age.equalsIgnoreCase(AGE_ELDEST))
+ return new Long(a.lastModified()).compareTo(new Long(b.lastModified()));
+ else
+ return new Long(b.lastModified()).compareTo(new Long(a.lastModified()));
+ }
+
+ protected int partition(Vector array, int start, int end)
+ {
+ int left, right;
+ File partitionElement;
+
+ partitionElement = (File)array.elementAt(end);
+
+ left = start - 1;
+ right = end;
+ for (;;)
+ {
+ while (compare(partitionElement, (File)array.elementAt(++left)) == 1)
+ {
+ if (left == end) break;
+ }
+ while (compare(partitionElement, (File)array.elementAt(--right)) == -1)
+ {
+ if (right == start) break;
+ }
+ if (left >= right) break;
+ swap(array, left, right);
+ }
+ swap(array, left, end);
+
+ return left;
+ }
+
+ protected void swap(Vector array, int i, int j)
+ {
+ Object temp;
+
+ temp = array.elementAt(i);
+ array.setElementAt(array.elementAt(j), i);
+ array.setElementAt(temp, j);
+ }
+
+ public void execute()
+ throws BuildException
+ {
+ if (property == null && outputSetId == null)
+ throw new BuildException("Property or OutputSetId must be specified.");
+ if (path == null)
+ throw new BuildException("A path element or pathref attribute must be specified.");
+
+ // Figure out the list of existing file elements
+ // from the designated path
+ String s[] = path.list();
+ Vector v = new Vector();
+ for (int i=0;i<s.length;i++)
+ {
+ File f = new File(s[i]);
+ if (f.exists())
+ v.addElement(f);
+ }
+
+ // Sort the vector, need to make java 1.1 compliant
+ sort(v);
+
+ // Pull off the first N items
+ Vector v2 = new Vector();
+ int sz = v.size();
+ for (int i=0;i<sz && i<count;i++)
+ v2.add(v.elementAt(i));
+
+
+
+
+ // Build the resulting Path object
+ Path path = new Path(getProject());
+ sz = v2.size();
+ for (int i=0;i<sz;i++)
+ {
+ File f = (File)(v.elementAt(i));
+ Path p = new Path(getProject(), f.getAbsolutePath());
+ path.addExisting(p);
+ }
+
+
+ if (outputSetId != null)
+ {
+ // Add the reference to the project
+ getProject().addReference(outputSetId, path);
+ }
+ else
+ {
+ // Concat the paths, and put them in a property
+ // which is separated list of the files, using the
+ // "pathSep" attribute as the separator
+ String paths[] = path.list();
+ StringBuffer sb = new StringBuffer();
+ for (int i=0;i<paths.length;i++)
+ {
+ if (i != 0) sb.append(pathSep);
+ sb.append(paths[i]);
+ }
+
+ if (paths.length != 0)
+ getProject().setProperty(property, sb.toString());
+ }
+ }
+
+
+ public void setProperty(String property)
+ {
+ if (outputSetId != null)
+ throw new BuildException("Cannot set both Property and OutputSetId.");
+
+ this.property = property;
+ }
+
+ public void setCount(int count)
+ {
+ this.count = count;
+ }
+
+ public void setAge(String age)
+ {
+ if (age.equalsIgnoreCase(AGE_ELDEST) ||
+ age.equalsIgnoreCase(AGE_YOUNGEST))
+ this.age = age;
+ else
+ throw new BuildException("Invalid age: " + age);
+ }
+
+ public void setPathSep(char pathSep)
+ {
+ this.pathSep = pathSep;
+ }
+
+ public void setOutputSetId(String outputSetId)
+ {
+ if (property != null)
+ throw new BuildException("Cannot set both Property and OutputSetId.");
+ this.outputSetId = outputSetId;
+ }
+
+ public void setPathRef(Reference ref)
+ throws BuildException
+ {
+ if (path == null)
+ {
+ path = new Path(getProject());
+ path.setRefid(ref);
+ }
+ else
+ {
+ throw new BuildException("Path element already specified.");
+ }
+ }
+
+
+ public Path createPath()
+ throws BuildException
+ {
+ if (path == null)
+ path = new Path(getProject());
+ else
+ throw new BuildException("Path element already specified.");
+ return path;
+ }
+
+}
+
+
diff --git a/ant1.5/src/java/net/sf/antcontrib/logic/TryCatchTask.java b/ant1.5/src/java/net/sf/antcontrib/logic/TryCatchTask.java
new file mode 100644
index 0000000..a40f6f7
--- /dev/null
+++ b/ant1.5/src/java/net/sf/antcontrib/logic/TryCatchTask.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.antcontrib.logic;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Sequential;
+
+/**
+ * A wrapper that lets you run a set of tasks and optionally run a
+ * different set of tasks if the first set fails and yet another set
+ * after the first one has finished.
+ *
+ * <p>This mirrors Java's try/catch/finally.</p>
+ *
+ * <p>The tasks inside of the required <code>&lt;try&gt;</code>
+ * element will be run. If one of them should throw a {@link
+ * org.apache.tools.ant.BuildException BuildException} several things
+ * can happen:</p>
+ *
+ * <ul>
+ * <li>If there is no <code>&lt;catch&gt;</code> block, the
+ * exception will be passed through to Ant.</li>
+ *
+ * <li>If the property attribute has been set, a property of the
+ * given name will be set to the message of the exception.</li>
+ *
+ * <li>If the reference attribute has been set, a reference of the
+ * given id will be created and point to the exception object.</li>
+ *
+ * <li>If there is a <code>&lt;catch&gt;</code> block, the tasks
+ * nested into it will be run.</li>
+ * </ul>
+ *
+ * <p>If a <code>&lt;finally&gt;</code> block is present, the task
+ * nested into it will be run, no matter whether the first tasks have
+ * thrown an exception or not.</p>
+ *
+ * <p><strong>Attributes:</strong></p>
+ *
+ * <table>
+ * <tr>
+ * <td>Name</td>
+ * <td>Description</td>
+ * <td>Required</td>
+ * </tr>
+ * <tr>
+ * <td>property</td>
+ * <td>Name of a property that will receive the message of the
+ * exception that has been caught (if any)</td>
+ * <td>No</td>
+ * </tr>
+ * <tr>
+ * <td>reference</td>
+ * <td>Id of a reference that will point to the exception object
+ * that has been caught (if any)</td>
+ * <td>No</td>
+ * </tr>
+ * </table>
+ *
+ * <p>Use the following task to define the <code>&lt;trycatch&gt;</code>
+ * task before you use it the first time:</p>
+ *
+ * <pre><code>
+ * &lt;taskdef name="trycatch"
+ * classname="net.sf.antcontrib.logic.TryCatchTask" /&gt;
+ * </code></pre>
+ *
+ * <h3>Crude Example</h3>
+ *
+ * <pre><code>
+ * &lt;trycatch property=&quot;foo&quot; reference=&quot;bar&quot;&gt;
+ * &lt;try&gt;
+ * &lt;fail&gt;Tada!&lt;/fail&gt;
+ * &lt;/try&gt;
+ *
+ * &lt;catch&gt;
+ * &lt;echo&gt;In &amp;lt;catch&amp;gt;.&lt;/echo&gt;
+ * &lt;/catch&gt;
+ *
+ * &lt;finally&gt;
+ * &lt;echo&gt;In &amp;lt;finally&amp;gt;.&lt;/echo&gt;
+ * &lt;/finally&gt;
+ * &lt;/trycatch&gt;
+ *
+ * &lt;echo&gt;As property: ${foo}&lt;/echo&gt;
+ * &lt;property name=&quot;baz&quot; refid=&quot;bar&quot; /&gt;
+ * &lt;echo&gt;From reference: ${baz}&lt;/echo&gt;
+ * </code></pre>
+ *
+ * <p>results in</p>
+ *
+ * <pre><code>
+ * [trycatch] Caught exception: Tada!
+ * [echo] In &lt;catch&gt;.
+ * [echo] In &lt;finally&gt;.
+ * [echo] As property: Tada!
+ * [echo] From reference: Tada!
+ * </code></pre>
+ *
+ * @author <a href="mailto:[email protected]">Stefan Bodewig</a>
+ * @author <a href="mailto:[email protected]">Dan Ritchey</a>
+ * @ant.task name="trycatch"
+ */
+public class TryCatchTask extends Task {
+
+ public static final class CatchBlock extends Sequential {
+ private String throwable = BuildException.class.getName();
+
+ public CatchBlock() {
+ super();
+ }
+
+ public void setThrowable(String throwable) {
+ this.throwable = throwable;
+ }
+
+ public boolean execute(Throwable t) throws BuildException {
+ try {
+ Class c = Thread.currentThread().getContextClassLoader().loadClass(throwable);
+ if (c.isAssignableFrom(t.getClass())) {
+ execute();
+ return true;
+ }
+ return false;
+ }
+ catch (ClassNotFoundException e) {
+ throw new BuildException(e);
+ }
+ }
+ }
+
+
+ private Sequential tryTasks = null;
+ private Vector catchBlocks = new Vector();
+ private Sequential finallyTasks = null;
+ private String property = null;
+ private String reference = null;
+
+ /**
+ * Adds a nested &lt;try&gt; block - one is required, more is
+ * forbidden.
+ */
+ public void addTry(Sequential seq) throws BuildException {
+ if (tryTasks != null) {
+ throw new BuildException("You must not specify more than one <try>");
+ }
+
+ tryTasks = seq;
+ }
+
+ public void addCatch(CatchBlock cb) {
+ catchBlocks.add(cb);
+ }
+
+ /**
+ * Adds a nested &lt;finally&gt; block - at most one is allowed.
+ */
+ public void addFinally(Sequential seq) throws BuildException {
+ if (finallyTasks != null) {
+ throw new BuildException("You must not specify more than one <finally>");
+ }
+
+ finallyTasks = seq;
+ }
+
+ /**
+ * Sets the property attribute.
+ */
+ public void setProperty(String p) {
+ property = p;
+ }
+
+ /**
+ * Sets the reference attribute.
+ */
+ public void setReference(String r) {
+ reference = r;
+ }
+
+ /**
+ * The heart of the task.
+ */
+ public void execute() throws BuildException {
+ Throwable thrown = null;
+
+ if (tryTasks == null) {
+ throw new BuildException("A nested <try> element is required");
+ }
+
+ try {
+ tryTasks.perform();
+ } catch (Throwable e) {
+ if (property != null) {
+ /*
+ * Using setProperty instead of setNewProperty to
+ * be able to compile with Ant < 1.5.
+ */
+ getProject().setProperty(property, e.getMessage());
+ }
+
+ if (reference != null) {
+ getProject().addReference(reference, e);
+ }
+
+ boolean executed = false;
+ Enumeration blocks = catchBlocks.elements();
+ while (blocks.hasMoreElements() && ! executed) {
+ CatchBlock cb = (CatchBlock)blocks.nextElement();
+ executed = cb.execute(e);
+ }
+
+ if (! executed) {
+ thrown = e;
+ }
+ } finally {
+ if (finallyTasks != null) {
+ finallyTasks.perform();
+ }
+ }
+
+ if (thrown != null) {
+ throw new BuildException(thrown);
+ }
+ }
+
+}
diff --git a/ant1.5/src/java/net/sf/antcontrib/logic/condition/BooleanConditionBase.java b/ant1.5/src/java/net/sf/antcontrib/logic/condition/BooleanConditionBase.java
new file mode 100644
index 0000000..f4a7412
--- /dev/null
+++ b/ant1.5/src/java/net/sf/antcontrib/logic/condition/BooleanConditionBase.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.antcontrib.logic.condition;
+
+import java.lang.reflect.Field;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.condition.ConditionBase;
+
+/**
+ * Extends ConditionBase so I can get access to the condition count and the
+ * first condition. This is the class that the BooleanConditionTask is proxy
+ * for.
+ * <p>Developed for use with Antelope, migrated to ant-contrib Oct 2003.
+ *
+ * @author Dale Anson, [email protected]
+ */
+public class BooleanConditionBase extends ConditionBase {
+
+ private Vector conditions;
+
+ public BooleanConditionBase() {
+ this.conditions = getParentConditions();
+ }
+
+ private Vector getParentConditions() {
+ try {
+ Field f = ConditionBase.class.getDeclaredField("conditions");
+ f.setAccessible(true);
+ Vector v = (Vector) f.get(this);
+ return v;
+ }
+ catch (NoSuchFieldException e) {
+ throw new BuildException(e);
+ }
+ catch (IllegalAccessException e) {
+ throw new BuildException(e);
+ }
+ }
+
+ /**
+ * Adds a feature to the IsPropertyTrue attribute of the BooleanConditionBase
+ * object
+ *
+ * @param i The feature to be added to the IsPropertyTrue attribute
+ */
+ public void addIsPropertyTrue( IsPropertyTrue i ) {
+ conditions.add( i );
+ }
+
+ /**
+ * Adds a feature to the IsPropertyFalse attribute of the
+ * BooleanConditionBase object
+ *
+ * @param i The feature to be added to the IsPropertyFalse attribute
+ */
+ public void addIsPropertyFalse( IsPropertyFalse i ) {
+ conditions.add( i );
+ }
+
+ public void addIsGreaterThan( IsGreaterThan i) {
+ conditions.add(i);
+ }
+
+ public void addIsLessThan( IsLessThan i) {
+ conditions.add(i);
+ }
+}
+
diff --git a/ant1.5/src/java/net/sf/antcontrib/logic/condition/IsGreaterThan.java b/ant1.5/src/java/net/sf/antcontrib/logic/condition/IsGreaterThan.java
new file mode 100644
index 0000000..0a0971b
--- /dev/null
+++ b/ant1.5/src/java/net/sf/antcontrib/logic/condition/IsGreaterThan.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.antcontrib.logic.condition;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.condition.Equals;
+
+/**
+ * Extends Equals condition to test if the first argument is greater than the
+ * second argument. Will deal with base 10 integer and decimal numbers, otherwise,
+ * treats arguments as Strings.
+ * <p>Developed for use with Antelope, migrated to ant-contrib Oct 2003.
+ *
+ * @author Dale Anson, [email protected]
+ * @version $Revision: 1.4 $
+ * @ant.type name="isgreaterthan"
+ */
+public class IsGreaterThan extends Equals {
+
+ private String arg1, arg2;
+ private boolean trim = false;
+ private boolean caseSensitive = true;
+
+ public void setArg1(String a1) {
+ arg1 = a1;
+ }
+
+ public void setArg2(String a2) {
+ arg2 = a2;
+ }
+
+ /**
+ * Should we want to trim the arguments before comparing them?
+ *
+ * @since Revision: 1.3, Ant 1.5
+ */
+ public void setTrim(boolean b) {
+ trim = b;
+ }
+
+ /**
+ * Should the comparison be case sensitive?
+ *
+ * @since Revision: 1.3, Ant 1.5
+ */
+ public void setCasesensitive(boolean b) {
+ caseSensitive = b;
+ }
+
+ public boolean eval() throws BuildException {
+ if (arg1 == null || arg2 == null) {
+ throw new BuildException("both arg1 and arg2 are required in "
+ + "greater than");
+ }
+
+ if (trim) {
+ arg1 = arg1.trim();
+ arg2 = arg2.trim();
+ }
+
+ // check if args are numbers
+ try {
+ double num1 = Double.parseDouble(arg1);
+ double num2 = Double.parseDouble(arg2);
+ return num1 > num2;
+ }
+ catch(NumberFormatException nfe) {
+ // ignored, fall thru to string comparision
+ }
+
+ return caseSensitive ? arg1.compareTo(arg2) > 0 : arg1.compareToIgnoreCase(arg2) > 0;
+ }
+
+}
diff --git a/ant1.5/src/java/net/sf/antcontrib/logic/condition/IsLessThan.java b/ant1.5/src/java/net/sf/antcontrib/logic/condition/IsLessThan.java
new file mode 100644
index 0000000..72e8e97
--- /dev/null
+++ b/ant1.5/src/java/net/sf/antcontrib/logic/condition/IsLessThan.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.antcontrib.logic.condition;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.condition.Equals;
+
+/**
+ * Extends Equals condition to test if the first argument is less than the
+ * second argument. Will deal with base 10 integer and decimal numbers, otherwise,
+ * treats arguments as Strings.
+ * <p>Developed for use with Antelope, migrated to ant-contrib Oct 2003.
+ *
+ * @author Dale Anson, [email protected]
+ * @version $Revision: 1.4 $
+ * @ant.type name="islessthan"
+ */
+public class IsLessThan extends Equals {
+
+ private String arg1, arg2;
+ private boolean trim = false;
+ private boolean caseSensitive = true;
+
+ public void setArg1(String a1) {
+ arg1 = a1;
+ }
+
+ public void setArg2(String a2) {
+ arg2 = a2;
+ }
+
+ /**
+ * Should we want to trim the arguments before comparing them?
+ *
+ * @since Revision: 1.3, Ant 1.5
+ */
+ public void setTrim(boolean b) {
+ trim = b;
+ }
+
+ /**
+ * Should the comparison be case sensitive?
+ *
+ * @since Revision: 1.3, Ant 1.5
+ */
+ public void setCasesensitive(boolean b) {
+ caseSensitive = b;
+ }
+
+ public boolean eval() throws BuildException {
+ if (arg1 == null || arg2 == null) {
+ throw new BuildException("both arg1 and arg2 are required in "
+ + "less than");
+ }
+
+ if (trim) {
+ arg1 = arg1.trim();
+ arg2 = arg2.trim();
+ }
+
+ // check if args are numbers
+ try {
+ double num1 = Double.parseDouble(arg1);
+ double num2 = Double.parseDouble(arg2);
+ return num1 < num2;
+ }
+ catch(NumberFormatException nfe) {
+ // ignored, fall thru to string comparision
+ }
+
+ return caseSensitive ? arg1.compareTo(arg2) < 0 : arg1.compareToIgnoreCase(arg2) < 0;
+ }
+
+}
diff --git a/ant1.5/src/java/net/sf/antcontrib/logic/condition/IsPropertyFalse.java b/ant1.5/src/java/net/sf/antcontrib/logic/condition/IsPropertyFalse.java
new file mode 100644
index 0000000..f54760d
--- /dev/null
+++ b/ant1.5/src/java/net/sf/antcontrib/logic/condition/IsPropertyFalse.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.antcontrib.logic.condition;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.condition.IsFalse;
+
+/**
+ * Extends IsFalse condition to check the value of a specified property.
+ * <p>Developed for use with Antelope, migrated to ant-contrib Oct 2003.
+ *
+ * @author Dale Anson, [email protected]
+ * @version $Revision: 1.3 $
+ * @ant.type name="ispropertyfalse"
+ */
+public class IsPropertyFalse extends IsFalse {
+
+ private String name = null;
+
+ public void setProperty(String name) {
+ this.name = name;
+ }
+
+ public boolean eval() throws BuildException {
+ if (name == null)
+ throw new BuildException("Property name must be set.");
+ String value = getProject().getProperty(name);
+ if (value == null)
+ return true;
+ return ! Project.toBoolean(value);
+ }
+
+}
diff --git a/ant1.5/src/java/net/sf/antcontrib/logic/condition/IsPropertyTrue.java b/ant1.5/src/java/net/sf/antcontrib/logic/condition/IsPropertyTrue.java
new file mode 100644
index 0000000..7ef9b79
--- /dev/null
+++ b/ant1.5/src/java/net/sf/antcontrib/logic/condition/IsPropertyTrue.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.antcontrib.logic.condition;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.condition.IsTrue;
+
+/**
+ * Extends IsTrue condition to check the value of a specified property.
+ * <p>Developed for use with Antelope, migrated to ant-contrib Oct 2003.
+ *
+ * @author Dale Anson, [email protected]
+ * @version $Revision: 1.3 $
+ * @ant.type name="ispropertytrue"
+ */
+public class IsPropertyTrue extends IsTrue {
+
+ private String name = null;
+
+ public void setProperty( String name ) {
+ this.name = name;
+ }
+
+ public boolean eval() throws BuildException {
+ if ( name == null )
+ throw new BuildException( "Property name must be set." );
+ String value = getProject().getProperty( name );
+ if ( value == null )
+ return false;
+ return Project.toBoolean( value );
+ }
+
+}