/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You 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
 *
 *      https://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 org.apache.tools.ant;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.StringTokenizer;

import org.apache.tools.ant.property.LocalProperties;
import org.apache.tools.ant.taskdefs.condition.And;
import org.apache.tools.ant.taskdefs.condition.Condition;
import org.apache.tools.ant.taskdefs.condition.Or;

Class to implement a target object with required parameters.

If you are creating Targets programmatically, make sure you set the Location to a useful value. In particular all targets should have different location values.

/** * Class to implement a target object with required parameters. * * <p>If you are creating Targets programmatically, make sure you set * the Location to a useful value. In particular all targets should * have different location values.</p> */
public class Target implements TaskContainer {
Name of this target.
/** Name of this target. */
private String name;
The "if" condition to test on execution.
/** The "if" condition to test on execution. */
private String ifString = "";
The "unless" condition to test on execution.
/** The "unless" condition to test on execution. */
private String unlessString = ""; private Condition ifCondition; private Condition unlessCondition;
List of targets this target is dependent on.
/** List of targets this target is dependent on. */
private List<String> dependencies = null;
Children of this target (tasks and data types).
/** Children of this target (tasks and data types). */
private List<Object> children = new ArrayList<>();
Since Ant 1.6.2
/** Since Ant 1.6.2 */
private Location location = Location.UNKNOWN_LOCATION;
Project this target belongs to.
/** Project this target belongs to. */
private Project project;
Description of this target, if any.
/** Description of this target, if any. */
private String description = null;
Default constructor.
/** Default constructor. */
public Target() { //empty }
Cloning constructor.
Params:
  • other – the Target to clone.
/** * Cloning constructor. * @param other the Target to clone. */
public Target(Target other) { this.name = other.name; this.ifString = other.ifString; this.unlessString = other.unlessString; this.ifCondition = other.ifCondition; this.unlessCondition = other.unlessCondition; this.dependencies = other.dependencies; this.location = other.location; this.project = other.project; this.description = other.description; // The children are added to after this cloning this.children = other.children; }
Sets the project this target belongs to.
Params:
  • project – The project this target belongs to. Must not be null.
/** * Sets the project this target belongs to. * * @param project The project this target belongs to. * Must not be <code>null</code>. */
public void setProject(Project project) { this.project = project; }
Returns the project this target belongs to.
Returns:The project this target belongs to, or null if the project has not been set yet.
/** * Returns the project this target belongs to. * * @return The project this target belongs to, or <code>null</code> if * the project has not been set yet. */
public Project getProject() { return project; }
Sets the location of this target's definition.
Params:
  • location – Location
Since:1.6.2
/** * Sets the location of this target's definition. * * @param location <code>Location</code> * @since 1.6.2 */
public void setLocation(Location location) { this.location = location; }
Get the location of this target's definition.
Returns:Location
Since:1.6.2
/** * Get the location of this target's definition. * * @return <code>Location</code> * @since 1.6.2 */
public Location getLocation() { return location; }
Sets the list of targets this target is dependent on. The targets themselves are not resolved at this time.
Params:
  • depS – A comma-separated list of targets this target depends on. Must not be null.
/** * Sets the list of targets this target is dependent on. * The targets themselves are not resolved at this time. * * @param depS A comma-separated list of targets this target * depends on. Must not be <code>null</code>. */
public void setDepends(String depS) { for (String dep : parseDepends(depS, getName(), "depends")) { addDependency(dep); } } public static List<String> parseDepends(String depends, String targetName, String attributeName) { if (depends.isEmpty()) { return new ArrayList<>(); } List<String> list = new ArrayList<>(); StringTokenizer tok = new StringTokenizer(depends, ",", true); while (tok.hasMoreTokens()) { String token = tok.nextToken().trim(); // Make sure the dependency is not empty string if (token.isEmpty() || ",".equals(token)) { throw new BuildException("Syntax Error: " + attributeName + " attribute of target \"" + targetName + "\" contains an empty string."); } list.add(token); // Make sure that depends attribute does not // end in a , if (tok.hasMoreTokens()) { token = tok.nextToken(); if (!tok.hasMoreTokens() || !",".equals(token)) { throw new BuildException("Syntax Error: " + attributeName + " attribute for target \"" + targetName + "\" ends with a \",\" " + "character"); } } } return list; }
Sets the name of this target.
Params:
  • name – The name of this target. Should not be null.
/** * Sets the name of this target. * * @param name The name of this target. Should not be <code>null</code>. */
public void setName(String name) { this.name = name; }
Returns the name of this target.
Returns:the name of this target, or null if the name has not been set yet.
/** * Returns the name of this target. * * @return the name of this target, or <code>null</code> if the * name has not been set yet. */
public String getName() { return name; }
Adds a task to this target.
Params:
  • task – The task to be added. Must not be null.
/** * Adds a task to this target. * * @param task The task to be added. Must not be <code>null</code>. */
public void addTask(Task task) { children.add(task); }
Adds the wrapper for a data type element to this target.
Params:
  • r – The wrapper for the data type element to be added. Must not be null.
/** * Adds the wrapper for a data type element to this target. * * @param r The wrapper for the data type element to be added. * Must not be <code>null</code>. */
public void addDataType(RuntimeConfigurable r) { children.add(r); }
Returns the current set of tasks to be executed by this target.
Returns:an array of the tasks currently within this target
/** * Returns the current set of tasks to be executed by this target. * * @return an array of the tasks currently within this target */
public Task[] getTasks() { List<Task> tasks = new ArrayList<>(children.size()); for (Object o : children) { if (o instanceof Task) { tasks.add((Task) o); } } return tasks.toArray(new Task[tasks.size()]); }
Adds a dependency to this target.
Params:
  • dependency – The name of a target this target is dependent on. Must not be null.
/** * Adds a dependency to this target. * * @param dependency The name of a target this target is dependent on. * Must not be <code>null</code>. */
public void addDependency(String dependency) { if (dependencies == null) { dependencies = new ArrayList<>(2); } dependencies.add(dependency); }
Returns an enumeration of the dependencies of this target.
Returns:an enumeration of the dependencies of this target (enumeration of String)
/** * Returns an enumeration of the dependencies of this target. * * @return an enumeration of the dependencies of this target (enumeration of String) */
public Enumeration<String> getDependencies() { return dependencies == null ? Collections.emptyEnumeration() : Collections.enumeration(dependencies); }
Does this target depend on the named target?
Params:
  • other – the other named target.
Returns:true if the target does depend on the named target
Since:Ant 1.6
/** * Does this target depend on the named target? * @param other the other named target. * @return true if the target does depend on the named target * @since Ant 1.6 */
public boolean dependsOn(String other) { Project p = getProject(); Hashtable<String, Target> t = p == null ? null : p.getTargets(); return p != null && p.topoSort(getName(), t, false).contains(t.get(other)); }
Sets the "if" condition to test on execution. This is the name of a property to test for existence - if the property is not set, the task will not execute. The property goes through property substitution once before testing, so if property foo has value bar, setting the "if" condition to ${foo}_x will mean that the task will only execute if property bar_x is set.
Params:
  • property – The property condition to test on execution. May be null, in which case no "if" test is performed.
/** * Sets the "if" condition to test on execution. This is the * name of a property to test for existence - if the property * is not set, the task will not execute. The property goes * through property substitution once before testing, so if * property <code>foo</code> has value <code>bar</code>, setting * the "if" condition to <code>${foo}_x</code> will mean that the * task will only execute if property <code>bar_x</code> is set. * * @param property The property condition to test on execution. * May be <code>null</code>, in which case * no "if" test is performed. */
public void setIf(String property) { ifString = property == null ? "" : property; setIf(() -> { PropertyHelper propertyHelper = PropertyHelper.getPropertyHelper(getProject()); Object o = propertyHelper.parseProperties(ifString); return propertyHelper.testIfCondition(o); }); }
Returns the "if" property condition of this target.
Returns:the "if" property condition or null if no "if" condition had been defined.
Since:1.6.2
/** * Returns the "if" property condition of this target. * * @return the "if" property condition or <code>null</code> if no * "if" condition had been defined. * @since 1.6.2 */
public String getIf() { return ifString.isEmpty() ? null : ifString; }
Same as setIf(String) but requires a Condition instance
Params:
  • condition – Condition
Since:1.9
/** * Same as {@link #setIf(String)} but requires a {@link Condition} instance * * @param condition Condition * @since 1.9 */
public void setIf(Condition condition) { if (ifCondition == null) { ifCondition = condition; } else { And andCondition = new And(); andCondition.setProject(getProject()); andCondition.setLocation(getLocation()); andCondition.add(ifCondition); andCondition.add(condition); ifCondition = andCondition; } }
Sets the "unless" condition to test on execution. This is the name of a property to test for existence - if the property is set, the task will not execute. The property goes through property substitution once before testing, so if property foo has value bar, setting the "unless" condition to ${foo}_x will mean that the task will only execute if property bar_x isn't set.
Params:
  • property – The property condition to test on execution. May be null, in which case no "unless" test is performed.
/** * Sets the "unless" condition to test on execution. This is the * name of a property to test for existence - if the property * is set, the task will not execute. The property goes * through property substitution once before testing, so if * property <code>foo</code> has value <code>bar</code>, setting * the "unless" condition to <code>${foo}_x</code> will mean that the * task will only execute if property <code>bar_x</code> isn't set. * * @param property The property condition to test on execution. * May be <code>null</code>, in which case * no "unless" test is performed. */
public void setUnless(String property) { unlessString = property == null ? "" : property; setUnless(() -> { PropertyHelper propertyHelper = PropertyHelper.getPropertyHelper(getProject()); Object o = propertyHelper.parseProperties(unlessString); return !propertyHelper.testUnlessCondition(o); }); }
Returns the "unless" property condition of this target.
Returns:the "unless" property condition or null if no "unless" condition had been defined.
Since:1.6.2
/** * Returns the "unless" property condition of this target. * * @return the "unless" property condition or <code>null</code> * if no "unless" condition had been defined. * @since 1.6.2 */
public String getUnless() { return unlessString.isEmpty() ? null : unlessString; }
Same as setUnless(String) but requires a Condition instance
Params:
  • condition – Condition
Since:1.9
/** * Same as {@link #setUnless(String)} but requires a {@link Condition} instance * * @param condition Condition * @since 1.9 */
public void setUnless(Condition condition) { if (unlessCondition == null) { unlessCondition = condition; } else { Or orCondition = new Or(); orCondition.setProject(getProject()); orCondition.setLocation(getLocation()); orCondition.add(unlessCondition); orCondition.add(condition); unlessCondition = orCondition; } }
Sets the description of this target.
Params:
  • description – The description for this target. May be null, indicating that no description is available.
/** * Sets the description of this target. * * @param description The description for this target. * May be <code>null</code>, indicating that no * description is available. */
public void setDescription(String description) { this.description = description; }
Returns the description of this target.
Returns:the description of this target, or null if no description is available.
/** * Returns the description of this target. * * @return the description of this target, or <code>null</code> if no * description is available. */
public String getDescription() { return description; }
Returns the name of this target.
Returns:the name of this target, or null if the name has not been set yet.
/** * Returns the name of this target. * * @return the name of this target, or <code>null</code> if the * name has not been set yet. */
@Override public String toString() { return name; }
Executes the target if the "if" and "unless" conditions are satisfied. Dependency checking should be done before calling this method, as it does no checking of its own. If either the "if" or "unless" test prevents this target from being executed, a verbose message is logged giving the reason. It is recommended that clients of this class call performTasks rather than this method so that appropriate build events are fired.
Throws:
  • BuildException – if any of the tasks fail or if a data type configuration fails.
See Also:
/** * Executes the target if the "if" and "unless" conditions are * satisfied. Dependency checking should be done before calling this * method, as it does no checking of its own. If either the "if" * or "unless" test prevents this target from being executed, a verbose * message is logged giving the reason. It is recommended that clients * of this class call performTasks rather than this method so that * appropriate build events are fired. * * @exception BuildException if any of the tasks fail or if a data type * configuration fails. * * @see #performTasks() * @see #setIf(String) * @see #setUnless(String) */
public void execute() throws BuildException { if (ifCondition != null && !ifCondition.eval()) { project.log(this, "Skipped because property '" + project.replaceProperties(ifString) + "' not set.", Project.MSG_VERBOSE); return; } if (unlessCondition != null && unlessCondition.eval()) { project.log(this, "Skipped because property '" + project.replaceProperties(unlessString) + "' set.", Project.MSG_VERBOSE); return; } LocalProperties localProperties = LocalProperties.get(getProject()); localProperties.enterScope(); try { // use index-based approach to avoid ConcurrentModificationExceptions; // also account for growing target children // do not optimize this loop by replacing children.size() by a variable // as children can be added dynamically as in RhinoScriptTest where a target is adding work for itself for (int i = 0; i < children.size(); i++) { Object o = children.get(i); if (o instanceof Task) { Task task = (Task) o; task.perform(); } else { ((RuntimeConfigurable) o).maybeConfigure(project); } } } finally { localProperties.exitScope(); } }
Performs the tasks within this target (if the conditions are met), firing target started/target finished messages around a call to execute.
See Also:
  • execute()
/** * Performs the tasks within this target (if the conditions are met), * firing target started/target finished messages around a call to * execute. * * @see #execute() */
public final void performTasks() { RuntimeException thrown = null; project.fireTargetStarted(this); try { execute(); } catch (RuntimeException exc) { thrown = exc; throw exc; } finally { project.fireTargetFinished(this, thrown); } }
Replaces all occurrences of the given task in the list of children with the replacement data type wrapper.
Params:
  • el – The task to replace. Must not be null.
  • o – The data type wrapper to replace el with.
/** * Replaces all occurrences of the given task in the list * of children with the replacement data type wrapper. * * @param el The task to replace. * Must not be <code>null</code>. * @param o The data type wrapper to replace <code>el</code> with. */
void replaceChild(Task el, RuntimeConfigurable o) { int index; while ((index = children.indexOf(el)) >= 0) { children.set(index, o); } }
Replaces all occurrences of the given task in the list of children with the replacement task.
Params:
  • el – The task to replace. Must not be null.
  • o – The task to replace el with.
/** * Replaces all occurrences of the given task in the list * of children with the replacement task. * * @param el The task to replace. * Must not be <code>null</code>. * @param o The task to replace <code>el</code> with. */
void replaceChild(Task el, Task o) { int index; while ((index = children.indexOf(el)) >= 0) { children.set(index, o); } } }