/*
* 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);
}
}
}