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

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259
  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. public void parse(Project project, Object source) throws BuildException {
  87. // Hook our internal tasks. XXX refactor
  88. try {
  89. Class c=Class.forName("org.apache.tools.ant.types.SystemPath");
  90. project.addDataTypeDefinition( "systemPath" , c );
  91. c=Class.forName("org.apache.tools.ant.tasks.Import");
  92. project.addTaskDefinition( "import" , c );
  93. } catch (Exception ex ) {
  94. }
  95. AntXmlContext context=new AntXmlContext(this);
  96. AntXmlContext.resetImports();
  97. project.addReference( "ant.parsing.context", context );
  98. parse(project, source,new RootHandler(context));
  99. }
  100. /**
  101. * Parses the project file, configuring the project as it goes.
  102. *
  103. * @exception BuildException if the configuration is invalid or cannot
  104. * be read
  105. */
  106. public void parse(Project project, Object source, RootHandler handler) throws BuildException {
  107. AntXmlContext context=handler.context;
  108. if(source instanceof File) {
  109. context.buildFile=(File)source;
  110. // } else if( source instanceof InputStream ) {
  111. // } else if( source instanceof URL ) {
  112. // } else if( source instanceof InputSource ) {
  113. } else {
  114. throw new BuildException( "Source " + source.getClass().getName() +
  115. " not supported by this plugin" );
  116. }
  117. FileInputStream inputStream = null;
  118. InputSource inputSource = null;
  119. context.project = project;
  120. context.buildFile = new File(context.buildFile.getAbsolutePath());
  121. context.buildFileParent = new File(context.buildFile.getParent());
  122. try {
  123. /**
  124. * SAX 2 style parser used to parse the given file.
  125. */
  126. context.parser =JAXPUtils.getXMLReader();
  127. String uri = "file:" + context.buildFile.getAbsolutePath().replace('\\', '/');
  128. for (int index = uri.indexOf('#'); index != -1; index = uri.indexOf('#')) {
  129. uri = uri.substring(0, index) + "%23" + uri.substring(index+1);
  130. }
  131. inputStream = new FileInputStream(context.buildFile);
  132. inputSource = new InputSource(inputStream);
  133. inputSource.setSystemId(uri);
  134. project.log("parsing buildfile " + context.buildFile + " with URI = " + uri, Project.MSG_VERBOSE);
  135. DefaultHandler hb = handler;
  136. context.parser.setContentHandler(hb);
  137. context.parser.setEntityResolver(hb);
  138. context.parser.setErrorHandler(hb);
  139. context.parser.setDTDHandler(hb);
  140. context.parser.parse(inputSource);
  141. } catch(SAXParseException exc) {
  142. Location location =
  143. new Location(exc.getSystemId(), exc.getLineNumber(), exc.getColumnNumber());
  144. Throwable t = exc.getException();
  145. if (t instanceof BuildException) {
  146. BuildException be = (BuildException) t;
  147. if (be.getLocation() == Location.UNKNOWN_LOCATION) {
  148. be.setLocation(location);
  149. }
  150. throw be;
  151. }
  152. throw new BuildException(exc.getMessage(), t, location);
  153. }
  154. catch(SAXException exc) {
  155. Throwable t = exc.getException();
  156. if (t instanceof BuildException) {
  157. throw (BuildException) t;
  158. }
  159. throw new BuildException(exc.getMessage(), t);
  160. }
  161. catch(FileNotFoundException exc) {
  162. throw new BuildException(exc);
  163. }
  164. catch(UnsupportedEncodingException exc) {
  165. throw new BuildException("Encoding of project file is invalid.",exc);
  166. }
  167. catch(IOException exc) {
  168. throw new BuildException("Error reading project file: " +exc.getMessage(), exc);
  169. }
  170. finally {
  171. if (inputStream != null) {
  172. try {
  173. inputStream.close();
  174. }
  175. catch (IOException ioe) {
  176. // ignore this
  177. }
  178. }
  179. }
  180. }
  181. /**
  182. * The common superclass for all SAX event handlers used to parse
  183. * the configuration file. Each method just throws an exception,
  184. * so subclasses should override what they can handle.
  185. *
  186. * Each type of XML element (task, target, etc.) in Ant has
  187. * a specific subclass.
  188. *
  189. * In the constructor, this class takes over the handling of SAX
  190. * events from the parent handler and returns
  191. * control back to the parent in the endElement method.
  192. */
  193. public static class AntHandler {
  194. /**
  195. * Handles the start of an element. This base implementation just
  196. * throws an exception.
  197. *
  198. * @param tag The name of the element being started.
  199. * Will not be <code>null</code>.
  200. * @param attrs Attributes of the element being started.
  201. * Will not be <code>null</code>.
  202. *
  203. * @exception SAXParseException if this method is not overridden, or in
  204. * case of error in an overridden version
  205. */
  206. public void onStartElement(String uri, String tag, String qname,
  207. Attributes attrs,
  208. AntXmlContext context)
  209. throws SAXParseException
  210. {
  211. throw new SAXParseException("Unexpected element \" " + qname + "\"", context.locator);
  212. }
  213. /**
  214. * Handles the start of an element. This base implementation just
  215. * throws an exception.
  216. *
  217. * @param tag The name of the element being started.
  218. * Will not be <code>null</code>.
  219. * @param attrs Attributes of the element being started.
  220. * Will not be <code>null</code>.
  221. *
  222. * @exception SAXParseException if this method is not overridden, or in
  223. * case of error in an overridden version
  224. */
  225. public AntHandler onStartChild(String uri, String tag, String qname,
  226. Attributes attrs,
  227. AntXmlContext context)
  228. throws SAXParseException
  229. {
  230. throw new SAXParseException("Unexpected element \"" + qname + " \"", context.locator);
  231. }
  232. /**
  233. * Called when this element and all elements nested into it have been
  234. * handled.
  235. */
  236. public void onEndElement(String uri, String tag, AntXmlContext context) {
  237. }
  238. /**
  239. * Handles text within an element. This base implementation just
  240. * throws an exception.
  241. *
  242. * @param buf A character array of the text within the element.
  243. * Will not be <code>null</code>.
  244. * @param start The start element in the array.
  245. * @param count The number of characters to read from the array.
  246. *
  247. * @exception SAXParseException if this method is not overridden, or in
  248. * case of error in an overridden version
  249. */
  250. public void characters(char[] buf, int start, int count, AntXmlContext context)
  251. throws SAXParseException
  252. {
  253. String s = new String(buf, start, count).trim();
  254. if (s.length() > 0) {
  255. throw new SAXParseException("Unexpected text \"" + s + "\"", context.locator);
  256. }
  257. }
  258. }
  259. /** Context information for ant deserialization
  260. */
  261. public static class AntXmlContext {
  262. /** The project to configure. */
  263. Project project;
  264. /** The configuration file to parse. */
  265. public File buildFile;
  266. /**
  267. * Parent directory of the build file. Used for resolving entities
  268. * and setting the project's base directory.
  269. */
  270. public File buildFileParent;
  271. /**
  272. * Locator for the configuration file parser.
  273. * Used for giving locations of errors etc.
  274. */
  275. Locator locator;
  276. public ProjectHelperImpl2 helper;
  277. org.xml.sax.XMLReader parser;
  278. /**
  279. * Target that all other targets will depend upon implicitly.
  280. *
  281. * <p>This holds all tasks and data type definitions that have
  282. * been placed outside of targets.</p>
  283. */
  284. Target implicitTarget = new Target();
  285. public boolean ignoreProjectTag=false;
  286. public static Hashtable importedFiles = new Hashtable();
  287. public static int importlevel = 0;
  288. public static void resetImports() {
  289. importedFiles.clear();
  290. }
  291. public AntXmlContext(ProjectHelperImpl2 helper) {
  292. implicitTarget.setName("");
  293. this.helper=helper;
  294. }
  295. /**
  296. * Scans an attribute list for the <code>id</code> attribute and
  297. * stores a reference to the target object in the project if an
  298. * id is found.
  299. * <p>
  300. * This method was moved out of the configure method to allow
  301. * it to be executed at parse time.
  302. *
  303. * @see #configure(Object,AttributeList,Project)
  304. */
  305. void configureId(Object target, Attributes attr) {
  306. String id = attr.getValue("id");
  307. if (id != null) {
  308. project.addReference(id, target);
  309. }
  310. }
  311. }
  312. /**
  313. * Handler for ant processing. Uses a stack of AntHandlers to
  314. * implement each element ( the original parser used a recursive behavior,
  315. * with the implicit execution stack )
  316. */
  317. public static class RootHandler extends DefaultHandler {
  318. Stack antHandlers=new Stack();
  319. AntHandler currentHandler;
  320. AntXmlContext context;
  321. public RootHandler(AntXmlContext context) {
  322. currentHandler=new MainHandler();
  323. antHandlers.push( currentHandler );
  324. this.context=context;
  325. }
  326. /**
  327. * Resolves file: URIs relative to the build file.
  328. *
  329. * @param publicId The public identifer, or <code>null</code>
  330. * if none is available. Ignored in this
  331. * implementation.
  332. * @param systemId The system identifier provided in the XML
  333. * document. Will not be <code>null</code>.
  334. */
  335. public InputSource resolveEntity(String publicId,
  336. String systemId) {
  337. context.project.log("resolving systemId: " + systemId, Project.MSG_VERBOSE);
  338. if (systemId.startsWith("file:")) {
  339. String path = systemId.substring(5);
  340. int index = path.indexOf("file:");
  341. // we only have to handle these for backward compatibility
  342. // since they are in the FAQ.
  343. while (index != -1) {
  344. path = path.substring(0, index) + path.substring(index + 5);
  345. index = path.indexOf("file:");
  346. }
  347. String entitySystemId = path;
  348. index = path.indexOf("%23");
  349. // convert these to #
  350. while (index != -1) {
  351. path = path.substring(0, index) + "#" + path.substring(index + 3);
  352. index = path.indexOf("%23");
  353. }
  354. File file = new File(path);
  355. if (!file.isAbsolute()) {
  356. file = new File(context.buildFileParent, path);
  357. }
  358. try {
  359. InputSource inputSource = new InputSource(new FileInputStream(file));
  360. inputSource.setSystemId("file:" + entitySystemId);
  361. return inputSource;
  362. } catch (FileNotFoundException fne) {
  363. context.project.log(file.getAbsolutePath()+" could not be found",
  364. Project.MSG_WARN);
  365. }
  366. }
  367. // use default if not file or file not found
  368. return null;
  369. }
  370. /**
  371. * Handles the start of a project element. A project handler is created
  372. * and initialised with the element name and attributes.
  373. *
  374. * @param tag The name of the element being started.
  375. * Will not be <code>null</code>.
  376. * @param attrs Attributes of the element being started.
  377. * Will not be <code>null</code>.
  378. *
  379. * @exception SAXParseException if the tag given is not
  380. * <code>"project"</code>
  381. */
  382. public void startElement(String uri, String tag, String qname, Attributes attrs)
  383. throws SAXParseException
  384. {
  385. AntHandler next=currentHandler.onStartChild(uri, tag, qname, attrs, context);
  386. antHandlers.push( currentHandler );
  387. //System.out.println("XXX push " + currentHandler );
  388. currentHandler=next;
  389. currentHandler.onStartElement( uri, tag, qname, attrs, context );
  390. }
  391. /**
  392. * Sets the locator in the project helper for future reference.
  393. *
  394. * @param locator The locator used by the parser.
  395. * Will not be <code>null</code>.
  396. */
  397. public void setDocumentLocator(Locator locator) {
  398. context.locator = locator;
  399. }
  400. /**
  401. * Handles the end of an element. Any required clean-up is performed
  402. * by the onEndElement() method and then the original handler is restored to
  403. * the parser.
  404. *
  405. * @param name The name of the element which is ending.
  406. * Will not be <code>null</code>.
  407. *
  408. * @exception SAXException in case of error (not thrown in
  409. * this implementation)
  410. *
  411. */
  412. public void endElement(String uri, String name, String qName) throws SAXException {
  413. currentHandler.onEndElement(uri, name, context);
  414. AntHandler prev=(AntHandler)antHandlers.pop();
  415. //System.out.println("XXX pop " + currentHandler + " " + prev);
  416. currentHandler=prev;
  417. }
  418. public void characters(char[] buf, int start, int count)
  419. throws SAXParseException
  420. {
  421. currentHandler.characters( buf, start, count, context );
  422. }
  423. }
  424. public static class MainHandler extends AntHandler {
  425. public void onStartElement(String uri, String tag, String qname,
  426. Attributes attrs,
  427. AntXmlContext context)
  428. throws SAXParseException
  429. {
  430. }
  431. public AntHandler onStartChild(String uri, String name, String qname,
  432. Attributes attrs,
  433. AntXmlContext context)
  434. throws SAXParseException
  435. {
  436. if (qname.equals("project")) {
  437. return new ProjectHandler();
  438. } else {
  439. throw new SAXParseException("Unexpected element \"" + qname + "\" " + name, context.locator);
  440. }
  441. }
  442. }
  443. /**
  444. * Handler for the top level "project" element.
  445. */
  446. public static class ProjectHandler extends AntHandler {
  447. /**
  448. * Initialisation routine called after handler creation
  449. * with the element name and attributes. The attributes which
  450. * this handler can deal with are: <code>"default"</code>,
  451. * <code>"name"</code>, <code>"id"</code> and <code>"basedir"</code>.
  452. *
  453. * @param tag Name of the element which caused this handler
  454. * to be created. Should not be <code>null</code>.
  455. * Ignored in this implementation.
  456. * @param attrs Attributes of the element which caused this
  457. * handler to be created. Must not be <code>null</code>.
  458. *
  459. * @exception SAXParseException if an unexpected attribute is
  460. * encountered or if the <code>"default"</code> attribute
  461. * is missing.
  462. */
  463. public void onStartElement(String uri, String tag, String qname,
  464. Attributes attrs,
  465. AntXmlContext context)
  466. throws SAXParseException
  467. {
  468. String def = null;
  469. String name = null;
  470. String id = null;
  471. String baseDir = null;
  472. if (! qname.equals("project")) {
  473. throw new SAXParseException("Config file is not of expected XML type", context.locator);
  474. }
  475. if( context.ignoreProjectTag ) {
  476. return;
  477. }
  478. for (int i = 0; i < attrs.getLength(); i++) {
  479. String key = attrs.getQName(i);
  480. String value = attrs.getValue(i);
  481. if (key.equals("default")) {
  482. def = value;
  483. } else if (key.equals("name")) {
  484. name = value;
  485. } else if (key.equals("id")) {
  486. id = value;
  487. } else if (key.equals("basedir")) {
  488. baseDir = value;
  489. } else {
  490. throw new SAXParseException("Unexpected attribute \"" + attrs.getQName(i) + "\"", context.locator);
  491. }
  492. }
  493. Project project=context.project;
  494. if (def != null && !def.equals("")) {
  495. project.setDefaultTarget(def);
  496. }
  497. if (name != null) {
  498. project.setName(name);
  499. project.addReference(name, project);
  500. }
  501. if (id != null) {
  502. project.addReference(id, project);
  503. }
  504. if (project.getProperty("basedir") != null) {
  505. project.setBasedir(project.getProperty("basedir"));
  506. } else {
  507. if (baseDir == null) {
  508. project.setBasedir(context.buildFileParent.getAbsolutePath());
  509. } else {
  510. // check whether the user has specified an absolute path
  511. if ((new File(baseDir)).isAbsolute()) {
  512. project.setBasedir(baseDir);
  513. } else {
  514. project.setBaseDir(project.resolveFile(baseDir,
  515. context.buildFileParent));
  516. }
  517. }
  518. }
  519. project.addTarget("", context.implicitTarget);
  520. }
  521. /**
  522. * Handles the start of a top-level element within the project. An
  523. * appropriate handler is created and initialised with the details
  524. * of the element.
  525. *
  526. * @param tag The name of the element being started.
  527. * Will not be <code>null</code>.
  528. * @param attrs Attributes of the element being started.
  529. * Will not be <code>null</code>.
  530. *
  531. * @exception SAXParseException if the tag given is not
  532. * <code>"taskdef"</code>, <code>"typedef"</code>,
  533. * <code>"property"</code>, <code>"target"</code>
  534. * or a data type definition
  535. */
  536. public AntHandler onStartChild(String uri, String name, String qname,
  537. Attributes attrs,
  538. AntXmlContext context)
  539. throws SAXParseException
  540. {
  541. // if (qname.equals("import")) {
  542. // return new ImportHandler();
  543. // } else
  544. if (qname.equals("target")) {
  545. return new TargetHandler();
  546. } else if (context.project.getDataTypeDefinitions().get(qname) != null) {
  547. return new DataTypeHandler(context.implicitTarget);
  548. } else if (context.project.getTaskDefinitions().get(qname) != null) {
  549. return new TaskHandler(context.implicitTarget,null,context.implicitTarget);
  550. } else {
  551. throw new SAXParseException("Unexpected element \"" + qname + "\" " + name, context.locator);
  552. }
  553. }
  554. }
  555. /**
  556. * Handler for "target" elements.
  557. */
  558. public static class TargetHandler extends AntHandler {
  559. private Target target;
  560. /**
  561. * Initialisation routine called after handler creation
  562. * with the element name and attributes. The attributes which
  563. * this handler can deal with are: <code>"name"</code>,
  564. * <code>"depends"</code>, <code>"if"</code>,
  565. * <code>"unless"</code>, <code>"id"</code> and
  566. * <code>"description"</code>.
  567. *
  568. * @param tag Name of the element which caused this handler
  569. * to be created. Should not be <code>null</code>.
  570. * Ignored in this implementation.
  571. * @param attrs Attributes of the element which caused this
  572. * handler to be created. Must not be <code>null</code>.
  573. *
  574. * @exception SAXParseException if an unexpected attribute is encountered
  575. * or if the <code>"name"</code> attribute is missing.
  576. */
  577. public void onStartElement(String uri, String tag, String qname,
  578. Attributes attrs,
  579. AntXmlContext context)
  580. throws SAXParseException
  581. {
  582. String name = null;
  583. String depends = "";
  584. String ifCond = null;
  585. String unlessCond = null;
  586. String id = null;
  587. String description = null;
  588. for (int i = 0; i < attrs.getLength(); i++) {
  589. String key = attrs.getQName(i);
  590. String value = attrs.getValue(i);
  591. if (key.equals("name")) {
  592. name = value;
  593. if( "".equals( name ) )
  594. throw new BuildException("name attribute must not be empty");
  595. } else if (key.equals("depends")) {
  596. depends = value;
  597. } else if (key.equals("if")) {
  598. ifCond = value;
  599. } else if (key.equals("unless")) {
  600. unlessCond = value;
  601. } else if (key.equals("id")) {
  602. id = value;
  603. } else if (key.equals("description")) {
  604. description = value;
  605. } else {
  606. throw new SAXParseException("Unexpected attribute \"" + key + "\"", context.locator);
  607. }
  608. }
  609. if (name == null) {
  610. throw new SAXParseException("target element appears without a name attribute",
  611. context.locator);
  612. }
  613. Project project=context.project;
  614. target = new Target();
  615. target.addDependency( "" );
  616. target.setName(name);
  617. target.setIf(ifCond);
  618. target.setUnless(unlessCond);
  619. target.setDescription(description);
  620. // START IMPORT CHANGE XXX Move to Import task
  621. int timesRedefined = 0;
  622. Hashtable currentTargets = project.getTargets();
  623. project.log("Defined targets: "+currentTargets ,Project.MSG_VERBOSE);
  624. //currently tracks only one level of super.
  625. if(currentTargets.containsKey(name)){
  626. timesRedefined++;
  627. }
  628. if(timesRedefined>0){
  629. project.log("Redefining target named: \""+name+"\"" ,Project.MSG_VERBOSE);
  630. //Adding old target as a new target with super.super[timesRedefined].super.name
  631. Target oldTarget = (Target) currentTargets.get(name);
  632. project.log("Current oldTarget named "+name+" is "+oldTarget.toString() ,Project.MSG_VERBOSE);
  633. String superTargetName = "";
  634. for(int i=0; i < timesRedefined; i++){
  635. superTargetName += "super.";
  636. }
  637. superTargetName = superTargetName + name;
  638. oldTarget.setName(superTargetName);
  639. project.addTarget(superTargetName, oldTarget);
  640. }
  641. // if the target is redefined, it redefines it, otherwise just adds it
  642. project.addOrReplaceTarget(name, target);
  643. project.log("targets are now: "+currentTargets.toString() ,Project.MSG_VERBOSE);
  644. // END IMPORT CHANGE
  645. // context.project.addTarget(name, target);
  646. if (id != null && !id.equals("")) {
  647. context.project.addReference(id, target);
  648. }
  649. // take care of dependencies
  650. if (depends.length() > 0) {
  651. target.setDepends(depends);
  652. }
  653. }
  654. /**
  655. * Handles the start of an element within a target.
  656. *
  657. * @param tag The name of the element being started.
  658. * Will not be <code>null</code>.
  659. * @param attrs Attributes of the element being started.
  660. * Will not be <code>null</code>.
  661. *
  662. * @exception SAXParseException if an error occurs when initialising
  663. * the appropriate child handler
  664. */
  665. public AntHandler onStartChild(String uri, String name, String qname,
  666. Attributes attrs,
  667. AntXmlContext context)
  668. throws SAXParseException
  669. {
  670. if (context.project.getDataTypeDefinitions().get(qname) != null) {
  671. return new DataTypeHandler(target);
  672. } else {
  673. return new TaskHandler(target, null, target);
  674. }
  675. }
  676. }
  677. /**
  678. * Handler for all task elements.
  679. */
  680. public static class TaskHandler extends AntHandler {
  681. /** Containing target, if any. */
  682. private Target target;
  683. /**
  684. * Container for the task, if any. If target is
  685. * non-<code>null</code>, this must be too.
  686. */
  687. private TaskContainer container;
  688. /**
  689. * Task created by this handler.
  690. */
  691. private Task task;
  692. /**
  693. * Wrapper for the parent element, if any. The wrapper for this
  694. * element will be added to this wrapper as a child.
  695. */
  696. private RuntimeConfigurable2 parentWrapper;
  697. /**
  698. * Wrapper for this element which takes care of actually configuring
  699. * the element, if this element is contained within a target.
  700. * Otherwise the configuration is performed with the configure method.
  701. * @see ProjectHelper#configure(Object,Attributes,Project)
  702. */
  703. private RuntimeConfigurable2 wrapper = null;
  704. /**
  705. * Constructor.
  706. *
  707. * @param parentHandler The handler which should be restored to the
  708. * parser at the end of the element.
  709. * Must not be <code>null</code>.
  710. *
  711. * @param container Container for the element.
  712. * Must not be <code>null</code>
  713. *
  714. * @param parentWrapper Wrapper for the parent element, if any.
  715. * May be <code>null</code>.
  716. *
  717. * @param target Target this element is part of.
  718. * Must not be <code>null</code>.
  719. */
  720. public TaskHandler(TaskContainer container, RuntimeConfigurable2 parentWrapper, Target target) {
  721. this.container = container;
  722. this.parentWrapper = parentWrapper;
  723. this.target = target;
  724. }
  725. /**
  726. * Initialisation routine called after handler creation
  727. * with the element name and attributes. This configures
  728. * the element with its attributes and sets it up with
  729. * its parent container (if any). Nested elements are then
  730. * added later as the parser encounters them.
  731. *
  732. * @param tag Name of the element which caused this handler
  733. * to be created. Must not be <code>null</code>.
  734. *
  735. * @param attrs Attributes of the element which caused this
  736. * handler to be created. Must not be <code>null</code>.
  737. *
  738. * @exception SAXParseException in case of error (not thrown in
  739. * this implementation)
  740. */
  741. public void onStartElement(String uri, String tag, String qname,
  742. Attributes attrs,
  743. AntXmlContext context)
  744. throws SAXParseException
  745. {
  746. try {
  747. task = context.project.createTask(qname);
  748. } catch (BuildException e) {
  749. // swallow here, will be thrown again in
  750. // UnknownElement.maybeConfigure if the problem persists.
  751. }
  752. if (task == null) {
  753. task = new UnknownElement(qname);
  754. task.setProject(context.project);
  755. //XXX task.setTaskType(qname);
  756. task.setTaskName(qname);
  757. }
  758. task.setLocation(new Location(context.locator.getSystemId(),
  759. context.locator.getLineNumber(),
  760. context.locator.getColumnNumber()));
  761. context.configureId(task, attrs);
  762. task.setOwningTarget(target);
  763. container.addTask(task);
  764. task.init();
  765. //wrapper = task.getRuntimeConfigurableWrapper();
  766. wrapper=new RuntimeConfigurable2(task, task.getTaskName());
  767. wrapper.setAttributes2(attrs);
  768. if (parentWrapper != null) {
  769. parentWrapper.addChild(wrapper);
  770. }
  771. }
  772. /**
  773. * Adds text to the task, using the wrapper
  774. *
  775. * @param buf A character array of the text within the element.
  776. * Will not be <code>null</code>.
  777. * @param start The start element in the array.
  778. * @param count The number of characters to read from the array.
  779. *
  780. * @exception SAXParseException if the element doesn't support text
  781. *
  782. * @see ProjectHelper#addText(Project,Object,char[],int,int)
  783. */
  784. public void characters(char[] buf, int start, int count,
  785. AntXmlContext context)
  786. throws SAXParseException
  787. {
  788. wrapper.addText(buf, start, count);
  789. }
  790. /**
  791. * Handles the start of an element within a target. Task containers
  792. * will always use another task handler, and all other tasks
  793. * will always use a nested element handler.
  794. *
  795. * @param tag The name of the element being started.
  796. * Will not be <code>null</code>.
  797. * @param attrs Attributes of the element being started.
  798. * Will not be <code>null</code>.
  799. *
  800. * @exception SAXParseException if an error occurs when initialising
  801. * the appropriate child handler
  802. */
  803. public AntHandler onStartChild(String uri, String tag, String qname,
  804. Attributes attrs,
  805. AntXmlContext context)
  806. throws SAXParseException
  807. {
  808. if (task instanceof TaskContainer) {
  809. // task can contain other tasks - no other nested elements possible
  810. return new TaskHandler((TaskContainer)task, wrapper, target);
  811. }
  812. else {
  813. return new NestedElementHandler(task, wrapper, target);
  814. }
  815. }
  816. }
  817. /**
  818. * Handler for all nested properties.
  819. */
  820. public static class NestedElementHandler extends AntHandler {
  821. /** Parent object (task/data type/etc). */
  822. private Object parent;
  823. /** The nested element itself. */
  824. private Object child;
  825. /**
  826. * Wrapper for the parent element, if any. The wrapper for this
  827. * element will be added to this wrapper as a child.
  828. */
  829. private RuntimeConfigurable2 parentWrapper;
  830. /**
  831. * Wrapper for this element which takes care of actually configuring
  832. * the element, if a parent wrapper is provided.
  833. * Otherwise the configuration is performed with the configure method.
  834. * @see ProjectHelper#configure(Object,Attributes,Project)
  835. */
  836. private RuntimeConfigurable2 childWrapper = null;
  837. /** Target this element is part of, if any. */
  838. private Target target;
  839. /**
  840. * Constructor.
  841. *
  842. * @param parentHandler The handler which should be restored to the
  843. * parser at the end of the element.
  844. * Must not be <code>null</code>.
  845. *
  846. * @param parent Parent of this element (task/data type/etc).
  847. * Must not be <code>null</code>.
  848. *
  849. * @param parentWrapper Wrapper for the parent element, if any.
  850. * Must not be <code>null</code>.
  851. *
  852. * @param target Target this element is part of.
  853. * Must not be <code>null</code>.
  854. */
  855. public NestedElementHandler(Object parent,
  856. RuntimeConfigurable2 parentWrapper,
  857. Target target) {
  858. if (parent instanceof TaskAdapter) {
  859. this.parent = ((TaskAdapter) parent).getProxy();
  860. } else {
  861. this.parent = parent;
  862. }
  863. this.parentWrapper = parentWrapper;
  864. this.target = target;
  865. }
  866. /**
  867. * Initialisation routine called after handler creation
  868. * with the element name and attributes. This configures
  869. * the element with its attributes and sets it up with
  870. * its parent container (if any). Nested elements are then
  871. * added later as the parser encounters them.
  872. *
  873. * @param tag Name of the element which caused this handler
  874. * to be created. Must not be <code>null</code>.
  875. *
  876. * @param attrs Attributes of the element which caused this
  877. * handler to be created. Must not be <code>null</code>.
  878. *
  879. * @exception SAXParseException in case of error, such as a
  880. * BuildException being thrown during configuration.
  881. */
  882. public void onStartElement(String uri, String propType, String qname,
  883. Attributes attrs,
  884. AntXmlContext context)
  885. throws SAXParseException
  886. {
  887. Class parentClass = parent.getClass();
  888. IntrospectionHelper ih =
  889. IntrospectionHelper.getHelper(parentClass);
  890. try {
  891. String elementName = qname.toLowerCase(Locale.US);
  892. if (parent instanceof UnknownElement) {
  893. UnknownElement uc = new UnknownElement(elementName);
  894. uc.setProject(context.project);
  895. ((UnknownElement) parent).addChild(uc);
  896. child = uc;
  897. } else {
  898. child = ih.createElement(context.project, parent, elementName);
  899. }
  900. context.configureId(child, attrs);
  901. childWrapper = new RuntimeConfigurable2(child, qname);
  902. childWrapper.setAttributes2(attrs);
  903. parentWrapper.addChild(childWrapper);
  904. } catch (BuildException exc) {
  905. throw new SAXParseException(exc.getMessage(), context.locator, exc);
  906. }
  907. }
  908. /**
  909. * Adds text to the element, using the wrapper if one is
  910. * available or using addText otherwise.
  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. *
  917. * @exception SAXParseException if the element doesn't support text
  918. *
  919. * @see ProjectHelper#addText(Project,Object,char[],int,int)
  920. */
  921. public void characters(char[] buf, int start, int count,
  922. AntXmlContext context)
  923. throws SAXParseException
  924. {
  925. childWrapper.addText(buf, start, count);
  926. }
  927. /**
  928. * Handles the start of an element within this one. Task containers
  929. * will always use a task handler, and all other elements
  930. * will always use another nested element handler.
  931. *
  932. * @param tag The name of the element being started.
  933. * Will not be <code>null</code>.
  934. * @param attrs Attributes of the element being started.
  935. * Will not be <code>null</code>.
  936. *
  937. * @exception SAXParseException if an error occurs when initialising
  938. * the appropriate child handler
  939. */
  940. public AntHandler onStartChild(String uri, String tag, String qname,
  941. Attributes attrs,
  942. AntXmlContext context)
  943. throws SAXParseException
  944. {
  945. if (child instanceof TaskContainer) {
  946. // taskcontainer nested element can contain other tasks - no other
  947. // nested elements possible
  948. return new TaskHandler((TaskContainer)child, childWrapper, target);
  949. }
  950. else {
  951. return new NestedElementHandler(child, childWrapper, target);
  952. }
  953. }
  954. }
  955. /**
  956. * Handler for all data types directly subordinate to project or target.
  957. */
  958. public static class DataTypeHandler extends AntHandler {
  959. /** Parent target, if any. */
  960. private Target target;
  961. /** The element being configured. */
  962. private Object element;
  963. /** Wrapper for this element, if it's part of a target. */
  964. private RuntimeConfigurable2 wrapper = null;
  965. /**
  966. * Constructor with a target specified.
  967. *
  968. * @param target The parent target of this element.
  969. * May be <code>null</code>.
  970. */
  971. public DataTypeHandler( Target target) {
  972. this.target = target;
  973. }
  974. /**
  975. * Initialisation routine called after handler creation
  976. * with the element name and attributes. This configures
  977. * the element with its attributes and sets it up with
  978. * its parent container (if any). Nested elements are then
  979. * added later as the parser encounters them.
  980. *
  981. * @param tag Name of the element which caused this handler
  982. * to be created. Must not be <code>null</code>.
  983. *
  984. * @param attrs Attributes of the element which caused this
  985. * handler to be created. Must not be <code>null</code>.
  986. *
  987. * @exception SAXParseException in case of error, such as a
  988. * BuildException being thrown during configuration.
  989. */
  990. public void onStartElement(String uri, String propType, String qname,
  991. Attributes attrs,
  992. AntXmlContext context)
  993. throws SAXParseException
  994. {
  995. try {
  996. element = context.project.createDataType(qname);
  997. if (element == null) {
  998. throw new BuildException("Unknown data type "+qname);
  999. }
  1000. wrapper = new RuntimeConfigurable2(element, qname);
  1001. wrapper.setAttributes2(attrs);
  1002. target.addDataType(wrapper);
  1003. } catch (BuildException exc) {
  1004. throw new SAXParseException(exc.getMessage(), context.locator, exc);
  1005. }
  1006. }
  1007. // XXX: (Jon Skeet) Any reason why this doesn't use the wrapper
  1008. // if one is available, whereas NestedElementHandler.characters does?
  1009. /**
  1010. * Adds text to the element.
  1011. *
  1012. * @param buf A character array of the text within the element.
  1013. * Will not be <code>null</code>.
  1014. * @param start The start element in the array.
  1015. * @param count The number of characters to read from the array.
  1016. *
  1017. * @exception SAXParseException if the element doesn't support text
  1018. *
  1019. * @see ProjectHelper#addText(Project,Object,char[],int,int)
  1020. */
  1021. public void characters(char[] buf, int start, int count,
  1022. AntXmlContext context)
  1023. throws SAXParseException
  1024. {
  1025. try {
  1026. ProjectHelper.addText(context.project, element, buf, start, count);
  1027. } catch (BuildException exc) {
  1028. throw new SAXParseException(exc.getMessage(), context.locator, exc);
  1029. }
  1030. }
  1031. /**
  1032. * Handles the start of an element within this one.
  1033. * This will always use a nested element handler.
  1034. *
  1035. * @param tag The name of the element being started.
  1036. * Will not be <code>null</code>.
  1037. * @param attrs Attributes of the element being started.
  1038. * Will not be <code>null</code>.
  1039. *
  1040. * @exception SAXParseException if an error occurs when initialising
  1041. * the child handler
  1042. */
  1043. public AntHandler onStartChild(String uri, String tag, String qname,
  1044. Attributes attrs, AntXmlContext context)
  1045. throws SAXParseException
  1046. {
  1047. return new NestedElementHandler(element, wrapper, target);
  1048. }
  1049. }
  1050. // /**
  1051. // * Handler for the root element. Its only child must be the "project" element.
  1052. // */
  1053. // static class ImportHandler extends AntHandler {
  1054. // /**
  1055. // * Initialisation routine called after handler creation
  1056. // * with the element name and attributes. The attributes which
  1057. // * this handler can deal with are: <code>"default"</code>,
  1058. // * <code>"name"</code>, <code>"id"</code> and <code>"basedir"</code>.
  1059. // *
  1060. // * @param tag Name of the element which caused this handler
  1061. // * to be created. Should not be <code>null</code>.
  1062. // * Ignored in this implementation.
  1063. // * @param attrs Attributes of the element which caused this
  1064. // * handler to be created. Must not be <code>null</code>.
  1065. // *
  1066. // * @exception SAXParseException if an unexpected attribute is
  1067. // * encountered or if the <code>"default"</code> attribute
  1068. // * is missing.
  1069. // */
  1070. // public void onStartElement(String uri, String tag, String qname,
  1071. // Attributes attrs,
  1072. // AntXmlContext context)
  1073. // throws SAXParseException
  1074. // {
  1075. // context._importlevel++;
  1076. // Project project=context.project;
  1077. // project.log("importlevel: "+(context._importlevel-1)+" -> "+(context._importlevel),
  1078. // Project.MSG_DEBUG);
  1079. // String file = null;
  1080. // for (int i = 0; i < attrs.getLength(); i++) {
  1081. // String key = attrs.getQName(i);
  1082. // String value = attrs.getValue(i);
  1083. // if (key.equals("file")) {
  1084. // file = value;
  1085. // } else {
  1086. // throw new SAXParseException("Unexpected attribute \"" + key + "\"", context.locator);
  1087. // }
  1088. // }
  1089. // if (file == null) {
  1090. // throw new SAXParseException("import element appears without a file attribute",
  1091. // context.locator);
  1092. // }
  1093. // file=project.replaceProperties(file);
  1094. // project.log("Importing file "+file+" from "+
  1095. // context.buildFile.getAbsolutePath(),
  1096. // Project.MSG_VERBOSE);
  1097. // // Paths are relative to the build file they're imported from,
  1098. // // *not* the current directory (same as entity includes).
  1099. // File importedFile = new File(file);
  1100. // if (!importedFile.isAbsolute()) {
  1101. // importedFile = new File(context.buildFileParent, file);
  1102. // }
  1103. // if (!importedFile.exists()) {
  1104. // throw new SAXParseException("Cannot find "+file+" imported from "+
  1105. // context.buildFile.getAbsolutePath(),
  1106. // context.locator);
  1107. // }
  1108. // // Add parent build file to the map to avoid cycles...
  1109. // String parentFilename = getPath(context.buildFile);
  1110. // if (!context._importedFiles.containsKey(parentFilename)) {
  1111. // context._importedFiles.put(parentFilename, context.buildFile);
  1112. // }
  1113. // // Make sure we import the file only once
  1114. // String importedFilename = getPath(importedFile);
  1115. // if (context._importedFiles.containsKey(importedFilename)) {
  1116. // project.log("\nSkipped already imported file:\n "+importedFilename+"\n",
  1117. // Project.MSG_WARN);
  1118. // return;
  1119. // }
  1120. // else {
  1121. // context._importedFiles.put(importedFilename, importedFile);
  1122. // }
  1123. // org.xml.sax.XMLReader oldparser = context.parser;
  1124. // context.ignoreProjectTag=true;
  1125. // context.helper.parse(context.project, importedFile, new RootHandler(context));
  1126. // context.ignoreProjectTag=false;
  1127. // context.parser = oldparser;
  1128. // context._importlevel--;
  1129. // context.project.log("importlevel: "+context._importlevel+" <- "+
  1130. // (context._importlevel+1) ,Project.MSG_DEBUG);
  1131. // }
  1132. // private static String getPath(File file) {
  1133. // try {
  1134. // return file.getCanonicalPath();
  1135. // }
  1136. // catch (IOException e) {
  1137. // return file.getAbsolutePath();
  1138. // }
  1139. // }
  1140. // }
  1141. }