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.

Task.java 15 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  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 org.apache.tools.ant.dispatch.DispatchUtils;
  20. import java.util.Enumeration;
  21. import java.io.IOException;
  22. /**
  23. * Base class for all tasks.
  24. *
  25. * Use Project.createTask to create a new task instance rather than
  26. * using this class directly for construction.
  27. *
  28. * @see Project#createTask
  29. */
  30. public abstract class Task extends ProjectComponent {
  31. /**
  32. * Target this task belongs to, if any.
  33. * @deprecated since 1.6.x.
  34. * You should not be accessing this variable directly.
  35. * Please use the {@link #getOwningTarget()} method.
  36. */
  37. protected Target target;
  38. /**
  39. * Description of this task, if any.
  40. * @deprecated since 1.6.x.
  41. * You should not be accessing this variable directly.
  42. */
  43. protected String description;
  44. /**
  45. * Name of this task to be used for logging purposes.
  46. * This defaults to the same as the type, but may be
  47. * overridden by the user. For instance, the name "java"
  48. * isn't terribly descriptive for a task used within
  49. * another task - the outer task code can probably
  50. * provide a better one.
  51. * @deprecated since 1.6.x.
  52. * You should not be accessing this variable directly.
  53. * Please use the {@link #getTaskName()} method.
  54. */
  55. protected String taskName;
  56. /**
  57. * Type of this task.
  58. *
  59. * @deprecated since 1.6.x.
  60. * You should not be accessing this variable directly.
  61. * Please use the {@link #getTaskType()} method.
  62. */
  63. protected String taskType;
  64. /**
  65. * Wrapper for this object, used to configure it at runtime.
  66. *
  67. * @deprecated since 1.6.x.
  68. * You should not be accessing this variable directly.
  69. * Please use the {@link #getWrapper()} method.
  70. */
  71. protected RuntimeConfigurable wrapper;
  72. /**
  73. * Whether or not this task is invalid. A task becomes invalid
  74. * if a conflicting class is specified as the implementation for
  75. * its type.
  76. */
  77. private boolean invalid;
  78. /** Sole constructor. */
  79. public Task() {
  80. }
  81. /**
  82. * Sets the target container of this task.
  83. *
  84. * @param target Target in whose scope this task belongs.
  85. * May be <code>null</code>, indicating a top-level task.
  86. */
  87. public void setOwningTarget(Target target) {
  88. this.target = target;
  89. }
  90. /**
  91. * Returns the container target of this task.
  92. *
  93. * @return The target containing this task, or <code>null</code> if
  94. * this task is a top-level task.
  95. */
  96. public Target getOwningTarget() {
  97. return target;
  98. }
  99. /**
  100. * Sets the name to use in logging messages.
  101. *
  102. * @param name The name to use in logging messages.
  103. * Should not be <code>null</code>.
  104. */
  105. public void setTaskName(String name) {
  106. this.taskName = name;
  107. }
  108. /**
  109. * Returns the name to use in logging messages.
  110. *
  111. * @return the name to use in logging messages.
  112. */
  113. public String getTaskName() {
  114. return taskName;
  115. }
  116. /**
  117. * Sets the name with which the task has been invoked.
  118. *
  119. * @param type The name the task has been invoked as.
  120. * Should not be <code>null</code>.
  121. */
  122. public void setTaskType(String type) {
  123. this.taskType = type;
  124. }
  125. /**
  126. * Sets a description of the current action. This may be used for logging
  127. * purposes.
  128. *
  129. * @param desc Description of the current action.
  130. * May be <code>null</code>, indicating that no description is
  131. * available.
  132. *
  133. */
  134. public void setDescription(String desc) {
  135. description = desc;
  136. }
  137. /**
  138. * Returns the description of the current action.
  139. *
  140. * @return the description of the current action, or <code>null</code> if
  141. * no description is available.
  142. */
  143. public String getDescription() {
  144. return description;
  145. }
  146. /**
  147. * Called by the project to let the task initialize properly.
  148. * The default implementation is a no-op.
  149. *
  150. * @exception BuildException if something goes wrong with the build
  151. */
  152. public void init() throws BuildException {
  153. }
  154. /**
  155. * Called by the project to let the task do its work. This method may be
  156. * called more than once, if the task is invoked more than once.
  157. * For example,
  158. * if target1 and target2 both depend on target3, then running
  159. * "ant target1 target2" will run all tasks in target3 twice.
  160. *
  161. * @exception BuildException if something goes wrong with the build.
  162. */
  163. public void execute() throws BuildException {
  164. }
  165. /**
  166. * Returns the wrapper used for runtime configuration.
  167. *
  168. * @return the wrapper used for runtime configuration. This
  169. * method will generate a new wrapper (and cache it)
  170. * if one isn't set already.
  171. */
  172. public RuntimeConfigurable getRuntimeConfigurableWrapper() {
  173. if (wrapper == null) {
  174. wrapper = new RuntimeConfigurable(this, getTaskName());
  175. }
  176. return wrapper;
  177. }
  178. /**
  179. * Sets the wrapper to be used for runtime configuration.
  180. *
  181. * This method should be used only by the ProjectHelper and Ant internals.
  182. * It is public to allow helper plugins to operate on tasks, normal tasks
  183. * should never use it.
  184. *
  185. * @param wrapper The wrapper to be used for runtime configuration.
  186. * May be <code>null</code>, in which case the next call
  187. * to getRuntimeConfigurableWrapper will generate a new
  188. * wrapper.
  189. */
  190. public void setRuntimeConfigurableWrapper(RuntimeConfigurable wrapper) {
  191. this.wrapper = wrapper;
  192. }
  193. // XXX: (Jon Skeet) The comment "if it hasn't been done already" may
  194. // not be strictly true. wrapper.maybeConfigure() won't configure the same
  195. // attributes/text more than once, but it may well add the children again,
  196. // unless I've missed something.
  197. /**
  198. * Configures this task - if it hasn't been done already.
  199. * If the task has been invalidated, it is replaced with an
  200. * UnknownElement task which uses the new definition in the project.
  201. *
  202. * @exception BuildException if the task cannot be configured.
  203. */
  204. public void maybeConfigure() throws BuildException {
  205. if (!invalid) {
  206. if (wrapper != null) {
  207. wrapper.maybeConfigure(getProject());
  208. }
  209. } else {
  210. getReplacement();
  211. }
  212. }
  213. /**
  214. * Force the task to be reconfigured from its RuntimeConfigurable.
  215. */
  216. public void reconfigure() {
  217. if (wrapper != null) {
  218. wrapper.reconfigure(getProject());
  219. }
  220. }
  221. /**
  222. * Handles output by logging it with the INFO priority.
  223. *
  224. * @param output The output to log. Should not be <code>null</code>.
  225. */
  226. protected void handleOutput(String output) {
  227. log(output, Project.MSG_INFO);
  228. }
  229. /**
  230. * Handles output by logging it with the INFO priority.
  231. *
  232. * @param output The output to log. Should not be <code>null</code>.
  233. *
  234. * @since Ant 1.5.2
  235. */
  236. protected void handleFlush(String output) {
  237. handleOutput(output);
  238. }
  239. /**
  240. * Handle an input request by this task.
  241. *
  242. * @param buffer the buffer into which data is to be read.
  243. * @param offset the offset into the buffer at which data is stored.
  244. * @param length the amount of data to read.
  245. *
  246. * @return the number of bytes read.
  247. *
  248. * @exception IOException if the data cannot be read.
  249. * @since Ant 1.6
  250. */
  251. protected int handleInput(byte[] buffer, int offset, int length)
  252. throws IOException {
  253. return getProject().defaultInput(buffer, offset, length);
  254. }
  255. /**
  256. * Handles an error output by logging it with the WARN priority.
  257. *
  258. * @param output The error output to log. Should not be <code>null</code>.
  259. */
  260. protected void handleErrorOutput(String output) {
  261. log(output, Project.MSG_WARN);
  262. }
  263. /**
  264. * Handles an error line by logging it with the WARN priority.
  265. *
  266. * @param output The error output to log. Should not be <code>null</code>.
  267. *
  268. * @since Ant 1.5.2
  269. */
  270. protected void handleErrorFlush(String output) {
  271. handleErrorOutput(output);
  272. }
  273. /**
  274. * Logs a message with the default (INFO) priority.
  275. *
  276. * @param msg The message to be logged. Should not be <code>null</code>.
  277. */
  278. public void log(String msg) {
  279. log(msg, Project.MSG_INFO);
  280. }
  281. /**
  282. * Logs a message with the given priority. This delegates
  283. * the actual logging to the project.
  284. *
  285. * @param msg The message to be logged. Should not be <code>null</code>.
  286. * @param msgLevel The message priority at which this message is to
  287. * be logged.
  288. */
  289. public void log(String msg, int msgLevel) {
  290. if (getProject() != null) {
  291. getProject().log(this, msg, msgLevel);
  292. } else {
  293. super.log(msg, msgLevel);
  294. }
  295. }
  296. /**
  297. * Performs this task if it's still valid, or gets a replacement
  298. * version and performs that otherwise.
  299. *
  300. * Performing a task consists of firing a task started event,
  301. * configuring the task, executing it, and then firing task finished
  302. * event. If a runtime exception is thrown, the task finished event
  303. * is still fired, but with the exception as the cause.
  304. */
  305. public final void perform() {
  306. if (!invalid) {
  307. getProject().fireTaskStarted(this);
  308. Throwable reason = null;
  309. try {
  310. maybeConfigure();
  311. DispatchUtils.execute(this);
  312. } catch (BuildException ex) {
  313. if (ex.getLocation() == Location.UNKNOWN_LOCATION) {
  314. ex.setLocation(getLocation());
  315. }
  316. reason = ex;
  317. throw ex;
  318. } catch (Exception ex) {
  319. reason = ex;
  320. BuildException be = new BuildException(ex);
  321. be.setLocation(getLocation());
  322. throw be;
  323. } catch (Error ex) {
  324. reason = ex;
  325. throw ex;
  326. } finally {
  327. getProject().fireTaskFinished(this, reason);
  328. }
  329. } else {
  330. UnknownElement ue = getReplacement();
  331. Task task = ue.getTask();
  332. task.perform();
  333. }
  334. }
  335. /**
  336. * Marks this task as invalid. Any further use of this task
  337. * will go through a replacement with the updated definition.
  338. */
  339. final void markInvalid() {
  340. invalid = true;
  341. }
  342. /**
  343. * Has this task been marked invalid?
  344. *
  345. * @return true if this task is no longer valid. A new task should be
  346. * configured in this case.
  347. *
  348. * @since Ant 1.5
  349. */
  350. protected final boolean isInvalid() {
  351. return invalid;
  352. }
  353. /**
  354. * Replacement element used if this task is invalidated.
  355. */
  356. private UnknownElement replacement;
  357. /**
  358. * Creates an UnknownElement that can be used to replace this task.
  359. * Once this has been created once, it is cached and returned by
  360. * future calls.
  361. *
  362. * @return the UnknownElement instance for the new definition of this task.
  363. */
  364. private UnknownElement getReplacement() {
  365. if (replacement == null) {
  366. replacement = new UnknownElement(taskType);
  367. replacement.setProject(getProject());
  368. replacement.setTaskType(taskType);
  369. replacement.setTaskName(taskName);
  370. replacement.setLocation(location);
  371. replacement.setOwningTarget(target);
  372. replacement.setRuntimeConfigurableWrapper(wrapper);
  373. wrapper.setProxy(replacement);
  374. replaceChildren(wrapper, replacement);
  375. target.replaceChild(this, replacement);
  376. replacement.maybeConfigure();
  377. }
  378. return replacement;
  379. }
  380. /**
  381. * Recursively adds an UnknownElement instance for each child
  382. * element of replacement.
  383. *
  384. * @since Ant 1.5.1
  385. */
  386. private void replaceChildren(RuntimeConfigurable wrapper,
  387. UnknownElement parentElement) {
  388. Enumeration e = wrapper.getChildren();
  389. while (e.hasMoreElements()) {
  390. RuntimeConfigurable childWrapper =
  391. (RuntimeConfigurable) e.nextElement();
  392. UnknownElement childElement =
  393. new UnknownElement(childWrapper.getElementTag());
  394. parentElement.addChild(childElement);
  395. childElement.setProject(getProject());
  396. childElement.setRuntimeConfigurableWrapper(childWrapper);
  397. childWrapper.setProxy(childElement);
  398. replaceChildren(childWrapper, childElement);
  399. }
  400. }
  401. /**
  402. * Return the type of task.
  403. *
  404. * @return the type of task.
  405. */
  406. public String getTaskType() {
  407. return taskType;
  408. }
  409. /**
  410. * Return the runtime configurable structure for this task.
  411. *
  412. * @return the runtime structure for this task.
  413. */
  414. protected RuntimeConfigurable getWrapper() {
  415. return wrapper;
  416. }
  417. /**
  418. * Bind a task to another; use this when configuring a newly created
  419. * task to do work on behalf of another.
  420. * Project, OwningTarget, TaskName, Location and Description are all copied
  421. *
  422. * Important: this method does not call {@link Task#init()}.
  423. * If you are creating a task to delegate work to, call {@link Task#init()}
  424. * to initialize it.
  425. *
  426. * @param owner owning target
  427. * @since Ant1.7
  428. */
  429. public final void bindToOwner(Task owner) {
  430. setProject(owner.getProject());
  431. setOwningTarget(owner.getOwningTarget());
  432. setTaskName(owner.getTaskName());
  433. setDescription(owner.getDescription());
  434. setLocation(owner.getLocation());
  435. setTaskType(owner.getTaskType());
  436. }
  437. }