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

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