You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

Target.java 16 kB

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