1. /*
  2. * Copyright 2000-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant;
  18. import java.util.ArrayList;
  19. import java.util.Collections;
  20. import java.util.Enumeration;
  21. import java.util.Iterator;
  22. import java.util.List;
  23. import java.util.StringTokenizer;
  24. import org.apache.tools.ant.util.CollectionUtils;
  25. /**
  26. * Class to implement a target object with required parameters.
  27. *
  28. */
  29. public class Target implements TaskContainer {
  30. /** Name of this target. */
  31. private String name;
  32. /** The "if" condition to test on execution. */
  33. private String ifCondition = "";
  34. /** The "unless" condition to test on execution. */
  35. private String unlessCondition = "";
  36. /** List of targets this target is dependent on. */
  37. private List dependencies = null;
  38. /** Children of this target (tasks and data types). */
  39. private List children = new ArrayList();
  40. /** Since Ant 1.6.2 */
  41. private Location location = Location.UNKNOWN_LOCATION;
  42. /** Project this target belongs to. */
  43. private Project project;
  44. /** Description of this target, if any. */
  45. private String description = null;
  46. /** Sole constructor. */
  47. public Target() {
  48. }
  49. /**
  50. * Sets the project this target belongs to.
  51. *
  52. * @param project The project this target belongs to.
  53. * Must not be <code>null</code>.
  54. */
  55. public void setProject(Project project) {
  56. this.project = project;
  57. }
  58. /**
  59. * Returns the project this target belongs to.
  60. *
  61. * @return The project this target belongs to, or <code>null</code> if
  62. * the project has not been set yet.
  63. */
  64. public Project getProject() {
  65. return project;
  66. }
  67. /**
  68. * Sets the location of this target's definition.
  69. *
  70. * @param location <CODE>Location</CODE>
  71. */
  72. public void setLocation(Location location) {
  73. this.location = location;
  74. }
  75. /**
  76. * Get the location of this target's definition.
  77. *
  78. * @return <CODE>Location</CODE>
  79. */
  80. public Location getLocation() {
  81. return location;
  82. }
  83. /**
  84. * Sets the list of targets this target is dependent on.
  85. * The targets themselves are not resolved at this time.
  86. *
  87. * @param depS A comma-separated list of targets this target
  88. * depends on. Must not be <code>null</code>.
  89. */
  90. public void setDepends(String depS) {
  91. if (depS.length() > 0) {
  92. StringTokenizer tok =
  93. new StringTokenizer(depS, ",", true);
  94. while (tok.hasMoreTokens()) {
  95. String token = tok.nextToken().trim();
  96. // Make sure the dependency is not empty string
  97. if (token.equals("") || token.equals(",")) {
  98. throw new BuildException("Syntax Error: Depend "
  99. + "attribute for target \"" + getName()
  100. + "\" has an empty string for dependency.");
  101. }
  102. addDependency(token);
  103. // Make sure that depends attribute does not
  104. // end in a ,
  105. if (tok.hasMoreTokens()) {
  106. token = tok.nextToken();
  107. if (!tok.hasMoreTokens() || !token.equals(",")) {
  108. throw new BuildException("Syntax Error: Depend "
  109. + "attribute for target \"" + getName()
  110. + "\" ends with a , character");
  111. }
  112. }
  113. }
  114. }
  115. }
  116. /**
  117. * Sets the name of this target.
  118. *
  119. * @param name The name of this target. Should not be <code>null</code>.
  120. */
  121. public void setName(String name) {
  122. this.name = name;
  123. }
  124. /**
  125. * Returns the name of this target.
  126. *
  127. * @return the name of this target, or <code>null</code> if the
  128. * name has not been set yet.
  129. */
  130. public String getName() {
  131. return name;
  132. }
  133. /**
  134. * Adds a task to this target.
  135. *
  136. * @param task The task to be added. Must not be <code>null</code>.
  137. */
  138. public void addTask(Task task) {
  139. children.add(task);
  140. }
  141. /**
  142. * Adds the wrapper for a data type element to this target.
  143. *
  144. * @param r The wrapper for the data type element to be added.
  145. * Must not be <code>null</code>.
  146. */
  147. public void addDataType(RuntimeConfigurable r) {
  148. children.add(r);
  149. }
  150. /**
  151. * Returns the current set of tasks to be executed by this target.
  152. *
  153. * @return an array of the tasks currently within this target
  154. */
  155. public Task[] getTasks() {
  156. List tasks = new ArrayList(children.size());
  157. Iterator it = children.iterator();
  158. while (it.hasNext()) {
  159. Object o = it.next();
  160. if (o instanceof Task) {
  161. tasks.add(o);
  162. }
  163. }
  164. return (Task[]) tasks.toArray(new Task[tasks.size()]);
  165. }
  166. /**
  167. * Adds a dependency to this target.
  168. *
  169. * @param dependency The name of a target this target is dependent on.
  170. * Must not be <code>null</code>.
  171. */
  172. public void addDependency(String dependency) {
  173. if (dependencies == null) {
  174. dependencies = new ArrayList(2);
  175. }
  176. dependencies.add(dependency);
  177. }
  178. /**
  179. * Returns an enumeration of the dependencies of this target.
  180. *
  181. * @return an enumeration of the dependencies of this target
  182. */
  183. public Enumeration getDependencies() {
  184. if (dependencies != null) {
  185. return Collections.enumeration(dependencies);
  186. } else {
  187. return new CollectionUtils.EmptyEnumeration();
  188. }
  189. }
  190. /**
  191. * Does this target depend on the named target?
  192. * @param other the other named target.
  193. * @return true if the target does depend on the named target
  194. * @since Ant 1.6
  195. */
  196. public boolean dependsOn(String other) {
  197. if (getProject() != null) {
  198. List l = getProject().topoSort(getName(),
  199. getProject().getTargets());
  200. int myIdx = l.indexOf(this);
  201. int otherIdx = l.indexOf(getProject().getTargets().get(other));
  202. return myIdx >= otherIdx;
  203. }
  204. return false;
  205. }
  206. /**
  207. * Sets the "if" condition to test on execution. This is the
  208. * name of a property to test for existence - if the property
  209. * is not set, the task will not execute. The property goes
  210. * through property substitution once before testing, so if
  211. * property <code>foo</code> has value <code>bar</code>, setting
  212. * the "if" condition to <code>${foo}_x</code> will mean that the
  213. * task will only execute if property <code>bar_x</code> is set.
  214. *
  215. * @param property The property condition to test on execution.
  216. * May be <code>null</code>, in which case
  217. * no "if" test is performed.
  218. */
  219. public void setIf(String property) {
  220. this.ifCondition = (property == null) ? "" : property;
  221. }
  222. /**
  223. * Returns the "if" property condition of this target.
  224. *
  225. * @return the "if" property condition or <code>null</code> if no
  226. * "if" condition had been defined.
  227. */
  228. public String getIf() {
  229. return ("".equals(ifCondition) ? null : ifCondition);
  230. }
  231. /**
  232. * Sets the "unless" condition to test on execution. This is the
  233. * name of a property to test for existence - if the property
  234. * is set, the task will not execute. The property goes
  235. * through property substitution once before testing, so if
  236. * property <code>foo</code> has value <code>bar</code>, setting
  237. * the "unless" condition to <code>${foo}_x</code> will mean that the
  238. * task will only execute if property <code>bar_x</code> isn't set.
  239. *
  240. * @param property The property condition to test on execution.
  241. * May be <code>null</code>, in which case
  242. * no "unless" test is performed.
  243. */
  244. public void setUnless(String property) {
  245. this.unlessCondition = (property == null) ? "" : property;
  246. }
  247. /**
  248. * Returns the "unless" property condition of this target.
  249. *
  250. * @return the "unless" property condition or <code>null</code>
  251. * if no "unless" condition had been defined.
  252. */
  253. public String getUnless() {
  254. return ("".equals(unlessCondition) ? null : unlessCondition);
  255. }
  256. /**
  257. * Sets the description of this target.
  258. *
  259. * @param description The description for this target.
  260. * May be <code>null</code>, indicating that no
  261. * description is available.
  262. */
  263. public void setDescription(String description) {
  264. this.description = description;
  265. }
  266. /**
  267. * Returns the description of this target.
  268. *
  269. * @return the description of this target, or <code>null</code> if no
  270. * description is available.
  271. */
  272. public String getDescription() {
  273. return description;
  274. }
  275. /**
  276. * Returns the name of this target.
  277. *
  278. * @return the name of this target, or <code>null</code> if the
  279. * name has not been set yet.
  280. */
  281. public String toString() {
  282. return name;
  283. }
  284. /**
  285. * Executes the target if the "if" and "unless" conditions are
  286. * satisfied. Dependency checking should be done before calling this
  287. * method, as it does no checking of its own. If either the "if"
  288. * or "unless" test prevents this target from being executed, a verbose
  289. * message is logged giving the reason. It is recommended that clients
  290. * of this class call performTasks rather than this method so that
  291. * appropriate build events are fired.
  292. *
  293. * @exception BuildException if any of the tasks fail or if a data type
  294. * configuration fails.
  295. *
  296. * @see #performTasks()
  297. * @see #setIf(String)
  298. * @see #setUnless(String)
  299. */
  300. public void execute() throws BuildException {
  301. if (testIfCondition() && testUnlessCondition()) {
  302. for (int taskPosition = 0;
  303. taskPosition < children.size();
  304. ++taskPosition) {
  305. Object o = children.get(taskPosition);
  306. if (o instanceof Task) {
  307. Task task = (Task) o;
  308. task.perform();
  309. } else {
  310. RuntimeConfigurable r = (RuntimeConfigurable) o;
  311. r.maybeConfigure(project);
  312. }
  313. }
  314. } else if (!testIfCondition()) {
  315. project.log(this, "Skipped because property '"
  316. + project.replaceProperties(this.ifCondition)
  317. + "' not set.", Project.MSG_VERBOSE);
  318. } else {
  319. project.log(this, "Skipped because property '"
  320. + project.replaceProperties(this.unlessCondition)
  321. + "' set.", Project.MSG_VERBOSE);
  322. }
  323. }
  324. /**
  325. * Performs the tasks within this target (if the conditions are met),
  326. * firing target started/target finished messages around a call to
  327. * execute.
  328. *
  329. * @see #execute()
  330. */
  331. public final void performTasks() {
  332. RuntimeException thrown = null;
  333. project.fireTargetStarted(this);
  334. try {
  335. execute();
  336. } catch (RuntimeException exc) {
  337. thrown = exc;
  338. throw exc;
  339. } finally {
  340. project.fireTargetFinished(this, thrown);
  341. }
  342. }
  343. /**
  344. * Replaces all occurrences of the given task in the list
  345. * of children with the replacement data type wrapper.
  346. *
  347. * @param el The task to replace.
  348. * Must not be <code>null</code>.
  349. * @param o The data type wrapper to replace <code>el</code> with.
  350. */
  351. void replaceChild(Task el, RuntimeConfigurable o) {
  352. int index;
  353. while ((index = children.indexOf(el)) >= 0) {
  354. children.set(index, o);
  355. }
  356. }
  357. /**
  358. * Replaces all occurrences of the given task in the list
  359. * of children with the replacement task.
  360. *
  361. * @param el The task to replace.
  362. * Must not be <code>null</code>.
  363. * @param o The task to replace <code>el</code> with.
  364. */
  365. void replaceChild(Task el, Task o) {
  366. int index;
  367. while ((index = children.indexOf(el)) >= 0) {
  368. children.set(index, o);
  369. }
  370. }
  371. /**
  372. * Tests whether or not the "if" condition is satisfied.
  373. *
  374. * @return whether or not the "if" condition is satisfied. If no
  375. * condition (or an empty condition) has been set,
  376. * <code>true</code> is returned.
  377. *
  378. * @see #setIf(String)
  379. */
  380. private boolean testIfCondition() {
  381. if ("".equals(ifCondition)) {
  382. return true;
  383. }
  384. String test = project.replaceProperties(ifCondition);
  385. return project.getProperty(test) != null;
  386. }
  387. /**
  388. * Tests whether or not the "unless" condition is satisfied.
  389. *
  390. * @return whether or not the "unless" condition is satisfied. If no
  391. * condition (or an empty condition) has been set,
  392. * <code>true</code> is returned.
  393. *
  394. * @see #setUnless(String)
  395. */
  396. private boolean testUnlessCondition() {
  397. if ("".equals(unlessCondition)) {
  398. return true;
  399. }
  400. String test = project.replaceProperties(unlessCondition);
  401. return project.getProperty(test) == null;
  402. }
  403. }