All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.tools.ant.Target Maven / Gradle / Ivy

There is a newer version: 1.10.15
Show newest version
/*
 *  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
 *
 *      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 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.

*/ public class Target implements TaskContainer { /** Name of this target. */ private String name; /** The "if" condition to test on execution. */ private String ifString = ""; /** The "unless" condition to test on execution. */ private String unlessString = ""; private Condition ifCondition; private Condition unlessCondition; /** List of targets this target is dependent on. */ private List dependencies = null; /** Children of this target (tasks and data types). */ private List children = new ArrayList(); /** Since Ant 1.6.2 */ private Location location = Location.UNKNOWN_LOCATION; /** Project this target belongs to. */ private Project project; /** Description of this target, if any. */ private String description = null; /** Default constructor. */ public Target() { //empty } /** * 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. * * @param project The project this target belongs to. * Must not be null. */ public void setProject(Project project) { this.project = project; } /** * Returns the project this target belongs to. * * @return The project this target belongs to, or null if * the project has not been set yet. */ public Project getProject() { return project; } /** * Sets the location of this target's definition. * * @param location Location * @since 1.6.2 */ public void setLocation(Location location) { this.location = location; } /** * Get the location of this target's definition. * * @return Location * @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. * * @param depS A comma-separated list of targets this target * depends on. Must not be null. */ public void setDepends(String depS) { for (String dep : parseDepends(depS, getName(), "depends")) { addDependency(dep); } } public static List parseDepends(String depends, String targetName, String attributeName) { List list = new ArrayList(); if (depends.length() > 0) { StringTokenizer tok = new StringTokenizer(depends, ",", true); while (tok.hasMoreTokens()) { String token = tok.nextToken().trim(); // Make sure the dependency is not empty string if ("".equals(token) || ",".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. * * @param name The name of this target. Should not be null. */ public void setName(String name) { this.name = name; } /** * Returns the name of this target. * * @return the name of this target, or null if the * name has not been set yet. */ public String getName() { return name; } /** * Adds a task to this target. * * @param task The task to be added. Must not be null. */ public void addTask(Task task) { children.add(task); } /** * 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 null. */ public void addDataType(RuntimeConfigurable r) { children.add(r); } /** * 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 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. * * @param dependency The name of a target this target is dependent on. * Must not be null. */ public void addDependency(String dependency) { if (dependencies == null) { dependencies = new ArrayList(2); } dependencies.add(dependency); } /** * Returns an enumeration of the dependencies of this target. * * @return an enumeration of the dependencies of this target (enumeration of String) */ public Enumeration getDependencies() { return Collections .enumeration(dependencies == null ? Collections. emptyList() : dependencies); } /** * 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 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. * * @param property The property condition to test on execution. * May be null, in which case * no "if" test is performed. */ public void setIf(String property) { ifString = property == null ? "" : property; setIf(new IfStringCondition(ifString)); } /** * Returns the "if" property condition of this target. * * @return the "if" property condition or null if no * "if" condition had been defined. * @since 1.6.2 */ public String getIf() { return "".equals(ifString) ? null : ifString; } /** * Same as {@link #setIf(String)} but requires a {@link Condition} instance * * @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. * * @param property The property condition to test on execution. * May be null, in which case * no "unless" test is performed. */ public void setUnless(String property) { unlessString = property == null ? "" : property; setUnless(new UnlessStringCondition(unlessString)); } /** * Returns the "unless" property condition of this target. * * @return the "unless" property condition or null * if no "unless" condition had been defined. * @since 1.6.2 */ public String getUnless() { return "".equals(unlessString) ? null : unlessString; } /** * Same as {@link #setUnless(String)} but requires a {@link Condition} instance * * @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. * * @param description The description for this target. * May be null, indicating that no * description is available. */ public void setDescription(String description) { this.description = description; } /** * Returns the description of this target. * * @return the description of this target, or null if no * description is available. */ public String getDescription() { return description; } /** * Returns the name of this target. * * @return the name of this target, or null if the * name has not been set yet. */ 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. * * @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 #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. * * @param el The task to replace. * Must not be null. * @param o The data type wrapper to replace el 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. * * @param el The task to replace. * Must not be null. * @param o The task to replace el with. */ void replaceChild(Task el, Task o) { int index; while ((index = children.indexOf(el)) >= 0) { children.set(index, o); } } /** * Condition evaluating the 'if' attribute with the PropertyHelper. */ private class IfStringCondition implements Condition { private String condition; public IfStringCondition(String condition) { this.condition = condition; } public boolean eval() throws BuildException { PropertyHelper propertyHelper = PropertyHelper.getPropertyHelper(getProject()); Object o = propertyHelper.parseProperties(condition); return propertyHelper.testIfCondition(o); } } /** * Condition evaluating the 'unless' attribute with the PropertyHelper. */ private class UnlessStringCondition implements Condition { private String condition; public UnlessStringCondition(String condition) { this.condition = condition; } public boolean eval() throws BuildException { PropertyHelper propertyHelper = PropertyHelper.getPropertyHelper(getProject()); Object o = propertyHelper.parseProperties(condition); return !propertyHelper.testUnlessCondition(o); } } }