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.

ProjectHelperImpl2.java 39 KiB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013
  1. /*
  2. * The Apache Software License, Version 1.1
  3. *
  4. * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
  5. * reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. *
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. *
  19. * 3. The end-user documentation included with the redistribution, if
  20. * any, must include the following acknowlegement:
  21. * "This product includes software developed by the
  22. * Apache Software Foundation (http://www.apache.org/)."
  23. * Alternately, this acknowlegement may appear in the software itself,
  24. * if and wherever such third-party acknowlegements normally appear.
  25. *
  26. * 4. The names "The Jakarta Project", "Ant", and "Apache Software
  27. * Foundation" must not be used to endorse or promote products derived
  28. * from this software without prior written permission. For written
  29. * permission, please contact apache@apache.org.
  30. *
  31. * 5. Products derived from this software may not be called "Apache"
  32. * nor may "Apache" appear in their names without prior written
  33. * permission of the Apache Group.
  34. *
  35. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46. * SUCH DAMAGE.
  47. * ====================================================================
  48. *
  49. * This software consists of voluntary contributions made by many
  50. * individuals on behalf of the Apache Software Foundation. For more
  51. * information on the Apache Software Foundation, please see
  52. * <http://www.apache.org/>.
  53. */
  54. package org.apache.tools.ant.helper;
  55. import org.apache.tools.ant.*;
  56. import java.io.File;
  57. import java.io.FileInputStream;
  58. import java.io.FileNotFoundException;
  59. import java.io.IOException;
  60. import java.io.UnsupportedEncodingException;
  61. import java.util.Hashtable;
  62. import java.util.Vector;
  63. import java.util.Enumeration;
  64. import java.util.Locale;
  65. import java.util.Stack;
  66. import org.xml.sax.Locator;
  67. import org.xml.sax.InputSource;
  68. import org.xml.sax.SAXParseException;
  69. import org.xml.sax.XMLReader;
  70. import org.xml.sax.SAXException;
  71. import org.xml.sax.DocumentHandler;
  72. import org.xml.sax.Attributes;
  73. import org.xml.sax.AttributeList;
  74. import org.xml.sax.helpers.XMLReaderAdapter;
  75. import org.xml.sax.helpers.DefaultHandler;
  76. import org.xml.sax.helpers.AttributeListImpl;
  77. import org.apache.tools.ant.util.JAXPUtils;
  78. /**
  79. * Sax2 based project reader
  80. *
  81. * @author duncan@x180.com
  82. * @author Costin Manolache
  83. */
  84. public class ProjectHelperImpl2 extends ProjectHelper {
  85. /* Stateless */
  86. // singletons - since all state is in the context
  87. static AntHandler elementHandler=new ElementHandler();
  88. static AntHandler targetHandler=new TargetHandler();
  89. static AntHandler nestedElementHandler=new NestedElementHandler();
  90. static AntHandler mainHandler=new MainHandler();
  91. static AntHandler projectHandler=new ProjectHandler();
  92. /** Method to add several 'special' tasks that are specific
  93. * to this helper. In future we could use the properties file
  94. */
  95. private void hookSpecialTasks(Project project) {
  96. try {
  97. Class c=Class.forName("org.apache.tools.ant.types.SystemPath");
  98. project.addDataTypeDefinition( "systemPath" , c );
  99. c=Class.forName("org.apache.tools.ant.tasks.Import");
  100. project.addTaskDefinition( "import" , c );
  101. } catch (Exception ex ) {
  102. }
  103. }
  104. public void parse(Project project, Object source) throws BuildException {
  105. hookSpecialTasks(project);
  106. AntXmlContext context=new AntXmlContext(project, this);
  107. project.addReference( "ant.parsing.context", context );
  108. parse(project, source,new RootHandler(context));
  109. // XXX How to deal with description ??
  110. context.implicitTarget.execute();
  111. }
  112. /**
  113. * Parses the project file, configuring the project as it goes.
  114. *
  115. * @exception BuildException if the configuration is invalid or cannot
  116. * be read
  117. */
  118. public void parse(Project project, Object source, RootHandler handler) throws BuildException {
  119. AntXmlContext context=handler.context;
  120. if(source instanceof File) {
  121. context.buildFile=(File)source;
  122. // } else if( source instanceof InputStream ) {
  123. // } else if( source instanceof URL ) {
  124. // } else if( source instanceof InputSource ) {
  125. } else {
  126. throw new BuildException( "Source " + source.getClass().getName() +
  127. " not supported by this plugin" );
  128. }
  129. FileInputStream inputStream = null;
  130. InputSource inputSource = null;
  131. context.buildFile = new File(context.buildFile.getAbsolutePath());
  132. context.buildFileParent = new File(context.buildFile.getParent());
  133. try {
  134. /**
  135. * SAX 2 style parser used to parse the given file.
  136. */
  137. context.parser =JAXPUtils.getXMLReader();
  138. String uri = "file:" + context.buildFile.getAbsolutePath().replace('\\', '/');
  139. for (int index = uri.indexOf('#'); index != -1; index = uri.indexOf('#')) {
  140. uri = uri.substring(0, index) + "%23" + uri.substring(index+1);
  141. }
  142. inputStream = new FileInputStream(context.buildFile);
  143. inputSource = new InputSource(inputStream);
  144. inputSource.setSystemId(uri);
  145. project.log("parsing buildfile " + context.buildFile + " with URI = " + uri, Project.MSG_VERBOSE);
  146. DefaultHandler hb = handler;
  147. context.parser.setContentHandler(hb);
  148. context.parser.setEntityResolver(hb);
  149. context.parser.setErrorHandler(hb);
  150. context.parser.setDTDHandler(hb);
  151. context.parser.parse(inputSource);
  152. } catch(SAXParseException exc) {
  153. Location location =
  154. new Location(exc.getSystemId(), exc.getLineNumber(), exc.getColumnNumber());
  155. Throwable t = exc.getException();
  156. if (t instanceof BuildException) {
  157. BuildException be = (BuildException) t;
  158. if (be.getLocation() == Location.UNKNOWN_LOCATION) {
  159. be.setLocation(location);
  160. }
  161. throw be;
  162. }
  163. throw new BuildException(exc.getMessage(), t, location);
  164. }
  165. catch(SAXException exc) {
  166. Throwable t = exc.getException();
  167. if (t instanceof BuildException) {
  168. throw (BuildException) t;
  169. }
  170. throw new BuildException(exc.getMessage(), t);
  171. }
  172. catch(FileNotFoundException exc) {
  173. throw new BuildException(exc);
  174. }
  175. catch(UnsupportedEncodingException exc) {
  176. throw new BuildException("Encoding of project file is invalid.",exc);
  177. }
  178. catch(IOException exc) {
  179. throw new BuildException("Error reading project file: " +exc.getMessage(), exc);
  180. }
  181. finally {
  182. if (inputStream != null) {
  183. try {
  184. inputStream.close();
  185. }
  186. catch (IOException ioe) {
  187. // ignore this
  188. }
  189. }
  190. }
  191. }
  192. /**
  193. * The common superclass for all SAX event handlers used to parse
  194. * the configuration file.
  195. *
  196. * The context will hold all state information. At each time
  197. * there is one active handler for the current element. It can
  198. * use onStartChild() to set an alternate handler for the child.
  199. */
  200. public static class AntHandler {
  201. /**
  202. * Handles the start of an element. This base implementation does nothing.
  203. *
  204. * @param tag The name of the element being started.
  205. * Will not be <code>null</code>.
  206. * @param attrs Attributes of the element being started.
  207. * Will not be <code>null</code>.
  208. *
  209. * @exception SAXParseException if this method is not overridden, or in
  210. * case of error in an overridden version
  211. */
  212. public void onStartElement(String uri, String tag, String qname,
  213. Attributes attrs,
  214. AntXmlContext context)
  215. throws SAXParseException
  216. {
  217. }
  218. /**
  219. * Handles the start of an element. This base implementation just
  220. * throws an exception - you must override this method if you expect
  221. * child elements.
  222. *
  223. * @param tag The name of the element being started.
  224. * Will not be <code>null</code>.
  225. * @param attrs Attributes of the element being started.
  226. * Will not be <code>null</code>.
  227. *
  228. * @exception SAXParseException if this method is not overridden, or in
  229. * case of error in an overridden version
  230. */
  231. public AntHandler onStartChild(String uri, String tag, String qname,
  232. Attributes attrs,
  233. AntXmlContext context)
  234. throws SAXParseException
  235. {
  236. throw new SAXParseException("Unexpected element \"" + qname + " \"", context.locator);
  237. }
  238. public void onEndChild(String uri, String tag, String qname,
  239. AntXmlContext context)
  240. throws SAXParseException
  241. {
  242. }
  243. /**
  244. * Called when this element and all elements nested into it have been
  245. * handled (i.e. at the </end_tag_of_the_element> ).
  246. */
  247. public void onEndElement(String uri, String tag, AntXmlContext context) {
  248. }
  249. /**
  250. * Handles text within an element. This base implementation just
  251. * throws an exception, you must override it if you expect content.
  252. *
  253. * @param buf A character array of the text within the element.
  254. * Will not be <code>null</code>.
  255. * @param start The start element in the array.
  256. * @param count The number of characters to read from the array.
  257. *
  258. * @exception SAXParseException if this method is not overridden, or in
  259. * case of error in an overridden version
  260. */
  261. public void characters(char[] buf, int start, int count, AntXmlContext context)
  262. throws SAXParseException
  263. {
  264. String s = new String(buf, start, count).trim();
  265. if (s.length() > 0) {
  266. throw new SAXParseException("Unexpected text \"" + s + "\"", context.locator);
  267. }
  268. }
  269. }
  270. /** Context information for the ant processing.
  271. */
  272. public static class AntXmlContext {
  273. /** The project to configure. */
  274. private Project project;
  275. /** The configuration file to parse. */
  276. public File buildFile;
  277. /**
  278. * Parent directory of the build file. Used for resolving entities
  279. * and setting the project's base directory.
  280. */
  281. public File buildFileParent;
  282. /** Name of the current project */
  283. public String currentProjectName;
  284. /**
  285. * Locator for the configuration file parser.
  286. * Used for giving locations of errors etc.
  287. */
  288. Locator locator;
  289. // Do we need those ?
  290. public ProjectHelperImpl2 helper;
  291. org.xml.sax.XMLReader parser;
  292. /**
  293. * Target that all other targets will depend upon implicitly.
  294. *
  295. * <p>This holds all tasks and data type definitions that have
  296. * been placed outside of targets.</p>
  297. */
  298. Target implicitTarget = new Target();
  299. /** Current target ( no need for a stack as the processing model
  300. allows only one level of target ) */
  301. public Target currentTarget=null;
  302. /** The stack of RuntimeConfigurable2 wrapping the
  303. objects.
  304. */
  305. Vector wStack=new Vector();
  306. // Import stuff
  307. public boolean ignoreProjectTag=false;
  308. public static Hashtable importedFiles = new Hashtable();
  309. public static int importlevel = 0;
  310. public AntXmlContext(Project project, ProjectHelperImpl2 helper) {
  311. this.project=project;
  312. implicitTarget.setName("");
  313. this.helper=helper;
  314. }
  315. public Project getProject() {
  316. return project;
  317. }
  318. public RuntimeConfigurable2 currentWrapper() {
  319. if( wStack.size() < 1 ) return null;
  320. return (RuntimeConfigurable2)wStack.elementAt( wStack.size() - 1 );
  321. }
  322. public RuntimeConfigurable2 parentWrapper() {
  323. if( wStack.size() < 2 ) return null;
  324. return (RuntimeConfigurable2)wStack.elementAt( wStack.size() - 2 );
  325. }
  326. public void pushWrapper( RuntimeConfigurable2 wrapper ) {
  327. wStack.addElement(wrapper);
  328. }
  329. public void popWrapper() {
  330. if( wStack.size() > 0 )
  331. wStack.removeElementAt( wStack.size() - 1 );
  332. }
  333. public Vector getWrapperStack() {
  334. return wStack;
  335. }
  336. /**
  337. * Scans an attribute list for the <code>id</code> attribute and
  338. * stores a reference to the target object in the project if an
  339. * id is found.
  340. * <p>
  341. * This method was moved out of the configure method to allow
  342. * it to be executed at parse time.
  343. *
  344. * @see #configure(Object,AttributeList,Project)
  345. */
  346. void configureId(Object element, Attributes attr) {
  347. String id = attr.getValue("id");
  348. if (id != null) {
  349. project.addReference(id, element);
  350. }
  351. }
  352. }
  353. /**
  354. * Handler for ant processing. Uses a stack of AntHandlers to
  355. * implement each element ( the original parser used a recursive behavior,
  356. * with the implicit execution stack )
  357. */
  358. public static class RootHandler extends DefaultHandler {
  359. Stack antHandlers=new Stack();
  360. AntHandler currentHandler=null;
  361. AntXmlContext context;
  362. public RootHandler(AntXmlContext context) {
  363. currentHandler=ProjectHelperImpl2.mainHandler;
  364. antHandlers.push( currentHandler );
  365. this.context=context;
  366. }
  367. /**
  368. * Resolves file: URIs relative to the build file.
  369. *
  370. * @param publicId The public identifer, or <code>null</code>
  371. * if none is available. Ignored in this
  372. * implementation.
  373. * @param systemId The system identifier provided in the XML
  374. * document. Will not be <code>null</code>.
  375. */
  376. public InputSource resolveEntity(String publicId,
  377. String systemId) {
  378. context.getProject().log("resolving systemId: " + systemId, Project.MSG_VERBOSE);
  379. if (systemId.startsWith("file:")) {
  380. String path = systemId.substring(5);
  381. int index = path.indexOf("file:");
  382. // we only have to handle these for backward compatibility
  383. // since they are in the FAQ.
  384. while (index != -1) {
  385. path = path.substring(0, index) + path.substring(index + 5);
  386. index = path.indexOf("file:");
  387. }
  388. String entitySystemId = path;
  389. index = path.indexOf("%23");
  390. // convert these to #
  391. while (index != -1) {
  392. path = path.substring(0, index) + "#" + path.substring(index + 3);
  393. index = path.indexOf("%23");
  394. }
  395. File file = new File(path);
  396. if (!file.isAbsolute()) {
  397. file = new File(context.buildFileParent, path);
  398. }
  399. try {
  400. InputSource inputSource = new InputSource(new FileInputStream(file));
  401. inputSource.setSystemId("file:" + entitySystemId);
  402. return inputSource;
  403. } catch (FileNotFoundException fne) {
  404. context.getProject().log(file.getAbsolutePath()+" could not be found",
  405. Project.MSG_WARN);
  406. }
  407. }
  408. // use default if not file or file not found
  409. return null;
  410. }
  411. /**
  412. * Handles the start of a project element. A project handler is created
  413. * and initialised with the element name and attributes.
  414. *
  415. * @param tag The name of the element being started.
  416. * Will not be <code>null</code>.
  417. * @param attrs Attributes of the element being started.
  418. * Will not be <code>null</code>.
  419. *
  420. * @exception SAXParseException if the tag given is not
  421. * <code>"project"</code>
  422. */
  423. public void startElement(String uri, String tag, String qname, Attributes attrs)
  424. throws SAXParseException
  425. {
  426. AntHandler next=currentHandler.onStartChild(uri, tag, qname, attrs, context);
  427. antHandlers.push( currentHandler );
  428. currentHandler=next;
  429. currentHandler.onStartElement( uri, tag, qname, attrs, context );
  430. }
  431. /**
  432. * Sets the locator in the project helper for future reference.
  433. *
  434. * @param locator The locator used by the parser.
  435. * Will not be <code>null</code>.
  436. */
  437. public void setDocumentLocator(Locator locator) {
  438. context.locator = locator;
  439. }
  440. /**
  441. * Handles the end of an element. Any required clean-up is performed
  442. * by the onEndElement() method and then the original handler is restored to
  443. * the parser.
  444. *
  445. * @param name The name of the element which is ending.
  446. * Will not be <code>null</code>.
  447. *
  448. * @exception SAXException in case of error (not thrown in
  449. * this implementation)
  450. *
  451. */
  452. public void endElement(String uri, String name, String qName) throws SAXException {
  453. currentHandler.onEndElement(uri, name, context);
  454. AntHandler prev=(AntHandler)antHandlers.pop();
  455. currentHandler=prev;
  456. if( currentHandler!=null )
  457. currentHandler.onEndChild( uri, name, qName, context );
  458. }
  459. public void characters(char[] buf, int start, int count)
  460. throws SAXParseException
  461. {
  462. currentHandler.characters( buf, start, count, context );
  463. }
  464. }
  465. public static class MainHandler extends AntHandler {
  466. public AntHandler onStartChild(String uri, String name, String qname,
  467. Attributes attrs,
  468. AntXmlContext context)
  469. throws SAXParseException
  470. {
  471. if (qname.equals("project")) {
  472. return ProjectHelperImpl2.projectHandler;
  473. } else {
  474. throw new SAXParseException("Unexpected element \"" + qname + "\" " + name, context.locator);
  475. }
  476. }
  477. }
  478. /**
  479. * Handler for the top level "project" element.
  480. */
  481. public static class ProjectHandler extends AntHandler {
  482. /**
  483. * Initialisation routine called after handler creation
  484. * with the element name and attributes. The attributes which
  485. * this handler can deal with are: <code>"default"</code>,
  486. * <code>"name"</code>, <code>"id"</code> and <code>"basedir"</code>.
  487. *
  488. * @param tag Name of the element which caused this handler
  489. * to be created. Should not be <code>null</code>.
  490. * Ignored in this implementation.
  491. * @param attrs Attributes of the element which caused this
  492. * handler to be created. Must not be <code>null</code>.
  493. *
  494. * @exception SAXParseException if an unexpected attribute is
  495. * encountered or if the <code>"default"</code> attribute
  496. * is missing.
  497. */
  498. public void onStartElement(String uri, String tag, String qname,
  499. Attributes attrs,
  500. AntXmlContext context)
  501. throws SAXParseException
  502. {
  503. String id = null;
  504. String baseDir = null;
  505. Project project=context.getProject();
  506. for (int i = 0; i < attrs.getLength(); i++) {
  507. String key = attrs.getQName(i);
  508. String value = attrs.getValue(i);
  509. if (key.equals("default")) {
  510. if ( value != null && !value.equals("")) {
  511. if( !context.ignoreProjectTag )
  512. project.setDefaultTarget(value);
  513. }
  514. } else if (key.equals("name")) {
  515. if (value != null) {
  516. context.currentProjectName=value;
  517. if( !context.ignoreProjectTag ) {
  518. project.setName(value);
  519. project.addReference(value, project);
  520. }
  521. }
  522. } else if (key.equals("id")) {
  523. if (value != null) {
  524. // What's the difference between id and name ?
  525. if( !context.ignoreProjectTag ) {
  526. project.addReference(value, project);
  527. }
  528. }
  529. } else if (key.equals("basedir")) {
  530. if( !context.ignoreProjectTag )
  531. baseDir = value;
  532. } else {
  533. // XXX ignore attributes in a different NS ( maybe store them ? )
  534. throw new SAXParseException("Unexpected attribute \"" + attrs.getQName(i) + "\"", context.locator);
  535. }
  536. }
  537. if( context.ignoreProjectTag ) {
  538. // no further processing
  539. return;
  540. }
  541. // set explicitely before starting ?
  542. if (project.getProperty("basedir") != null) {
  543. project.setBasedir(project.getProperty("basedir"));
  544. } else {
  545. // Default for baseDir is the location of the build file.
  546. if (baseDir == null) {
  547. project.setBasedir(context.buildFileParent.getAbsolutePath());
  548. } else {
  549. // check whether the user has specified an absolute path
  550. if ((new File(baseDir)).isAbsolute()) {
  551. project.setBasedir(baseDir);
  552. } else {
  553. project.setBaseDir(project.resolveFile(baseDir,
  554. context.buildFileParent));
  555. }
  556. }
  557. }
  558. project.addTarget("", context.implicitTarget);
  559. context.currentTarget=context.implicitTarget;
  560. }
  561. /**
  562. * Handles the start of a top-level element within the project. An
  563. * appropriate handler is created and initialised with the details
  564. * of the element.
  565. *
  566. * @param tag The name of the element being started.
  567. * Will not be <code>null</code>.
  568. * @param attrs Attributes of the element being started.
  569. * Will not be <code>null</code>.
  570. *
  571. * @exception SAXParseException if the tag given is not
  572. * <code>"taskdef"</code>, <code>"typedef"</code>,
  573. * <code>"property"</code>, <code>"target"</code>
  574. * or a data type definition
  575. */
  576. public AntHandler onStartChild(String uri, String name, String qname,
  577. Attributes attrs,
  578. AntXmlContext context)
  579. throws SAXParseException
  580. {
  581. if (qname.equals("target")) {
  582. return ProjectHelperImpl2.targetHandler;
  583. } else {
  584. return ProjectHelperImpl2.elementHandler;
  585. }
  586. }
  587. }
  588. /**
  589. * Handler for "target" elements.
  590. */
  591. public static class TargetHandler extends AntHandler {
  592. /**
  593. * Initialisation routine called after handler creation
  594. * with the element name and attributes. The attributes which
  595. * this handler can deal with are: <code>"name"</code>,
  596. * <code>"depends"</code>, <code>"if"</code>,
  597. * <code>"unless"</code>, <code>"id"</code> and
  598. * <code>"description"</code>.
  599. *
  600. * @param tag Name of the element which caused this handler
  601. * to be created. Should not be <code>null</code>.
  602. * Ignored in this implementation.
  603. * @param attrs Attributes of the element which caused this
  604. * handler to be created. Must not be <code>null</code>.
  605. *
  606. * @exception SAXParseException if an unexpected attribute is encountered
  607. * or if the <code>"name"</code> attribute is missing.
  608. */
  609. public void onStartElement(String uri, String tag, String qname,
  610. Attributes attrs,
  611. AntXmlContext context)
  612. throws SAXParseException
  613. {
  614. String name = null;
  615. String depends = "";
  616. Project project=context.getProject();
  617. Target target = new Target();
  618. context.currentTarget=target;
  619. for (int i = 0; i < attrs.getLength(); i++) {
  620. String key = attrs.getQName(i);
  621. String value = attrs.getValue(i);
  622. if (key.equals("name")) {
  623. name = value;
  624. if( "".equals( name ) )
  625. throw new BuildException("name attribute must not be empty");
  626. } else if (key.equals("depends")) {
  627. depends = value;
  628. } else if (key.equals("if")) {
  629. target.setIf(value);
  630. } else if (key.equals("unless")) {
  631. target.setUnless(value);
  632. } else if (key.equals("id")) {
  633. if (value != null && !value.equals("")) {
  634. context.getProject().addReference(value, target);
  635. }
  636. } else if (key.equals("description")) {
  637. target.setDescription(value);
  638. } else {
  639. throw new SAXParseException("Unexpected attribute \"" + key + "\"", context.locator);
  640. }
  641. }
  642. if (name == null) {
  643. throw new SAXParseException("target element appears without a name attribute",
  644. context.locator);
  645. }
  646. Hashtable currentTargets = project.getTargets();
  647. // If the name has already beend defined ( import for example )
  648. if(currentTargets.containsKey(name)) {
  649. // Alter the name.
  650. if( context.currentProjectName != null ) {
  651. String newName=context.currentProjectName + "." + name;
  652. project.log("Already defined in main or a previous import, define "
  653. + name + " as " + newName,
  654. Project.MSG_VERBOSE);
  655. name=newName;
  656. } else {
  657. project.log("Already defined in main or a previous import, ignore "
  658. + name,
  659. Project.MSG_VERBOSE);
  660. name=null;
  661. }
  662. }
  663. if( name != null ) {
  664. target.setName(name);
  665. project.addOrReplaceTarget(name, target);
  666. }
  667. project.log("Targets are now: "+ currentTargets ,
  668. Project.MSG_VERBOSE);
  669. // take care of dependencies
  670. if (depends.length() > 0) {
  671. target.setDepends(depends);
  672. }
  673. }
  674. /**
  675. * Handles the start of an element within a target.
  676. *
  677. * @param tag The name of the element being started.
  678. * Will not be <code>null</code>.
  679. * @param attrs Attributes of the element being started.
  680. * Will not be <code>null</code>.
  681. *
  682. * @exception SAXParseException if an error occurs when initialising
  683. * the appropriate child handler
  684. */
  685. public AntHandler onStartChild(String uri, String name, String qname,
  686. Attributes attrs,
  687. AntXmlContext context)
  688. throws SAXParseException
  689. {
  690. return ProjectHelperImpl2.elementHandler;
  691. }
  692. public void onEndElement(String uri, String tag, AntXmlContext context) {
  693. context.currentTarget=context.implicitTarget;
  694. }
  695. }
  696. /**
  697. * Handler for all project elements ( tasks, data types )
  698. */
  699. public static class ElementHandler extends AntHandler {
  700. /**
  701. * Constructor.
  702. */
  703. public ElementHandler() {
  704. }
  705. /**
  706. * Initialisation routine called after handler creation
  707. * with the element name and attributes. This configures
  708. * the element with its attributes and sets it up with
  709. * its parent container (if any). Nested elements are then
  710. * added later as the parser encounters them.
  711. *
  712. * @param tag Name of the element which caused this handler
  713. * to be created. Must not be <code>null</code>.
  714. *
  715. * @param attrs Attributes of the element which caused this
  716. * handler to be created. Must not be <code>null</code>.
  717. *
  718. * @exception SAXParseException in case of error (not thrown in
  719. * this implementation)
  720. */
  721. public void onStartElement(String uri, String tag, String qname,
  722. Attributes attrs,
  723. AntXmlContext context)
  724. throws SAXParseException
  725. {
  726. RuntimeConfigurable2 parentWrapper=context.currentWrapper();
  727. RuntimeConfigurable2 wrapper=null;
  728. if (context.getProject().getDataTypeDefinitions().get(qname) != null) {
  729. try {
  730. Object element = context.getProject().createDataType(qname);
  731. if (element == null) {
  732. // can it happen ? We just checked that the type exists
  733. throw new BuildException("Unknown data type "+qname);
  734. }
  735. wrapper = new RuntimeConfigurable2(element, qname);
  736. wrapper.setAttributes2(attrs);
  737. context.currentTarget.addDataType(wrapper);
  738. } catch (BuildException exc) {
  739. throw new SAXParseException(exc.getMessage(), context.locator, exc);
  740. }
  741. } else {
  742. Task task=null;
  743. try {
  744. task = context.getProject().createTask(qname);
  745. } catch (BuildException e) {
  746. // swallow here, will be thrown again in
  747. // UnknownElement.maybeConfigure if the problem persists.
  748. }
  749. if (task == null) {
  750. task = new UnknownElement(qname);
  751. task.setProject(context.getProject());
  752. //XXX task.setTaskType(qname);
  753. task.setTaskName(qname);
  754. }
  755. task.setLocation(new Location(context.locator.getSystemId(),
  756. context.locator.getLineNumber(),
  757. context.locator.getColumnNumber()));
  758. context.configureId(task, attrs);
  759. task.setOwningTarget(context.currentTarget);
  760. Object parent=null;
  761. if( parentWrapper!=null ) {
  762. parent=parentWrapper.getProxy();
  763. }
  764. if( parent instanceof TaskContainer ) {
  765. // Task included in a TaskContainer
  766. ((TaskContainer)parent).addTask( task );
  767. } else {
  768. // Task included in a target ( including the default one ).
  769. context.currentTarget.addTask( task );
  770. }
  771. // container.addTask(task);
  772. task.init();
  773. wrapper=new RuntimeConfigurable2(task, task.getTaskName());
  774. wrapper.setAttributes2(attrs);
  775. if (parentWrapper != null) {
  776. parentWrapper.addChild(wrapper);
  777. }
  778. }
  779. context.pushWrapper( wrapper );
  780. }
  781. /**
  782. * Adds text to the task, using the wrapper
  783. *
  784. * @param buf A character array of the text within the element.
  785. * Will not be <code>null</code>.
  786. * @param start The start element in the array.
  787. * @param count The number of characters to read from the array.
  788. *
  789. * @exception SAXParseException if the element doesn't support text
  790. *
  791. * @see ProjectHelper#addText(Project,Object,char[],int,int)
  792. */
  793. public void characters(char[] buf, int start, int count,
  794. AntXmlContext context)
  795. throws SAXParseException
  796. {
  797. RuntimeConfigurable2 wrapper=context.currentWrapper();
  798. wrapper.addText(buf, start, count);
  799. }
  800. /**
  801. * Handles the start of an element within a target. Task containers
  802. * will always use another task handler, and all other tasks
  803. * will always use a nested element handler.
  804. *
  805. * @param tag The name of the element being started.
  806. * Will not be <code>null</code>.
  807. * @param attrs Attributes of the element being started.
  808. * Will not be <code>null</code>.
  809. *
  810. * @exception SAXParseException if an error occurs when initialising
  811. * the appropriate child handler
  812. */
  813. public AntHandler onStartChild(String uri, String tag, String qname,
  814. Attributes attrs,
  815. AntXmlContext context)
  816. throws SAXParseException
  817. {
  818. // this element
  819. RuntimeConfigurable2 wrapper=context.currentWrapper();
  820. Object element=wrapper.getProxy();
  821. if (element instanceof TaskContainer) {
  822. // task can contain other tasks - no other nested elements possible
  823. return ProjectHelperImpl2.elementHandler;
  824. }
  825. else {
  826. return ProjectHelperImpl2.nestedElementHandler;
  827. }
  828. }
  829. public void onEndElement(String uri, String tag, AntXmlContext context) {
  830. context.popWrapper();
  831. }
  832. public void onEndChild(String uri, String tag, String qname,
  833. AntXmlContext context)
  834. throws SAXParseException
  835. {
  836. }
  837. }
  838. /**
  839. * Handler for all nested properties. Same as ElementHandler, except that
  840. * it doesn't deal with DataTypes and doesn't support TaskContainer.
  841. *
  842. * This is the original behavior - I just made few changes to avoid duplicated
  843. * code.
  844. */
  845. public static class NestedElementHandler extends ElementHandler {
  846. /**
  847. * Constructor.
  848. */
  849. public NestedElementHandler() {
  850. }
  851. /**
  852. * Initialisation routine called after handler creation
  853. * with the element name and attributes. This configures
  854. * the element with its attributes and sets it up with
  855. * its parent container (if any). Nested elements are then
  856. * added later as the parser encounters them.
  857. *
  858. * @param tag Name of the element which caused this handler
  859. * to be created. Must not be <code>null</code>.
  860. *
  861. * @param attrs Attributes of the element which caused this
  862. * handler to be created. Must not be <code>null</code>.
  863. *
  864. * @exception SAXParseException in case of error, such as a
  865. * BuildException being thrown during configuration.
  866. */
  867. public void onStartElement(String uri, String propType, String qname,
  868. Attributes attrs,
  869. AntXmlContext context)
  870. throws SAXParseException
  871. {
  872. RuntimeConfigurable2 parentWrapper=context.currentWrapper();
  873. RuntimeConfigurable2 wrapper=null;
  874. try {
  875. Object element;
  876. Object parent=parentWrapper.getProxy();
  877. if (parent instanceof TaskAdapter) {
  878. parent = ((TaskAdapter) parent).getProxy();
  879. }
  880. String elementName = qname.toLowerCase(Locale.US);
  881. if (parent instanceof UnknownElement) {
  882. UnknownElement uc = new UnknownElement(elementName);
  883. uc.setProject(context.getProject());
  884. ((UnknownElement) parent).addChild(uc);
  885. element = uc;
  886. } else {
  887. Class parentClass = parent.getClass();
  888. IntrospectionHelper ih =
  889. IntrospectionHelper.getHelper(parentClass);
  890. element = ih.createElement(context.getProject(), parent, elementName);
  891. }
  892. context.configureId(element, attrs);
  893. wrapper = new RuntimeConfigurable2(element, qname);
  894. wrapper.setAttributes2(attrs);
  895. parentWrapper.addChild(wrapper);
  896. } catch (BuildException exc) {
  897. throw new SAXParseException(exc.getMessage(), context.locator, exc);
  898. }
  899. context.pushWrapper( wrapper );
  900. }
  901. }
  902. }