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.

ProjectHelper2.java 46 kB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117
  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.helper;
  19. import org.apache.tools.ant.BuildException;
  20. import org.apache.tools.ant.Location;
  21. import org.apache.tools.ant.MagicNames;
  22. import org.apache.tools.ant.Project;
  23. import org.apache.tools.ant.ProjectHelper;
  24. import org.apache.tools.ant.RuntimeConfigurable;
  25. import org.apache.tools.ant.Target;
  26. import org.apache.tools.ant.Task;
  27. import org.apache.tools.ant.UnknownElement;
  28. import org.apache.tools.ant.util.FileUtils;
  29. import org.apache.tools.ant.util.JAXPUtils;
  30. import org.xml.sax.Attributes;
  31. import org.xml.sax.InputSource;
  32. import org.xml.sax.Locator;
  33. import org.xml.sax.SAXException;
  34. import org.xml.sax.SAXParseException;
  35. import org.xml.sax.XMLReader;
  36. import org.xml.sax.helpers.DefaultHandler;
  37. import java.io.File;
  38. import java.io.FileInputStream;
  39. import java.io.FileNotFoundException;
  40. import java.io.IOException;
  41. import java.io.InputStream;
  42. import java.io.UnsupportedEncodingException;
  43. import java.net.URL;
  44. import java.util.HashMap;
  45. import java.util.Hashtable;
  46. import java.util.Iterator;
  47. import java.util.Map;
  48. import java.util.Stack;
  49. /**
  50. * Sax2 based project reader
  51. *
  52. */
  53. public class ProjectHelper2 extends ProjectHelper {
  54. /** Reference holding the (ordered) target Vector */
  55. public static final String REFID_TARGETS = "ant.targets";
  56. /* Stateless */
  57. // singletons - since all state is in the context
  58. private static AntHandler elementHandler = new ElementHandler();
  59. private static AntHandler targetHandler = new TargetHandler();
  60. private static AntHandler mainHandler = new MainHandler();
  61. private static AntHandler projectHandler = new ProjectHandler();
  62. /** Specific to ProjectHelper2 so not a true Ant "magic name:" */
  63. private static final String REFID_CONTEXT = "ant.parsing.context";
  64. /**
  65. * helper for path -> URI and URI -> path conversions.
  66. */
  67. private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
  68. /**
  69. * Whether this instance of ProjectHelper can parse an Antlib
  70. * descriptor given by the URL and return its content as an
  71. * UnknownElement ready to be turned into an Antlib task.
  72. *
  73. * <p>This implementation returns true.</p>
  74. *
  75. * @since Ant 1.8.0
  76. */
  77. public boolean canParseAntlibDescriptor(URL url) {
  78. return true;
  79. }
  80. /**
  81. * Parse the given URL as an antlib descriptor an return the
  82. * content as something that can be turned into an Antlib task.
  83. *
  84. * <p>simply delegates to {@link #parseUnknownElement
  85. * parseUnknownElement}.</p>
  86. *
  87. * @since ant 1.8.0
  88. */
  89. public UnknownElement parseAntlibDescriptor(Project containingProject,
  90. URL source) {
  91. return parseUnknownElement(containingProject, source);
  92. }
  93. /**
  94. * Parse an unknown element from a url
  95. *
  96. * @param project the current project
  97. * @param source the url containing the task
  98. * @return a configured task
  99. * @exception BuildException if an error occurs
  100. */
  101. public UnknownElement parseUnknownElement(Project project, URL source)
  102. throws BuildException {
  103. Target dummyTarget = new Target();
  104. dummyTarget.setProject(project);
  105. AntXMLContext context = new AntXMLContext(project);
  106. context.addTarget(dummyTarget);
  107. context.setImplicitTarget(dummyTarget);
  108. parse(context.getProject(), source, new RootHandler(context, elementHandler));
  109. Task[] tasks = dummyTarget.getTasks();
  110. if (tasks.length != 1) {
  111. throw new BuildException("No tasks defined");
  112. }
  113. return (UnknownElement) tasks[0];
  114. }
  115. /**
  116. * Parse a source xml input.
  117. *
  118. * @param project the current project
  119. * @param source the xml source
  120. * @exception BuildException if an error occurs
  121. */
  122. public void parse(Project project, Object source) throws BuildException {
  123. getImportStack().addElement(source);
  124. AntXMLContext context = null;
  125. context = (AntXMLContext) project.getReference(REFID_CONTEXT);
  126. if (context == null) {
  127. context = new AntXMLContext(project);
  128. project.addReference(REFID_CONTEXT, context);
  129. project.addReference(REFID_TARGETS, context.getTargets());
  130. }
  131. if (getImportStack().size() > 1) {
  132. // we are in an imported file.
  133. context.setIgnoreProjectTag(true);
  134. Target currentTarget = context.getCurrentTarget();
  135. Target currentImplicit = context.getImplicitTarget();
  136. Map currentTargets = context.getCurrentTargets();
  137. try {
  138. Target newCurrent = new Target();
  139. newCurrent.setProject(project);
  140. newCurrent.setName("");
  141. context.setCurrentTarget(newCurrent);
  142. context.setCurrentTargets(new HashMap());
  143. context.setImplicitTarget(newCurrent);
  144. parse(project, source, new RootHandler(context, mainHandler));
  145. newCurrent.execute();
  146. } finally {
  147. context.setCurrentTarget(currentTarget);
  148. context.setImplicitTarget(currentImplicit);
  149. context.setCurrentTargets(currentTargets);
  150. }
  151. } else {
  152. // top level file
  153. context.setCurrentTargets(new HashMap());
  154. parse(project, source, new RootHandler(context, mainHandler));
  155. // Execute the top-level target
  156. context.getImplicitTarget().execute();
  157. }
  158. }
  159. /**
  160. * Parses the project file, configuring the project as it goes.
  161. *
  162. * @param project the current project
  163. * @param source the xml source
  164. * @param handler the root handler to use (contains the current context)
  165. * @exception BuildException if the configuration is invalid or cannot
  166. * be read
  167. */
  168. public void parse(Project project, Object source, RootHandler handler) throws BuildException {
  169. AntXMLContext context = handler.context;
  170. File buildFile = null;
  171. URL url = null;
  172. String buildFileName = null;
  173. if (source instanceof File) {
  174. buildFile = (File) source;
  175. buildFile = FILE_UTILS.normalize(buildFile.getAbsolutePath());
  176. context.setBuildFile(buildFile);
  177. buildFileName = buildFile.toString();
  178. // } else if (source instanceof InputStream ) {
  179. } else if (source instanceof URL) {
  180. url = (URL) source;
  181. buildFileName = url.toString();
  182. // } else if (source instanceof InputSource ) {
  183. } else {
  184. throw new BuildException("Source " + source.getClass().getName()
  185. + " not supported by this plugin");
  186. }
  187. InputStream inputStream = null;
  188. InputSource inputSource = null;
  189. try {
  190. /**
  191. * SAX 2 style parser used to parse the given file.
  192. */
  193. XMLReader parser = JAXPUtils.getNamespaceXMLReader();
  194. String uri = null;
  195. if (buildFile != null) {
  196. uri = FILE_UTILS.toURI(buildFile.getAbsolutePath());
  197. inputStream = new FileInputStream(buildFile);
  198. } else {
  199. inputStream = url.openStream();
  200. uri = url.toString(); // ?? OK ??
  201. }
  202. inputSource = new InputSource(inputStream);
  203. if (uri != null) {
  204. inputSource.setSystemId(uri);
  205. }
  206. project.log("parsing buildfile " + buildFileName + " with URI = " + uri,
  207. Project.MSG_VERBOSE);
  208. DefaultHandler hb = handler;
  209. parser.setContentHandler(hb);
  210. parser.setEntityResolver(hb);
  211. parser.setErrorHandler(hb);
  212. parser.setDTDHandler(hb);
  213. parser.parse(inputSource);
  214. } catch (SAXParseException exc) {
  215. Location location = new Location(exc.getSystemId(), exc.getLineNumber(), exc
  216. .getColumnNumber());
  217. Throwable t = exc.getException();
  218. if (t instanceof BuildException) {
  219. BuildException be = (BuildException) t;
  220. if (be.getLocation() == Location.UNKNOWN_LOCATION) {
  221. be.setLocation(location);
  222. }
  223. throw be;
  224. }
  225. throw new BuildException(exc.getMessage(), t == null ? exc : t, location);
  226. } catch (SAXException exc) {
  227. Throwable t = exc.getException();
  228. if (t instanceof BuildException) {
  229. throw (BuildException) t;
  230. }
  231. throw new BuildException(exc.getMessage(), t == null ? exc : t);
  232. } catch (FileNotFoundException exc) {
  233. throw new BuildException(exc);
  234. } catch (UnsupportedEncodingException exc) {
  235. throw new BuildException("Encoding of project file " + buildFileName + " is invalid.",
  236. exc);
  237. } catch (IOException exc) {
  238. throw new BuildException("Error reading project file " + buildFileName + ": "
  239. + exc.getMessage(), exc);
  240. } finally {
  241. FileUtils.close(inputStream);
  242. }
  243. }
  244. /**
  245. * Returns main handler
  246. * @return main handler
  247. */
  248. protected static AntHandler getMainHandler() {
  249. return mainHandler;
  250. }
  251. /**
  252. * Sets main handler
  253. * @param handler new main handler
  254. */
  255. protected static void setMainHandler(AntHandler handler) {
  256. mainHandler = handler;
  257. }
  258. /**
  259. * Returns project handler
  260. * @return project handler
  261. */
  262. protected static AntHandler getProjectHandler() {
  263. return projectHandler;
  264. }
  265. /**
  266. * Sets project handler
  267. * @param handler new project handler
  268. */
  269. protected static void setProjectHandler(AntHandler handler) {
  270. projectHandler = handler;
  271. }
  272. /**
  273. * Returns target handler
  274. * @return target handler
  275. */
  276. protected static AntHandler getTargetHandler() {
  277. return targetHandler;
  278. }
  279. /**
  280. * Sets target handler
  281. * @param handler new target handler
  282. */
  283. protected static void setTargetHandler(AntHandler handler) {
  284. targetHandler = handler;
  285. }
  286. /**
  287. * Returns element handler
  288. * @return element handler
  289. */
  290. protected static AntHandler getElementHandler() {
  291. return elementHandler;
  292. }
  293. /**
  294. * Sets element handler
  295. * @param handler new element handler
  296. */
  297. protected static void setElementHandler(AntHandler handler) {
  298. elementHandler = handler;
  299. }
  300. /**
  301. * The common superclass for all SAX event handlers used to parse
  302. * the configuration file.
  303. *
  304. * The context will hold all state information. At each time
  305. * there is one active handler for the current element. It can
  306. * use onStartChild() to set an alternate handler for the child.
  307. */
  308. public static class AntHandler {
  309. /**
  310. * Handles the start of an element. This base implementation does
  311. * nothing.
  312. *
  313. * @param uri the namespace URI for the tag
  314. * @param tag The name of the element being started.
  315. * Will not be <code>null</code>.
  316. * @param qname The qualified name of the element.
  317. * @param attrs Attributes of the element being started.
  318. * Will not be <code>null</code>.
  319. * @param context The context that this element is in.
  320. *
  321. * @exception SAXParseException if this method is not overridden, or in
  322. * case of error in an overridden version
  323. */
  324. public void onStartElement(String uri, String tag, String qname, Attributes attrs,
  325. AntXMLContext context) throws SAXParseException {
  326. }
  327. /**
  328. * Handles the start of an element. This base implementation just
  329. * throws an exception - you must override this method if you expect
  330. * child elements.
  331. *
  332. * @param uri The namespace uri for this element.
  333. * @param tag The name of the element being started.
  334. * Will not be <code>null</code>.
  335. * @param qname The qualified name for this element.
  336. * @param attrs Attributes of the element being started.
  337. * Will not be <code>null</code>.
  338. * @param context The current context.
  339. * @return a handler (in the derived classes)
  340. *
  341. * @exception SAXParseException if this method is not overridden, or in
  342. * case of error in an overridden version
  343. */
  344. public AntHandler onStartChild(String uri, String tag, String qname, Attributes attrs,
  345. AntXMLContext context) throws SAXParseException {
  346. throw new SAXParseException("Unexpected element \"" + qname + " \"", context
  347. .getLocator());
  348. }
  349. /**
  350. * Handle the end of a element.
  351. *
  352. * @param uri the namespace uri of the element
  353. * @param tag the tag of the element
  354. * @param qname the qualified name of the element
  355. * @param context the current context
  356. * @exception SAXParseException if an error occurs
  357. */
  358. public void onEndChild(String uri, String tag, String qname, AntXMLContext context)
  359. throws SAXParseException {
  360. }
  361. /**
  362. * This method is called when this element and all elements nested into it have been
  363. * handled. I.e., this happens at the &lt;/end_tag_of_the_element&gt;.
  364. * @param uri the namespace uri for this element
  365. * @param tag the element name
  366. * @param context the current context
  367. */
  368. public void onEndElement(String uri, String tag, AntXMLContext context) {
  369. }
  370. /**
  371. * Handles text within an element. This base implementation just
  372. * throws an exception, you must override it if you expect content.
  373. *
  374. * @param buf A character array of the text within the element.
  375. * Will not be <code>null</code>.
  376. * @param start The start element in the array.
  377. * @param count The number of characters to read from the array.
  378. * @param context The current context.
  379. *
  380. * @exception SAXParseException if this method is not overridden, or in
  381. * case of error in an overridden version
  382. */
  383. public void characters(char[] buf, int start, int count, AntXMLContext context)
  384. throws SAXParseException {
  385. String s = new String(buf, start, count).trim();
  386. if (s.length() > 0) {
  387. throw new SAXParseException("Unexpected text \"" + s + "\"", context.getLocator());
  388. }
  389. }
  390. /**
  391. * Will be called every time a namespace is reached.
  392. * It'll verify if the ns was processed, and if not load the task definitions.
  393. * @param uri The namespace uri.
  394. */
  395. protected void checkNamespace(String uri) {
  396. }
  397. }
  398. /**
  399. * Handler for ant processing. Uses a stack of AntHandlers to
  400. * implement each element ( the original parser used a recursive behavior,
  401. * with the implicit execution stack )
  402. */
  403. public static class RootHandler extends DefaultHandler {
  404. private Stack antHandlers = new Stack();
  405. private AntHandler currentHandler = null;
  406. private AntXMLContext context;
  407. /**
  408. * Creates a new RootHandler instance.
  409. *
  410. * @param context The context for the handler.
  411. * @param rootHandler The handler for the root element.
  412. */
  413. public RootHandler(AntXMLContext context, AntHandler rootHandler) {
  414. currentHandler = rootHandler;
  415. antHandlers.push(currentHandler);
  416. this.context = context;
  417. }
  418. /**
  419. * Returns the current ant handler object.
  420. * @return the current ant handler.
  421. */
  422. public AntHandler getCurrentAntHandler() {
  423. return currentHandler;
  424. }
  425. /**
  426. * Resolves file: URIs relative to the build file.
  427. *
  428. * @param publicId The public identifier, or <code>null</code>
  429. * if none is available. Ignored in this
  430. * implementation.
  431. * @param systemId The system identifier provided in the XML
  432. * document. Will not be <code>null</code>.
  433. * @return an inputsource for this identifier
  434. */
  435. public InputSource resolveEntity(String publicId, String systemId) {
  436. context.getProject().log("resolving systemId: " + systemId, Project.MSG_VERBOSE);
  437. if (systemId.startsWith("file:")) {
  438. String path = FILE_UTILS.fromURI(systemId);
  439. File file = new File(path);
  440. if (!file.isAbsolute()) {
  441. file = FILE_UTILS.resolveFile(context.getBuildFileParent(), path);
  442. context.getProject().log(
  443. "Warning: '" + systemId + "' in " + context.getBuildFile()
  444. + " should be expressed simply as '" + path.replace('\\', '/')
  445. + "' for compliance with other XML tools", Project.MSG_WARN);
  446. }
  447. context.getProject().log("file=" + file, Project.MSG_DEBUG);
  448. try {
  449. InputSource inputSource = new InputSource(new FileInputStream(file));
  450. inputSource.setSystemId(FILE_UTILS.toURI(file.getAbsolutePath()));
  451. return inputSource;
  452. } catch (FileNotFoundException fne) {
  453. context.getProject().log(file.getAbsolutePath() + " could not be found",
  454. Project.MSG_WARN);
  455. }
  456. }
  457. // use default if not file or file not found
  458. context.getProject().log("could not resolve systemId", Project.MSG_DEBUG);
  459. return null;
  460. }
  461. /**
  462. * Handles the start of a project element. A project handler is created
  463. * and initialised with the element name and attributes.
  464. *
  465. * @param uri The namespace uri for this element.
  466. * @param tag The name of the element being started.
  467. * Will not be <code>null</code>.
  468. * @param qname The qualified name for this element.
  469. * @param attrs Attributes of the element being started.
  470. * Will not be <code>null</code>.
  471. *
  472. * @exception org.xml.sax.SAXParseException if the tag given is not
  473. * <code>"project"</code>
  474. */
  475. public void startElement(String uri, String tag, String qname, Attributes attrs)
  476. throws SAXParseException {
  477. AntHandler next = currentHandler.onStartChild(uri, tag, qname, attrs, context);
  478. antHandlers.push(currentHandler);
  479. currentHandler = next;
  480. currentHandler.onStartElement(uri, tag, qname, attrs, context);
  481. }
  482. /**
  483. * Sets the locator in the project helper for future reference.
  484. *
  485. * @param locator The locator used by the parser.
  486. * Will not be <code>null</code>.
  487. */
  488. public void setDocumentLocator(Locator locator) {
  489. context.setLocator(locator);
  490. }
  491. /**
  492. * Handles the end of an element. Any required clean-up is performed
  493. * by the onEndElement() method and then the original handler is restored to the parser.
  494. *
  495. * @param uri The namespace URI for this element.
  496. * @param name The name of the element which is ending.
  497. * Will not be <code>null</code>.
  498. * @param qName The qualified name for this element.
  499. *
  500. * @exception SAXException in case of error (not thrown in this implementation)
  501. */
  502. public void endElement(String uri, String name, String qName) throws SAXException {
  503. currentHandler.onEndElement(uri, name, context);
  504. AntHandler prev = (AntHandler) antHandlers.pop();
  505. currentHandler = prev;
  506. if (currentHandler != null) {
  507. currentHandler.onEndChild(uri, name, qName, context);
  508. }
  509. }
  510. /**
  511. * Handle text within an element, calls currentHandler.characters.
  512. *
  513. * @param buf A character array of the test.
  514. * @param start The start offset in the array.
  515. * @param count The number of characters to read.
  516. * @exception SAXParseException if an error occurs
  517. */
  518. public void characters(char[] buf, int start, int count) throws SAXParseException {
  519. currentHandler.characters(buf, start, count, context);
  520. }
  521. /**
  522. * Start a namespace prefix to uri mapping
  523. *
  524. * @param prefix the namespace prefix
  525. * @param uri the namespace uri
  526. */
  527. public void startPrefixMapping(String prefix, String uri) {
  528. context.startPrefixMapping(prefix, uri);
  529. }
  530. /**
  531. * End a namepace prefix to uri mapping
  532. *
  533. * @param prefix the prefix that is not mapped anymore
  534. */
  535. public void endPrefixMapping(String prefix) {
  536. context.endPrefixMapping(prefix);
  537. }
  538. }
  539. /**
  540. * The main handler - it handles the &lt;project&gt; tag.
  541. *
  542. * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler
  543. */
  544. public static class MainHandler extends AntHandler {
  545. /**
  546. * Handle the project tag
  547. *
  548. * @param uri The namespace uri.
  549. * @param name The element tag.
  550. * @param qname The element qualified name.
  551. * @param attrs The attributes of the element.
  552. * @param context The current context.
  553. * @return The project handler that handles subelements of project
  554. * @exception SAXParseException if the qualified name is not "project".
  555. */
  556. public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs,
  557. AntXMLContext context) throws SAXParseException {
  558. if (name.equals("project")
  559. && (uri.equals("") || uri.equals(ANT_CORE_URI))) {
  560. return ProjectHelper2.projectHandler;
  561. }
  562. if (name.equals(qname)) {
  563. throw new SAXParseException("Unexpected element \"{" + uri
  564. + "}" + name + "\" {" + ANT_CORE_URI + "}" + name, context.getLocator());
  565. }
  566. throw new SAXParseException("Unexpected element \"" + qname
  567. + "\" " + name, context.getLocator());
  568. }
  569. }
  570. /**
  571. * Handler for the top level "project" element.
  572. */
  573. public static class ProjectHandler extends AntHandler {
  574. /**
  575. * Initialisation routine called after handler creation
  576. * with the element name and attributes. The attributes which
  577. * this handler can deal with are: <code>"default"</code>,
  578. * <code>"name"</code>, <code>"id"</code> and <code>"basedir"</code>.
  579. *
  580. * @param uri The namespace URI for this element.
  581. * @param tag Name of the element which caused this handler
  582. * to be created. Should not be <code>null</code>.
  583. * Ignored in this implementation.
  584. * @param qname The qualified name for this element.
  585. * @param attrs Attributes of the element which caused this
  586. * handler to be created. Must not be <code>null</code>.
  587. * @param context The current context.
  588. *
  589. * @exception SAXParseException if an unexpected attribute is
  590. * encountered or if the <code>"default"</code> attribute
  591. * is missing.
  592. */
  593. public void onStartElement(String uri, String tag, String qname, Attributes attrs,
  594. AntXMLContext context) throws SAXParseException {
  595. String baseDir = null;
  596. boolean nameAttributeSet = false;
  597. Project project = context.getProject();
  598. // Set the location of the implicit target associated with the project tag
  599. context.getImplicitTarget().setLocation(new Location(context.getLocator()));
  600. /** XXX I really don't like this - the XML processor is still
  601. * too 'involved' in the processing. A better solution (IMO)
  602. * would be to create UE for Project and Target too, and
  603. * then process the tree and have Project/Target deal with
  604. * its attributes ( similar with Description ).
  605. *
  606. * If we eventually switch to ( or add support for ) DOM,
  607. * things will work smoothly - UE can be avoided almost completely
  608. * ( it could still be created on demand, for backward compatibility )
  609. */
  610. for (int i = 0; i < attrs.getLength(); i++) {
  611. String attrUri = attrs.getURI(i);
  612. if (attrUri != null && !attrUri.equals("") && !attrUri.equals(uri)) {
  613. continue; // Ignore attributes from unknown uris
  614. }
  615. String key = attrs.getLocalName(i);
  616. String value = attrs.getValue(i);
  617. if (key.equals("default")) {
  618. if (value != null && !value.equals("")) {
  619. if (!context.isIgnoringProjectTag()) {
  620. project.setDefault(value);
  621. }
  622. }
  623. } else if (key.equals("name")) {
  624. if (value != null) {
  625. context.setCurrentProjectName(value);
  626. nameAttributeSet = true;
  627. if (!context.isIgnoringProjectTag()) {
  628. project.setName(value);
  629. project.addReference(value, project);
  630. }
  631. }
  632. } else if (key.equals("id")) {
  633. if (value != null) {
  634. // What's the difference between id and name ?
  635. if (!context.isIgnoringProjectTag()) {
  636. project.addReference(value, project);
  637. }
  638. }
  639. } else if (key.equals("basedir")) {
  640. if (!context.isIgnoringProjectTag()) {
  641. baseDir = value;
  642. }
  643. } else {
  644. // XXX ignore attributes in a different NS ( maybe store them ? )
  645. throw new SAXParseException("Unexpected attribute \"" + attrs.getQName(i)
  646. + "\"", context.getLocator());
  647. }
  648. }
  649. // XXX Move to Project ( so it is shared by all helpers )
  650. String antFileProp = "ant.file." + context.getCurrentProjectName();
  651. String dup = project.getProperty(antFileProp);
  652. if (dup != null && nameAttributeSet) {
  653. File dupFile = new File(dup);
  654. if (context.isIgnoringProjectTag() && !dupFile.equals(context.getBuildFile())) {
  655. project.log("Duplicated project name in import. Project "
  656. + context.getCurrentProjectName() + " defined first in " + dup
  657. + " and again in " + context.getBuildFile(), Project.MSG_WARN);
  658. }
  659. }
  660. if (context.getBuildFile() != null && nameAttributeSet) {
  661. project.setUserProperty(
  662. MagicNames.ANT_FILE + "." + context.getCurrentProjectName(), context
  663. .getBuildFile().toString());
  664. }
  665. if (context.isIgnoringProjectTag()) {
  666. // no further processing
  667. return;
  668. }
  669. // set explicitly before starting ?
  670. if (project.getProperty("basedir") != null) {
  671. project.setBasedir(project.getProperty("basedir"));
  672. } else {
  673. // Default for baseDir is the location of the build file.
  674. if (baseDir == null) {
  675. project.setBasedir(context.getBuildFileParent().getAbsolutePath());
  676. } else {
  677. // check whether the user has specified an absolute path
  678. if ((new File(baseDir)).isAbsolute()) {
  679. project.setBasedir(baseDir);
  680. } else {
  681. project.setBaseDir(FILE_UTILS.resolveFile(context.getBuildFileParent(),
  682. baseDir));
  683. }
  684. }
  685. }
  686. project.addTarget("", context.getImplicitTarget());
  687. context.setCurrentTarget(context.getImplicitTarget());
  688. }
  689. /**
  690. * Handles the start of a top-level element within the project. An
  691. * appropriate handler is created and initialised with the details
  692. * of the element.
  693. *
  694. * @param uri The namespace URI for this element.
  695. * @param name The name of the element being started.
  696. * Will not be <code>null</code>.
  697. * @param qname The qualified name for this element.
  698. * @param attrs Attributes of the element being started.
  699. * Will not be <code>null</code>.
  700. * @param context The context for this element.
  701. * @return a target or an element handler.
  702. *
  703. * @exception org.xml.sax.SAXParseException if the tag given is not
  704. * <code>"taskdef"</code>, <code>"typedef"</code>,
  705. * <code>"property"</code>, <code>"target"</code>
  706. * or a data type definition
  707. */
  708. public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs,
  709. AntXMLContext context) throws SAXParseException {
  710. return name.equals("target") && (uri.equals("") || uri.equals(ANT_CORE_URI))
  711. ? ProjectHelper2.targetHandler : ProjectHelper2.elementHandler;
  712. }
  713. }
  714. /**
  715. * Handler for "target" elements.
  716. */
  717. public static class TargetHandler extends AntHandler {
  718. /**
  719. * Initialisation routine called after handler creation
  720. * with the element name and attributes. The attributes which
  721. * this handler can deal with are: <code>"name"</code>,
  722. * <code>"depends"</code>, <code>"if"</code>,
  723. * <code>"unless"</code>, <code>"id"</code> and
  724. * <code>"description"</code>.
  725. *
  726. * @param uri The namespace URI for this element.
  727. * @param tag Name of the element which caused this handler
  728. * to be created. Should not be <code>null</code>.
  729. * Ignored in this implementation.
  730. * @param qname The qualified name for this element.
  731. * @param attrs Attributes of the element which caused this
  732. * handler to be created. Must not be <code>null</code>.
  733. * @param context The current context.
  734. *
  735. * @exception SAXParseException if an unexpected attribute is encountered
  736. * or if the <code>"name"</code> attribute is missing.
  737. */
  738. public void onStartElement(String uri, String tag, String qname, Attributes attrs,
  739. AntXMLContext context) throws SAXParseException {
  740. String name = null;
  741. String depends = "";
  742. Project project = context.getProject();
  743. Target target = new Target();
  744. target.setProject(project);
  745. target.setLocation(new Location(context.getLocator()));
  746. context.addTarget(target);
  747. for (int i = 0; i < attrs.getLength(); i++) {
  748. String attrUri = attrs.getURI(i);
  749. if (attrUri != null && !attrUri.equals("") && !attrUri.equals(uri)) {
  750. continue; // Ignore attributes from unknown uris
  751. }
  752. String key = attrs.getLocalName(i);
  753. String value = attrs.getValue(i);
  754. if (key.equals("name")) {
  755. name = value;
  756. if ("".equals(name)) {
  757. throw new BuildException("name attribute must " + "not be empty");
  758. }
  759. } else if (key.equals("depends")) {
  760. depends = value;
  761. } else if (key.equals("if")) {
  762. target.setIf(value);
  763. } else if (key.equals("unless")) {
  764. target.setUnless(value);
  765. } else if (key.equals("id")) {
  766. if (value != null && !value.equals("")) {
  767. context.getProject().addReference(value, target);
  768. }
  769. } else if (key.equals("description")) {
  770. target.setDescription(value);
  771. } else {
  772. throw new SAXParseException("Unexpected attribute \"" + key + "\"", context
  773. .getLocator());
  774. }
  775. }
  776. if (name == null) {
  777. throw new SAXParseException("target element appears without a name attribute",
  778. context.getLocator());
  779. }
  780. String prefix = null;
  781. boolean isInIncludeMode =
  782. context.isIgnoringProjectTag() && isInIncludeMode();
  783. String sep = getCurrentPrefixSeparator();
  784. if (isInIncludeMode) {
  785. prefix = getTargetPrefix(context);
  786. if (prefix == null) {
  787. throw new BuildException("can't include build file "
  788. + context.getBuildFile()
  789. + ", no as attribute has been given"
  790. + " and the project tag doesn't"
  791. + " specify a name attribute");
  792. }
  793. name = prefix + sep + name;
  794. }
  795. // Check if this target is in the current build file
  796. if (context.getCurrentTargets().get(name) != null) {
  797. throw new BuildException("Duplicate target '" + name + "'",
  798. target.getLocation());
  799. }
  800. Hashtable projectTargets = project.getTargets();
  801. boolean usedTarget = false;
  802. // If the name has not already been defined define it
  803. if (projectTargets.containsKey(name)) {
  804. project.log("Already defined in main or a previous import, ignore " + name,
  805. Project.MSG_VERBOSE);
  806. } else {
  807. target.setName(name);
  808. context.getCurrentTargets().put(name, target);
  809. project.addOrReplaceTarget(name, target);
  810. usedTarget = true;
  811. }
  812. if (depends.length() > 0) {
  813. if (!isInIncludeMode) {
  814. target.setDepends(depends);
  815. } else {
  816. for (Iterator iter =
  817. Target.parseDepends(depends, name).iterator();
  818. iter.hasNext(); ) {
  819. target.addDependency(prefix + sep + iter.next());
  820. }
  821. }
  822. }
  823. if (!isInIncludeMode && context.isIgnoringProjectTag()
  824. && (prefix = getTargetPrefix(context)) != null) {
  825. // In an imported file (and not completely
  826. // ignoring the project tag or having a preconfigured prefix)
  827. String newName = prefix + sep + name;
  828. Target newTarget = usedTarget ? new Target(target) : target;
  829. newTarget.setName(newName);
  830. context.getCurrentTargets().put(newName, newTarget);
  831. project.addOrReplaceTarget(newName, newTarget);
  832. }
  833. }
  834. private String getTargetPrefix(AntXMLContext context) {
  835. String configuredValue = getCurrentTargetPrefix();
  836. if (configuredValue != null && configuredValue.length() == 0) {
  837. configuredValue = null;
  838. }
  839. if (configuredValue != null) {
  840. return configuredValue;
  841. }
  842. String projectName = context.getCurrentProjectName();
  843. if ("".equals(projectName)) {
  844. projectName = null;
  845. }
  846. // help nested include tasks
  847. if (projectName != null) {
  848. setCurrentTargetPrefix(projectName);
  849. }
  850. return projectName;
  851. }
  852. /**
  853. * Handles the start of an element within a target.
  854. *
  855. * @param uri The namespace URI for this element.
  856. * @param name The name of the element being started.
  857. * Will not be <code>null</code>.
  858. * @param qname The qualified name for this element.
  859. * @param attrs Attributes of the element being started.
  860. * Will not be <code>null</code>.
  861. * @param context The current context.
  862. * @return an element handler.
  863. *
  864. * @exception SAXParseException if an error occurs when initialising
  865. * the appropriate child handler
  866. */
  867. public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs,
  868. AntXMLContext context) throws SAXParseException {
  869. return ProjectHelper2.elementHandler;
  870. }
  871. /**
  872. * Handle the end of the project, sets the current target of the
  873. * context to be the implicit target.
  874. *
  875. * @param uri The namespace URI of the element.
  876. * @param tag The name of the element.
  877. * @param context The current context.
  878. */
  879. public void onEndElement(String uri, String tag, AntXMLContext context) {
  880. context.setCurrentTarget(context.getImplicitTarget());
  881. }
  882. }
  883. /**
  884. * Handler for all project elements ( tasks, data types )
  885. */
  886. public static class ElementHandler extends AntHandler {
  887. /**
  888. * Constructor.
  889. */
  890. public ElementHandler() {
  891. }
  892. /**
  893. * Initialisation routine called after handler creation
  894. * with the element name and attributes. This configures
  895. * the element with its attributes and sets it up with
  896. * its parent container (if any). Nested elements are then
  897. * added later as the parser encounters them.
  898. *
  899. * @param uri The namespace URI for this element.
  900. * @param tag Name of the element which caused this handler
  901. * to be created. Must not be <code>null</code>.
  902. * @param qname The qualified name for this element.
  903. * @param attrs Attributes of the element which caused this
  904. * handler to be created. Must not be <code>null</code>.
  905. * @param context The current context.
  906. *
  907. * @exception SAXParseException in case of error (not thrown in
  908. * this implementation)
  909. */
  910. public void onStartElement(String uri, String tag, String qname, Attributes attrs,
  911. AntXMLContext context) throws SAXParseException {
  912. RuntimeConfigurable parentWrapper = context.currentWrapper();
  913. Object parent = null;
  914. if (parentWrapper != null) {
  915. parent = parentWrapper.getProxy();
  916. }
  917. /* UnknownElement is used for tasks and data types - with
  918. delayed eval */
  919. UnknownElement task = new UnknownElement(tag);
  920. task.setProject(context.getProject());
  921. task.setNamespace(uri);
  922. task.setQName(qname);
  923. task.setTaskType(ProjectHelper.genComponentName(task.getNamespace(), tag));
  924. task.setTaskName(qname);
  925. Location location = new Location(context.getLocator().getSystemId(), context
  926. .getLocator().getLineNumber(), context.getLocator().getColumnNumber());
  927. task.setLocation(location);
  928. task.setOwningTarget(context.getCurrentTarget());
  929. if (parent != null) {
  930. // Nested element
  931. ((UnknownElement) parent).addChild(task);
  932. } else {
  933. // Task included in a target ( including the default one ).
  934. context.getCurrentTarget().addTask(task);
  935. }
  936. context.configureId(task, attrs);
  937. // container.addTask(task);
  938. // This is a nop in UE: task.init();
  939. RuntimeConfigurable wrapper = new RuntimeConfigurable(task, task.getTaskName());
  940. for (int i = 0; i < attrs.getLength(); i++) {
  941. String name = attrs.getLocalName(i);
  942. String attrUri = attrs.getURI(i);
  943. if (attrUri != null && !attrUri.equals("") && !attrUri.equals(uri)) {
  944. name = attrUri + ":" + attrs.getQName(i);
  945. }
  946. String value = attrs.getValue(i);
  947. // PR: Hack for ant-type value
  948. // an ant-type is a component name which can
  949. // be namespaced, need to extract the name
  950. // and convert from qualified name to uri/name
  951. if (ANT_TYPE.equals(name)
  952. || (ANT_CORE_URI.equals(attrUri)
  953. && ANT_TYPE.equals(attrs.getLocalName(i)))) {
  954. name = ANT_TYPE;
  955. int index = value.indexOf(":");
  956. if (index >= 0) {
  957. String prefix = value.substring(0, index);
  958. String mappedUri = context.getPrefixMapping(prefix);
  959. if (mappedUri == null) {
  960. throw new BuildException("Unable to find XML NS prefix \"" + prefix
  961. + "\"");
  962. }
  963. value = ProjectHelper.genComponentName(mappedUri, value
  964. .substring(index + 1));
  965. }
  966. }
  967. wrapper.setAttribute(name, value);
  968. }
  969. if (parentWrapper != null) {
  970. parentWrapper.addChild(wrapper);
  971. }
  972. context.pushWrapper(wrapper);
  973. }
  974. /**
  975. * Adds text to the task, using the wrapper
  976. *
  977. * @param buf A character array of the text within the element.
  978. * Will not be <code>null</code>.
  979. * @param start The start element in the array.
  980. * @param count The number of characters to read from the array.
  981. * @param context The current context.
  982. *
  983. * @exception SAXParseException if the element doesn't support text
  984. *
  985. * @see ProjectHelper#addText(Project,java.lang.Object,char[],int,int)
  986. */
  987. public void characters(char[] buf, int start, int count,
  988. AntXMLContext context) throws SAXParseException {
  989. RuntimeConfigurable wrapper = context.currentWrapper();
  990. wrapper.addText(buf, start, count);
  991. }
  992. /**
  993. * Handles the start of an element within a target. Task containers
  994. * will always use another task handler, and all other tasks
  995. * will always use a nested element handler.
  996. *
  997. * @param uri The namespace URI for this element.
  998. * @param tag The name of the element being started.
  999. * Will not be <code>null</code>.
  1000. * @param qname The qualified name for this element.
  1001. * @param attrs Attributes of the element being started.
  1002. * Will not be <code>null</code>.
  1003. * @param context The current context.
  1004. * @return The handler for elements.
  1005. *
  1006. * @exception SAXParseException if an error occurs when initialising
  1007. * the appropriate child handler
  1008. */
  1009. public AntHandler onStartChild(String uri, String tag, String qname, Attributes attrs,
  1010. AntXMLContext context) throws SAXParseException {
  1011. return ProjectHelper2.elementHandler;
  1012. }
  1013. /**
  1014. * Handles the end of the element. This pops the wrapper from
  1015. * the context.
  1016. *
  1017. * @param uri The namespace URI for the element.
  1018. * @param tag The name of the element.
  1019. * @param context The current context.
  1020. */
  1021. public void onEndElement(String uri, String tag, AntXMLContext context) {
  1022. context.popWrapper();
  1023. }
  1024. }
  1025. }