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

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