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

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