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

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