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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981
  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 does nothing.
  197. *
  198. * @param tag The name of the element being started.
  199. * Will not be <code>null</code>.
  200. * @param attrs Attributes of the element being started.
  201. * Will not be <code>null</code>.
  202. *
  203. * @exception SAXParseException if this method is not overridden, or in
  204. * case of error in an overridden version
  205. */
  206. public void onStartElement(String uri, String tag, String qname,
  207. Attributes attrs,
  208. AntXmlContext context)
  209. throws SAXParseException
  210. {
  211. }
  212. /**
  213. * Handles the start of an element. This base implementation just
  214. * throws an exception - you must override this method if you expect
  215. * child elements.
  216. *
  217. * @param tag The name of the element being started.
  218. * Will not be <code>null</code>.
  219. * @param attrs Attributes of the element being started.
  220. * Will not be <code>null</code>.
  221. *
  222. * @exception SAXParseException if this method is not overridden, or in
  223. * case of error in an overridden version
  224. */
  225. public AntHandler onStartChild(String uri, String tag, String qname,
  226. Attributes attrs,
  227. AntXmlContext context)
  228. throws SAXParseException
  229. {
  230. throw new SAXParseException("Unexpected element \"" + qname + " \"", context.locator);
  231. }
  232. /**
  233. * Called when this element and all elements nested into it have been
  234. * handled (i.e. at the </end_tag_of_the_element> ).
  235. */
  236. public void onEndElement(String uri, String tag, AntXmlContext context) {
  237. }
  238. /**
  239. * Handles text within an element. This base implementation just
  240. * throws an exception, you must override it if you expect content.
  241. *
  242. * @param buf A character array of the text within the element.
  243. * Will not be <code>null</code>.
  244. * @param start The start element in the array.
  245. * @param count The number of characters to read from the array.
  246. *
  247. * @exception SAXParseException if this method is not overridden, or in
  248. * case of error in an overridden version
  249. */
  250. public void characters(char[] buf, int start, int count, AntXmlContext context)
  251. throws SAXParseException
  252. {
  253. String s = new String(buf, start, count).trim();
  254. if (s.length() > 0) {
  255. throw new SAXParseException("Unexpected text \"" + s + "\"", context.locator);
  256. }
  257. }
  258. }
  259. /** Context information for ant deserialization
  260. */
  261. public static class AntXmlContext {
  262. /** The project to configure. */
  263. Project project;
  264. /** The configuration file to parse. */
  265. public File buildFile;
  266. /**
  267. * Parent directory of the build file. Used for resolving entities
  268. * and setting the project's base directory.
  269. */
  270. public File buildFileParent;
  271. public String currentProjectName;
  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 Target currentTarget=null;
  287. public boolean ignoreProjectTag=false;
  288. public static Hashtable importedFiles = new Hashtable();
  289. public static int importlevel = 0;
  290. public static void resetImports() {
  291. importedFiles.clear();
  292. }
  293. public AntXmlContext(ProjectHelperImpl2 helper) {
  294. implicitTarget.setName("");
  295. this.helper=helper;
  296. }
  297. /**
  298. * Scans an attribute list for the <code>id</code> attribute and
  299. * stores a reference to the target object in the project if an
  300. * id is found.
  301. * <p>
  302. * This method was moved out of the configure method to allow
  303. * it to be executed at parse time.
  304. *
  305. * @see #configure(Object,AttributeList,Project)
  306. */
  307. void configureId(Object target, Attributes attr) {
  308. String id = attr.getValue("id");
  309. if (id != null) {
  310. project.addReference(id, target);
  311. }
  312. }
  313. }
  314. /**
  315. * Handler for ant processing. Uses a stack of AntHandlers to
  316. * implement each element ( the original parser used a recursive behavior,
  317. * with the implicit execution stack )
  318. */
  319. public static class RootHandler extends DefaultHandler {
  320. Stack antHandlers=new Stack();
  321. AntHandler currentHandler=null;
  322. AntXmlContext context;
  323. public RootHandler(AntXmlContext context) {
  324. currentHandler=new MainHandler();
  325. antHandlers.push( currentHandler );
  326. this.context=context;
  327. }
  328. /**
  329. * Resolves file: URIs relative to the build file.
  330. *
  331. * @param publicId The public identifer, or <code>null</code>
  332. * if none is available. Ignored in this
  333. * implementation.
  334. * @param systemId The system identifier provided in the XML
  335. * document. Will not be <code>null</code>.
  336. */
  337. public InputSource resolveEntity(String publicId,
  338. String systemId) {
  339. context.project.log("resolving systemId: " + systemId, Project.MSG_VERBOSE);
  340. if (systemId.startsWith("file:")) {
  341. String path = systemId.substring(5);
  342. int index = path.indexOf("file:");
  343. // we only have to handle these for backward compatibility
  344. // since they are in the FAQ.
  345. while (index != -1) {
  346. path = path.substring(0, index) + path.substring(index + 5);
  347. index = path.indexOf("file:");
  348. }
  349. String entitySystemId = path;
  350. index = path.indexOf("%23");
  351. // convert these to #
  352. while (index != -1) {
  353. path = path.substring(0, index) + "#" + path.substring(index + 3);
  354. index = path.indexOf("%23");
  355. }
  356. File file = new File(path);
  357. if (!file.isAbsolute()) {
  358. file = new File(context.buildFileParent, path);
  359. }
  360. try {
  361. InputSource inputSource = new InputSource(new FileInputStream(file));
  362. inputSource.setSystemId("file:" + entitySystemId);
  363. return inputSource;
  364. } catch (FileNotFoundException fne) {
  365. context.project.log(file.getAbsolutePath()+" could not be found",
  366. Project.MSG_WARN);
  367. }
  368. }
  369. // use default if not file or file not found
  370. return null;
  371. }
  372. /**
  373. * Handles the start of a project element. A project handler is created
  374. * and initialised with the element name and attributes.
  375. *
  376. * @param tag The name of the element being started.
  377. * Will not be <code>null</code>.
  378. * @param attrs Attributes of the element being started.
  379. * Will not be <code>null</code>.
  380. *
  381. * @exception SAXParseException if the tag given is not
  382. * <code>"project"</code>
  383. */
  384. public void startElement(String uri, String tag, String qname, Attributes attrs)
  385. throws SAXParseException
  386. {
  387. AntHandler next=currentHandler.onStartChild(uri, tag, qname, attrs, context);
  388. antHandlers.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. currentHandler=prev;
  417. }
  418. public void characters(char[] buf, int start, int count)
  419. throws SAXParseException
  420. {
  421. currentHandler.characters( buf, start, count, context );
  422. }
  423. }
  424. public static class MainHandler extends AntHandler {
  425. public AntHandler onStartChild(String uri, String name, String qname,
  426. Attributes attrs,
  427. AntXmlContext context)
  428. throws SAXParseException
  429. {
  430. if (qname.equals("project")) {
  431. return new ProjectHandler();
  432. } else {
  433. throw new SAXParseException("Unexpected element \"" + qname + "\" " + name, context.locator);
  434. }
  435. }
  436. }
  437. /**
  438. * Handler for the top level "project" element.
  439. */
  440. public static class ProjectHandler extends AntHandler {
  441. /**
  442. * Initialisation routine called after handler creation
  443. * with the element name and attributes. The attributes which
  444. * this handler can deal with are: <code>"default"</code>,
  445. * <code>"name"</code>, <code>"id"</code> and <code>"basedir"</code>.
  446. *
  447. * @param tag Name of the element which caused this handler
  448. * to be created. Should not be <code>null</code>.
  449. * Ignored in this implementation.
  450. * @param attrs Attributes of the element which caused this
  451. * handler to be created. Must not be <code>null</code>.
  452. *
  453. * @exception SAXParseException if an unexpected attribute is
  454. * encountered or if the <code>"default"</code> attribute
  455. * is missing.
  456. */
  457. public void onStartElement(String uri, String tag, String qname,
  458. Attributes attrs,
  459. AntXmlContext context)
  460. throws SAXParseException
  461. {
  462. String id = null;
  463. String baseDir = null;
  464. Project project=context.project;
  465. for (int i = 0; i < attrs.getLength(); i++) {
  466. String key = attrs.getQName(i);
  467. String value = attrs.getValue(i);
  468. if (key.equals("default")) {
  469. if ( value != null && !value.equals("")) {
  470. if( !context.ignoreProjectTag )
  471. project.setDefaultTarget(value);
  472. }
  473. } else if (key.equals("name")) {
  474. if (value != null) {
  475. context.currentProjectName=value;
  476. if( !context.ignoreProjectTag ) {
  477. project.setName(value);
  478. project.addReference(value, project);
  479. }
  480. }
  481. } else if (key.equals("id")) {
  482. if (value != null) {
  483. // What's the difference between id and name ?
  484. if( !context.ignoreProjectTag ) {
  485. project.addReference(value, project);
  486. }
  487. }
  488. } else if (key.equals("basedir")) {
  489. if( !context.ignoreProjectTag )
  490. baseDir = value;
  491. } else {
  492. // XXX ignore attributes in a different NS ( maybe store them ? )
  493. throw new SAXParseException("Unexpected attribute \"" + attrs.getQName(i) + "\"", context.locator);
  494. }
  495. }
  496. if( context.ignoreProjectTag ) {
  497. // no further processing
  498. return;
  499. }
  500. // set explicitely before starting ?
  501. if (project.getProperty("basedir") != null) {
  502. project.setBasedir(project.getProperty("basedir"));
  503. } else {
  504. // Default for baseDir is the location of the build file.
  505. if (baseDir == null) {
  506. project.setBasedir(context.buildFileParent.getAbsolutePath());
  507. } else {
  508. // check whether the user has specified an absolute path
  509. if ((new File(baseDir)).isAbsolute()) {
  510. project.setBasedir(baseDir);
  511. } else {
  512. project.setBaseDir(project.resolveFile(baseDir,
  513. context.buildFileParent));
  514. }
  515. }
  516. }
  517. project.addTarget("", context.implicitTarget);
  518. context.currentTarget=context.implicitTarget;
  519. }
  520. /**
  521. * Handles the start of a top-level element within the project. An
  522. * appropriate handler is created and initialised with the details
  523. * of the element.
  524. *
  525. * @param tag The name of the element being started.
  526. * Will not be <code>null</code>.
  527. * @param attrs Attributes of the element being started.
  528. * Will not be <code>null</code>.
  529. *
  530. * @exception SAXParseException if the tag given is not
  531. * <code>"taskdef"</code>, <code>"typedef"</code>,
  532. * <code>"property"</code>, <code>"target"</code>
  533. * or a data type definition
  534. */
  535. public AntHandler onStartChild(String uri, String name, String qname,
  536. Attributes attrs,
  537. AntXmlContext context)
  538. throws SAXParseException
  539. {
  540. if (qname.equals("target")) {
  541. return new TargetHandler();
  542. } else {
  543. return new ElementHandler(context.implicitTarget,null,context.implicitTarget);
  544. }
  545. }
  546. }
  547. /**
  548. * Handler for "target" elements.
  549. */
  550. public static class TargetHandler extends AntHandler {
  551. /**
  552. * Initialisation routine called after handler creation
  553. * with the element name and attributes. The attributes which
  554. * this handler can deal with are: <code>"name"</code>,
  555. * <code>"depends"</code>, <code>"if"</code>,
  556. * <code>"unless"</code>, <code>"id"</code> and
  557. * <code>"description"</code>.
  558. *
  559. * @param tag Name of the element which caused this handler
  560. * to be created. Should not be <code>null</code>.
  561. * Ignored in this implementation.
  562. * @param attrs Attributes of the element which caused this
  563. * handler to be created. Must not be <code>null</code>.
  564. *
  565. * @exception SAXParseException if an unexpected attribute is encountered
  566. * or if the <code>"name"</code> attribute is missing.
  567. */
  568. public void onStartElement(String uri, String tag, String qname,
  569. Attributes attrs,
  570. AntXmlContext context)
  571. throws SAXParseException
  572. {
  573. String name = null;
  574. String depends = "";
  575. Project project=context.project;
  576. Target target = new Target();
  577. context.currentTarget=target;
  578. for (int i = 0; i < attrs.getLength(); i++) {
  579. String key = attrs.getQName(i);
  580. String value = attrs.getValue(i);
  581. if (key.equals("name")) {
  582. name = value;
  583. if( "".equals( name ) )
  584. throw new BuildException("name attribute must not be empty");
  585. } else if (key.equals("depends")) {
  586. depends = value;
  587. } else if (key.equals("if")) {
  588. target.setIf(value);
  589. } else if (key.equals("unless")) {
  590. target.setUnless(value);
  591. } else if (key.equals("id")) {
  592. if (value != null && !value.equals("")) {
  593. context.project.addReference(value, target);
  594. }
  595. } else if (key.equals("description")) {
  596. target.setDescription(value);
  597. } else {
  598. throw new SAXParseException("Unexpected attribute \"" + key + "\"", context.locator);
  599. }
  600. }
  601. if (name == null) {
  602. throw new SAXParseException("target element appears without a name attribute",
  603. context.locator);
  604. }
  605. Hashtable currentTargets = project.getTargets();
  606. // If the name has already beend defined ( import for example )
  607. if(currentTargets.containsKey(name)) {
  608. // Alter the name.
  609. if( context.currentProjectName != null ) {
  610. String newName=context.currentProjectName + "." + name;
  611. project.log("Already defined in main or a previous import, define "
  612. + name + " as " + newName,
  613. Project.MSG_VERBOSE);
  614. name=newName;
  615. } else {
  616. project.log("Already defined in main or a previous import, ignore "
  617. + name,
  618. Project.MSG_VERBOSE);
  619. name=null;
  620. }
  621. }
  622. if( name != null ) {
  623. target.setName(name);
  624. project.addOrReplaceTarget(name, target);
  625. }
  626. project.log("Targets are now: "+ currentTargets ,
  627. Project.MSG_VERBOSE);
  628. // take care of dependencies
  629. if (depends.length() > 0) {
  630. target.setDepends(depends);
  631. }
  632. }
  633. /**
  634. * Handles the start of an element within a target.
  635. *
  636. * @param tag The name of the element being started.
  637. * Will not be <code>null</code>.
  638. * @param attrs Attributes of the element being started.
  639. * Will not be <code>null</code>.
  640. *
  641. * @exception SAXParseException if an error occurs when initialising
  642. * the appropriate child handler
  643. */
  644. public AntHandler onStartChild(String uri, String name, String qname,
  645. Attributes attrs,
  646. AntXmlContext context)
  647. throws SAXParseException
  648. {
  649. return new ElementHandler(context.currentTarget, null, context.currentTarget);
  650. }
  651. public void onEndElement(String uri, String tag, AntXmlContext context) {
  652. context.currentTarget=context.implicitTarget;
  653. }
  654. }
  655. /**
  656. * Handler for all project elements ( tasks, data types )
  657. */
  658. public static class ElementHandler extends AntHandler {
  659. /** Containing target, if any. */
  660. protected Target target;
  661. /**
  662. * Container for the task, if any. If target is
  663. * non-<code>null</code>, this must be too.
  664. */
  665. protected TaskContainer container;
  666. /**
  667. * element created by this handler.
  668. */
  669. protected Object element;
  670. /**
  671. * Wrapper for the parent element, if any. The wrapper for this
  672. * element will be added to this wrapper as a child.
  673. */
  674. protected RuntimeConfigurable2 parentWrapper;
  675. /**
  676. * Wrapper for this element which takes care of actually configuring
  677. * the element, if this element is contained within a target.
  678. * Otherwise the configuration is performed with the configure method.
  679. * @see ProjectHelper#configure(Object,Attributes,Project)
  680. */
  681. protected RuntimeConfigurable2 wrapper = null;
  682. /**
  683. * Constructor.
  684. *
  685. * @param parentHandler The handler which should be restored to the
  686. * parser at the end of the element.
  687. * Must not be <code>null</code>.
  688. *
  689. * @param container Container for the element.
  690. * Must not be <code>null</code>
  691. *
  692. * @param parentWrapper Wrapper for the parent element, if any.
  693. * May be <code>null</code>.
  694. *
  695. * @param target Target this element is part of.
  696. * Must not be <code>null</code>.
  697. */
  698. public ElementHandler(TaskContainer container, RuntimeConfigurable2 parentWrapper, Target target) {
  699. this.container = container;
  700. this.parentWrapper = parentWrapper;
  701. this.target = target;
  702. }
  703. /**
  704. * Initialisation routine called after handler creation
  705. * with the element name and attributes. This configures
  706. * the element with its attributes and sets it up with
  707. * its parent container (if any). Nested elements are then
  708. * added later as the parser encounters them.
  709. *
  710. * @param tag Name of the element which caused this handler
  711. * to be created. Must not be <code>null</code>.
  712. *
  713. * @param attrs Attributes of the element which caused this
  714. * handler to be created. Must not be <code>null</code>.
  715. *
  716. * @exception SAXParseException in case of error (not thrown in
  717. * this implementation)
  718. */
  719. public void onStartElement(String uri, String tag, String qname,
  720. Attributes attrs,
  721. AntXmlContext context)
  722. throws SAXParseException
  723. {
  724. if (context.project.getDataTypeDefinitions().get(qname) != null) {
  725. try {
  726. element = context.project.createDataType(qname);
  727. if (element == null) {
  728. throw new BuildException("Unknown data type "+qname);
  729. }
  730. wrapper = new RuntimeConfigurable2(element, qname);
  731. wrapper.setAttributes2(attrs);
  732. target.addDataType(wrapper);
  733. } catch (BuildException exc) {
  734. throw new SAXParseException(exc.getMessage(), context.locator, exc);
  735. }
  736. } else {
  737. Task task=null;
  738. try {
  739. task = context.project.createTask(qname);
  740. } catch (BuildException e) {
  741. // swallow here, will be thrown again in
  742. // UnknownElement.maybeConfigure if the problem persists.
  743. }
  744. if (task == null) {
  745. task = new UnknownElement(qname);
  746. task.setProject(context.project);
  747. //XXX task.setTaskType(qname);
  748. task.setTaskName(qname);
  749. }
  750. element=task;
  751. task.setLocation(new Location(context.locator.getSystemId(),
  752. context.locator.getLineNumber(),
  753. context.locator.getColumnNumber()));
  754. context.configureId(task, attrs);
  755. task.setOwningTarget(target);
  756. container.addTask(task);
  757. task.init();
  758. wrapper=new RuntimeConfigurable2(task, task.getTaskName());
  759. wrapper.setAttributes2(attrs);
  760. if (parentWrapper != null) {
  761. parentWrapper.addChild(wrapper);
  762. }
  763. }
  764. }
  765. /**
  766. * Adds text to the task, using the wrapper
  767. *
  768. * @param buf A character array of the text within the element.
  769. * Will not be <code>null</code>.
  770. * @param start The start element in the array.
  771. * @param count The number of characters to read from the array.
  772. *
  773. * @exception SAXParseException if the element doesn't support text
  774. *
  775. * @see ProjectHelper#addText(Project,Object,char[],int,int)
  776. */
  777. public void characters(char[] buf, int start, int count,
  778. AntXmlContext context)
  779. throws SAXParseException
  780. {
  781. wrapper.addText(buf, start, count);
  782. }
  783. /**
  784. * Handles the start of an element within a target. Task containers
  785. * will always use another task handler, and all other tasks
  786. * will always use a nested element handler.
  787. *
  788. * @param tag The name of the element being started.
  789. * Will not be <code>null</code>.
  790. * @param attrs Attributes of the element being started.
  791. * Will not be <code>null</code>.
  792. *
  793. * @exception SAXParseException if an error occurs when initialising
  794. * the appropriate child handler
  795. */
  796. public AntHandler onStartChild(String uri, String tag, String qname,
  797. Attributes attrs,
  798. AntXmlContext context)
  799. throws SAXParseException
  800. {
  801. if (element instanceof TaskContainer) {
  802. // task can contain other tasks - no other nested elements possible
  803. return new ElementHandler((TaskContainer)element, wrapper, target);
  804. }
  805. else {
  806. return new NestedElementHandler(element, wrapper, target);
  807. }
  808. }
  809. }
  810. /**
  811. * Handler for all nested properties.
  812. */
  813. public static class NestedElementHandler extends ElementHandler {
  814. /** Parent object (task/data type/etc). */
  815. private Object parent;
  816. /**
  817. * Constructor.
  818. *
  819. * @param parentHandler The handler which should be restored to the
  820. * parser at the end of the element.
  821. * Must not be <code>null</code>.
  822. *
  823. * @param parent Parent of this element (task/data type/etc).
  824. * Must not be <code>null</code>.
  825. *
  826. * @param parentWrapper Wrapper for the parent element, if any.
  827. * Must not be <code>null</code>.
  828. *
  829. * @param target Target this element is part of.
  830. * Must not be <code>null</code>.
  831. */
  832. public NestedElementHandler(Object parent,
  833. RuntimeConfigurable2 parentWrapper,
  834. Target target) {
  835. super(null, parentWrapper, target);
  836. if (parent instanceof TaskAdapter) {
  837. this.parent = ((TaskAdapter) parent).getProxy();
  838. } else {
  839. this.parent = parent;
  840. }
  841. }
  842. /**
  843. * Initialisation routine called after handler creation
  844. * with the element name and attributes. This configures
  845. * the element with its attributes and sets it up with
  846. * its parent container (if any). Nested elements are then
  847. * added later as the parser encounters them.
  848. *
  849. * @param tag Name of the element which caused this handler
  850. * to be created. Must not be <code>null</code>.
  851. *
  852. * @param attrs Attributes of the element which caused this
  853. * handler to be created. Must not be <code>null</code>.
  854. *
  855. * @exception SAXParseException in case of error, such as a
  856. * BuildException being thrown during configuration.
  857. */
  858. public void onStartElement(String uri, String propType, String qname,
  859. Attributes attrs,
  860. AntXmlContext context)
  861. throws SAXParseException
  862. {
  863. try {
  864. String elementName = qname.toLowerCase(Locale.US);
  865. if (parent instanceof UnknownElement) {
  866. UnknownElement uc = new UnknownElement(elementName);
  867. uc.setProject(context.project);
  868. ((UnknownElement) parent).addChild(uc);
  869. element = uc;
  870. } else {
  871. Class parentClass = parent.getClass();
  872. IntrospectionHelper ih =
  873. IntrospectionHelper.getHelper(parentClass);
  874. element = ih.createElement(context.project, parent, elementName);
  875. }
  876. context.configureId(element, attrs);
  877. wrapper = new RuntimeConfigurable2(element, qname);
  878. wrapper.setAttributes2(attrs);
  879. parentWrapper.addChild(wrapper);
  880. } catch (BuildException exc) {
  881. throw new SAXParseException(exc.getMessage(), context.locator, exc);
  882. }
  883. }
  884. }
  885. }