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.

UnknownElement.java 19 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. * Copyright (c) 2000-2003 The Apache Software Foundation. All rights
  5. * reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. *
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if
  20. * any, must include the following acknowlegement:
  21. * "This product includes software developed by the
  22. * Apache Software Foundation (http://www.apache.org/)."
  23. * Alternately, this acknowlegement may appear in the software itself,
  24. * if and wherever such third-party acknowlegements normally appear.
  25. *
  26. * 4. The names "Ant" and "Apache Software
  27. * Foundation" must not be used to endorse or promote products derived
  28. * from this software without prior written permission. For written
  29. * permission, please contact apache@apache.org.
  30. *
  31. * 5. Products derived from this software may not be called "Apache"
  32. * nor may "Apache" appear in their names without prior written
  33. * permission of the Apache Group.
  34. *
  35. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46. * SUCH DAMAGE.
  47. * ====================================================================
  48. *
  49. * This software consists of voluntary contributions made by many
  50. * individuals on behalf of the Apache Software Foundation. For more
  51. * information on the Apache Software Foundation, please see
  52. * <http://www.apache.org/>.
  53. */
  54. package org.apache.tools.ant;
  55. import java.util.ArrayList;
  56. import java.util.Iterator;
  57. import java.util.List;
  58. import java.util.Locale;
  59. import java.io.IOException;
  60. /**
  61. * Wrapper class that holds all the information necessary to create a task
  62. * or data type that did not exist when Ant started, or one which
  63. * has had its definition updated to use a different implementation class.
  64. *
  65. * @author Stefan Bodewig
  66. */
  67. public class UnknownElement extends Task {
  68. /**
  69. * Holds the name of the task/type or nested child element of a
  70. * task/type that hasn't been defined at parser time or has
  71. * been redefined since original creation.
  72. */
  73. private String elementName;
  74. /**
  75. * Holds the namespace of the element.
  76. */
  77. private String namespace;
  78. /**
  79. * Holds the namespace qname of the element.
  80. */
  81. private String qname;
  82. /**
  83. * The real object after it has been loaded.
  84. */
  85. private Object realThing;
  86. /**
  87. * List of child elements (UnknownElements).
  88. */
  89. private List/*<UnknownElement>*/ children = null;
  90. /**
  91. * Creates an UnknownElement for the given element name.
  92. *
  93. * @param elementName The name of the unknown element.
  94. * Must not be <code>null</code>.
  95. */
  96. public UnknownElement (String elementName) {
  97. this.elementName = elementName;
  98. }
  99. /**
  100. * Returns the name of the XML element which generated this unknown
  101. * element.
  102. *
  103. * @return the name of the XML element which generated this unknown
  104. * element.
  105. */
  106. public String getTag() {
  107. return elementName;
  108. }
  109. /** Return the namespace of the XML element associated with this component.
  110. *
  111. * @return Namespace URI used in the xmlns declaration.
  112. */
  113. public String getNamespace() {
  114. return namespace;
  115. }
  116. /** Set the namespace of the XML element associated with this component.
  117. * This method is typically called by the XML processor.
  118. *
  119. * @param namespace URI used in the xmlns declaration.
  120. */
  121. public void setNamespace(String namespace) {
  122. this.namespace = namespace;
  123. }
  124. /** Return the qname of the XML element associated with this component.
  125. *
  126. * @return namespace Qname used in the element declaration.
  127. */
  128. public String getQName() {
  129. return qname;
  130. }
  131. /** Set the namespace qname of the XML element.
  132. * This method is typically called by the XML processor.
  133. *
  134. * @param qname the qualified name of the element
  135. */
  136. public void setQName(String qname) {
  137. this.qname = qname;
  138. }
  139. /**
  140. * Get the RuntimeConfigurable instance for this UnknownElement, containing
  141. * the configuration information.
  142. *
  143. * @return the configuration info.
  144. */
  145. public RuntimeConfigurable getWrapper() {
  146. return wrapper;
  147. }
  148. /**
  149. * Creates the real object instance and child elements, then configures
  150. * the attributes and text of the real object. This unknown element
  151. * is then replaced with the real object in the containing target's list
  152. * of children.
  153. *
  154. * @exception BuildException if the configuration fails
  155. */
  156. public void maybeConfigure() throws BuildException {
  157. //ProjectComponentHelper helper=ProjectComponentHelper.getProjectComponentHelper();
  158. //realThing = helper.createProjectComponent( this, getProject(), null,
  159. // this.getTag());
  160. configure(makeObject(this, getWrapper()));
  161. }
  162. /**
  163. * Configure the given object from this UnknownElement
  164. *
  165. * @param realObject the real object this UnknownElement is representing.
  166. *
  167. */
  168. public void configure(Object realObject) {
  169. realThing = realObject;
  170. getWrapper().setProxy(realThing);
  171. Task task = null;
  172. if (realThing instanceof Task) {
  173. task = (Task) realThing;
  174. task.setRuntimeConfigurableWrapper(getWrapper());
  175. // For Script to work. Ugly
  176. // The reference is replaced by RuntimeConfigurable
  177. this.getOwningTarget().replaceChild(this, (Task) realThing);
  178. }
  179. handleChildren(realThing, getWrapper());
  180. // configure attributes of the object and it's children. If it is
  181. // a task container, defer the configuration till the task container
  182. // attempts to use the task
  183. if (task != null) {
  184. task.maybeConfigure();
  185. } else {
  186. getWrapper().maybeConfigure(getProject());
  187. }
  188. }
  189. /**
  190. * Handles output sent to System.out by this task or its real task.
  191. *
  192. * @param output The output to log. Should not be <code>null</code>.
  193. */
  194. protected void handleOutput(String output) {
  195. if (realThing instanceof Task) {
  196. ((Task) realThing).handleOutput(output);
  197. } else {
  198. super.handleOutput(output);
  199. }
  200. }
  201. /**
  202. * @see Task#handleInput(byte[], int, int)
  203. *
  204. * @since Ant 1.6
  205. */
  206. protected int handleInput(byte[] buffer, int offset, int length)
  207. throws IOException {
  208. if (realThing instanceof Task) {
  209. return ((Task) realThing).handleInput(buffer, offset, length);
  210. } else {
  211. return super.handleInput(buffer, offset, length);
  212. }
  213. }
  214. /**
  215. * Handles output sent to System.out by this task or its real task.
  216. *
  217. * @param output The output to log. Should not be <code>null</code>.
  218. */
  219. protected void handleFlush(String output) {
  220. if (realThing instanceof Task) {
  221. ((Task) realThing).handleFlush(output);
  222. } else {
  223. super.handleFlush(output);
  224. }
  225. }
  226. /**
  227. * Handles error output sent to System.err by this task or its real task.
  228. *
  229. * @param output The error output to log. Should not be <code>null</code>.
  230. */
  231. protected void handleErrorOutput(String output) {
  232. if (realThing instanceof Task) {
  233. ((Task) realThing).handleErrorOutput(output);
  234. } else {
  235. super.handleErrorOutput(output);
  236. }
  237. }
  238. /**
  239. * Handles error output sent to System.err by this task or its real task.
  240. *
  241. * @param output The error output to log. Should not be <code>null</code>.
  242. */
  243. protected void handleErrorFlush(String output) {
  244. if (realThing instanceof Task) {
  245. ((Task) realThing).handleErrorOutput(output);
  246. } else {
  247. super.handleErrorOutput(output);
  248. }
  249. }
  250. /**
  251. * Executes the real object if it's a task. If it's not a task
  252. * (e.g. a data type) then this method does nothing.
  253. */
  254. public void execute() {
  255. if (realThing == null) {
  256. // plain impossible to get here, maybeConfigure should
  257. // have thrown an exception.
  258. throw new BuildException("Could not create task of type: "
  259. + elementName, getLocation());
  260. }
  261. if (realThing instanceof Task) {
  262. ((Task) realThing).execute();
  263. }
  264. // the task will not be reused ( a new init() will be called )
  265. // Let GC do its job
  266. realThing = null;
  267. }
  268. /**
  269. * Adds a child element to this element.
  270. *
  271. * @param child The child element to add. Must not be <code>null</code>.
  272. */
  273. public void addChild(UnknownElement child) {
  274. if (children == null) {
  275. children = new ArrayList();
  276. }
  277. children.add(child);
  278. }
  279. /**
  280. * Creates child elements, creates children of the children
  281. * (recursively), and sets attributes of the child elements.
  282. *
  283. * @param parent The configured object for the parent.
  284. * Must not be <code>null</code>.
  285. *
  286. * @param parentWrapper The wrapper containing child wrappers
  287. * to be configured. Must not be <code>null</code>
  288. * if there are any children.
  289. *
  290. * @exception BuildException if the children cannot be configured.
  291. */
  292. protected void handleChildren(Object parent,
  293. RuntimeConfigurable parentWrapper)
  294. throws BuildException {
  295. if (parent instanceof TypeAdapter) {
  296. parent = ((TypeAdapter) parent).getProxy();
  297. }
  298. Class parentClass = parent.getClass();
  299. IntrospectionHelper ih = IntrospectionHelper.getHelper(parentClass);
  300. if (children != null) {
  301. Iterator it = children.iterator();
  302. for (int i = 0; it.hasNext(); i++) {
  303. RuntimeConfigurable childWrapper = parentWrapper.getChild(i);
  304. UnknownElement child = (UnknownElement) it.next();
  305. if (!handleChild(ih, parent, child,
  306. childWrapper)) {
  307. if (!(parent instanceof TaskContainer)) {
  308. ih.throwNotSupported(getProject(), parent,
  309. child.getTag());
  310. } else {
  311. // a task container - anything could happen - just add the
  312. // child to the container
  313. TaskContainer container = (TaskContainer) parent;
  314. container.addTask(child);
  315. }
  316. }
  317. }
  318. }
  319. }
  320. /**
  321. * @return the component name - uses ProjectHelper#genComponentName()
  322. */
  323. protected String getComponentName() {
  324. return ProjectHelper.genComponentName(getNamespace(), getTag());
  325. }
  326. /**
  327. * Creates a named task or data type. If the real object is a task,
  328. * it is configured up to the init() stage.
  329. *
  330. * @param ue The unknown element to create the real object for.
  331. * Must not be <code>null</code>.
  332. * @param w Ignored in this implementation.
  333. *
  334. * @return the task or data type represented by the given unknown element.
  335. */
  336. protected Object makeObject(UnknownElement ue, RuntimeConfigurable w) {
  337. ComponentHelper helper = ComponentHelper.getComponentHelper(
  338. getProject());
  339. String name = ue.getComponentName();
  340. Object o = helper.createComponent(ue, ue.getNamespace(), name);
  341. if (o == null) {
  342. throw getNotFoundException("task or type", name);
  343. }
  344. if (o instanceof Task) {
  345. Task task = (Task) o;
  346. task.setOwningTarget(getOwningTarget());
  347. task.init();
  348. }
  349. return o;
  350. }
  351. /**
  352. * Creates a named task and configures it up to the init() stage.
  353. *
  354. * @param ue The UnknownElement to create the real task for.
  355. * Must not be <code>null</code>.
  356. * @param w Ignored.
  357. *
  358. * @return the task specified by the given unknown element, or
  359. * <code>null</code> if the task name is not recognised.
  360. */
  361. protected Task makeTask(UnknownElement ue, RuntimeConfigurable w) {
  362. Task task = getProject().createTask(ue.getTag());
  363. if (task != null) {
  364. task.setLocation(getLocation());
  365. // UnknownElement always has an associated target
  366. task.setOwningTarget(getOwningTarget());
  367. task.init();
  368. }
  369. return task;
  370. }
  371. /**
  372. * Returns a very verbose exception for when a task/data type cannot
  373. * be found.
  374. *
  375. * @param what The kind of thing being created. For example, when
  376. * a task name could not be found, this would be
  377. * <code>"task"</code>. Should not be <code>null</code>.
  378. * @param elementName The name of the element which could not be found.
  379. * Should not be <code>null</code>.
  380. *
  381. * @return a detailed description of what might have caused the problem.
  382. */
  383. protected BuildException getNotFoundException(String what,
  384. String elementName) {
  385. String lSep = System.getProperty("line.separator");
  386. String msg = "Could not create " + what + " of type: " + elementName
  387. + "." + lSep + lSep
  388. + "Ant could not find the task or a class this "
  389. + "task relies upon." + lSep + lSep
  390. + "This is common and has a number of causes; the usual " + lSep
  391. + "solutions are to read the manual pages then download and" + lSep
  392. + "install needed JAR files, or fix the build file: " + lSep
  393. + " - You have misspelt '" + elementName + "'." + lSep
  394. + " Fix: check your spelling." + lSep
  395. + " - The task needs an external JAR file to execute" + lSep
  396. + " and this is not found at the right place in the classpath." + lSep
  397. + " Fix: check the documentation for dependencies." + lSep
  398. + " Fix: declare the task." + lSep
  399. + " - The task is an Ant optional task and optional.jar is absent" + lSep
  400. + " Fix: look for optional.jar in ANT_HOME/lib, download if needed" + lSep
  401. + " - The task was not built into optional.jar as dependent" + lSep
  402. + " libraries were not found at build time." + lSep
  403. + " Fix: look in the JAR to verify, then rebuild with the needed" + lSep
  404. + " libraries, or download a release version from apache.org" + lSep
  405. + " - The build file was written for a later version of Ant" + lSep
  406. + " Fix: upgrade to at least the latest release version of Ant" + lSep
  407. + " - The task is not an Ant core or optional task " + lSep
  408. + " and needs to be declared using <taskdef>." + lSep
  409. + lSep
  410. + "Remember that for JAR files to be visible to Ant tasks implemented" + lSep
  411. + "in ANT_HOME/lib, the files must be in the same directory or on the" + lSep
  412. + "classpath" + lSep
  413. + lSep
  414. + "Please neither file bug reports on this problem, nor email the" + lSep
  415. + "Ant mailing lists, until all of these causes have been explored," + lSep
  416. + "as this is not an Ant bug.";
  417. return new BuildException(msg, getLocation());
  418. }
  419. /**
  420. * Returns the name to use in logging messages.
  421. *
  422. * @return the name to use in logging messages.
  423. */
  424. public String getTaskName() {
  425. //return elementName;
  426. return realThing == null
  427. || !(realThing instanceof Task) ? super.getTaskName()
  428. : ((Task) realThing).getTaskName();
  429. }
  430. /**
  431. * Returns the task instance after it has been created and if it is a task.
  432. *
  433. * @return a task instance or <code>null</code> if the real object is not
  434. * a task.
  435. */
  436. public Task getTask() {
  437. if (realThing instanceof Task) {
  438. return (Task) realThing;
  439. }
  440. return null;
  441. }
  442. /**
  443. * Return the configured object
  444. *
  445. * @return the real thing whatever it is
  446. *
  447. * @since ant 1.6
  448. */
  449. public Object getRealThing() {
  450. return realThing;
  451. }
  452. /**
  453. * Try to create a nested element of <code>parent</code> for the
  454. * given tag.
  455. *
  456. * @return whether the creation has been successful
  457. */
  458. private boolean handleChild(IntrospectionHelper ih,
  459. Object parent, UnknownElement child,
  460. RuntimeConfigurable childWrapper) {
  461. // backwards compatibility - element names of nested
  462. // elements have been all lower-case in Ant, except for
  463. // TaskContainers
  464. String childName = child.getTag().toLowerCase(Locale.US);
  465. if (ih.supportsNestedElement(childName)) {
  466. IntrospectionHelper.Creator creator =
  467. ih.getElementCreator(getProject(), parent, childName);
  468. creator.setPolyType(childWrapper.getPolyType());
  469. Object realChild = creator.create();
  470. childWrapper.setCreator(creator);
  471. childWrapper.setProxy(realChild);
  472. if (realChild instanceof Task) {
  473. Task childTask = (Task) realChild;
  474. childTask.setRuntimeConfigurableWrapper(childWrapper);
  475. childTask.setTaskName(childName);
  476. childTask.setTaskType(childName);
  477. childTask.setLocation(child.getLocation());
  478. }
  479. child.handleChildren(realChild, childWrapper);
  480. return true;
  481. }
  482. return false;
  483. }
  484. }