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

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