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 15 kB

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