Clover coverage report - Ant Coverage
Coverage timestamp: Tue Apr 8 2003 20:43:55 EST
file stats: LOC: 857   Methods: 25
NCLOC: 429   Classes: 7
 
 Source file Conditionals Statements Methods TOTAL
ProjectHelper2.java 63.7% 81.8% 88% 76.6%
 1   
 /*
 2   
  * The Apache Software License, Version 1.1
 3   
  *
 4   
  * Copyright (c) 2000-2003 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 "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   
 
 55   
 package org.apache.tools.ant.helper;
 56   
 
 57   
 import java.io.File;
 58   
 import java.io.FileInputStream;
 59   
 import java.io.FileNotFoundException;
 60   
 import java.io.IOException;
 61   
 import java.io.UnsupportedEncodingException;
 62   
 import java.util.Hashtable;
 63   
 import java.util.Stack;
 64   
 import java.util.Locale;
 65   
 
 66   
 import org.xml.sax.Locator;
 67   
 import org.xml.sax.InputSource;
 68   
 import org.xml.sax.SAXParseException;
 69   
 import org.xml.sax.SAXException;
 70   
 import org.xml.sax.Attributes;
 71   
 import org.xml.sax.helpers.DefaultHandler;
 72   
 
 73   
 import org.apache.tools.ant.util.JAXPUtils;
 74   
 import org.apache.tools.ant.util.FileUtils;
 75   
 
 76   
 import org.apache.tools.ant.ProjectHelper;
 77   
 import org.apache.tools.ant.Project;
 78   
 import org.apache.tools.ant.Target;
 79   
 import org.apache.tools.ant.RuntimeConfigurable;
 80   
 import org.apache.tools.ant.BuildException;
 81   
 import org.apache.tools.ant.Location;
 82   
 import org.apache.tools.ant.UnknownElement;
 83   
 
 84   
 import org.xml.sax.XMLReader;
 85   
 
 86   
 /**
 87   
  * Sax2 based project reader
 88   
  *
 89   
  * @author duncan@x180.com
 90   
  * @author Costin Manolache
 91   
  */
 92   
 public class ProjectHelper2 extends ProjectHelper {
 93   
     /* Stateless */
 94   
 
 95   
     // singletons - since all state is in the context
 96   
     private static AntHandler elementHandler = new ElementHandler();
 97   
     private static AntHandler targetHandler = new TargetHandler();
 98   
     private static AntHandler mainHandler = new MainHandler();
 99   
     private static AntHandler projectHandler = new ProjectHandler();
 100   
 
 101   
     /**
 102   
      * helper for path -> URI and URI -> path conversions.
 103   
      */
 104   
     private static FileUtils fu = FileUtils.newFileUtils();
 105   
 
 106  566
     public void parse(Project project, Object source)
 107   
             throws BuildException {
 108  566
         this.getImportStack().addElement(source);
 109   
         //System.out.println("Adding " + source);
 110  566
         AntXMLContext context = null;
 111  566
         context = (AntXMLContext) project.getReference("ant.parsing.context");
 112   
 //        System.out.println("Parsing " + getImportStack().size() + " " +
 113   
 //                context+ " " + getImportStack() );
 114  566
         if (context == null) {
 115  566
             context = new AntXMLContext(project);
 116  566
             project.addReference("ant.parsing.context", context);
 117  566
             project.addReference("ant.targets", context.getTargets());
 118   
         }
 119   
 
 120  566
         if (this.getImportStack().size() > 1) {
 121   
             // we are in an imported file.
 122  0
             context.setIgnoreProjectTag(true);
 123  0
             parse(project, source, new RootHandler(context));
 124   
         } else {
 125   
             // top level file
 126  566
             parse(project, source, new RootHandler(context));
 127   
             // Execute the top-level target
 128  564
             context.getImplicitTarget().execute();
 129   
         }
 130   
     }
 131   
 
 132   
     /**
 133   
      * Parses the project file, configuring the project as it goes.
 134   
      *
 135   
      * @exception BuildException if the configuration is invalid or cannot
 136   
      *                           be read
 137   
      */
 138  566
     public void parse(Project project, Object source, RootHandler handler)
 139   
             throws BuildException {
 140   
 
 141  566
         AntXMLContext context = handler.context;
 142   
 
 143  566
         File buildFile = null;
 144   
 
 145  566
         if (source instanceof File) {
 146  566
             buildFile = (File) source;
 147   
 //         } else if (source instanceof InputStream ) {
 148   
 //         } else if (source instanceof URL ) {
 149   
 //         } else if (source instanceof InputSource ) {
 150   
         } else {
 151  0
             throw new BuildException("Source " + source.getClass().getName() +
 152   
                                      " not supported by this plugin");
 153   
         }
 154   
 
 155  566
         FileInputStream inputStream = null;
 156  566
         InputSource inputSource = null;
 157   
 
 158  566
         buildFile = new File(buildFile.getAbsolutePath());
 159  566
         context.setBuildFile(buildFile);
 160   
 
 161  566
         try {
 162   
             /**
 163   
              * SAX 2 style parser used to parse the given file.
 164   
              */
 165  566
             XMLReader parser = JAXPUtils.getNamespaceXMLReader();
 166   
 
 167  566
             String uri = fu.toURI(buildFile.getAbsolutePath());
 168   
 
 169  566
             inputStream = new FileInputStream(buildFile);
 170  566
             inputSource = new InputSource(inputStream);
 171  566
             inputSource.setSystemId(uri);
 172  566
             project.log("parsing buildfile " + buildFile
 173   
                 + " with URI = " + uri, Project.MSG_VERBOSE);
 174   
 
 175  566
             DefaultHandler hb = handler;
 176   
 
 177  566
             parser.setContentHandler(hb);
 178  566
             parser.setEntityResolver(hb);
 179  566
             parser.setErrorHandler(hb);
 180  566
             parser.setDTDHandler(hb);
 181  566
             parser.parse(inputSource);
 182   
         } catch (SAXParseException exc) {
 183  2
             Location location = new Location(exc.getSystemId(),
 184   
                 exc.getLineNumber(), exc.getColumnNumber());
 185   
 
 186  2
             Throwable t = exc.getException();
 187  2
             if (t instanceof BuildException) {
 188  0
                 BuildException be = (BuildException) t;
 189  0
                 if (be.getLocation() == Location.UNKNOWN_LOCATION) {
 190  0
                     be.setLocation(location);
 191   
                 }
 192  0
                 throw be;
 193   
             }
 194   
 
 195  2
             throw new BuildException(exc.getMessage(), t, location);
 196   
         } catch (SAXException exc) {
 197  0
             Throwable t = exc.getException();
 198  0
             if (t instanceof BuildException) {
 199  0
                 throw (BuildException) t;
 200   
             }
 201  0
             throw new BuildException(exc.getMessage(), t);
 202   
         } catch (FileNotFoundException exc) {
 203  0
             throw new BuildException(exc);
 204   
         } catch (UnsupportedEncodingException exc) {
 205  0
               throw new BuildException("Encoding of project file is invalid.",
 206   
                 exc);
 207   
         } catch (IOException exc) {
 208  0
             throw new BuildException("Error reading project file: "
 209   
                 + exc.getMessage(), exc);
 210   
         } finally {
 211  566
             if (inputStream != null) {
 212  566
                 try {
 213  566
                     inputStream.close();
 214   
                 } catch (IOException ioe) {
 215   
                     // ignore this
 216   
                 }
 217   
             }
 218   
         }
 219   
     }
 220   
 
 221   
     /**
 222   
      * The common superclass for all SAX event handlers used to parse
 223   
      * the configuration file.
 224   
      *
 225   
      * The context will hold all state information. At each time
 226   
      * there is one active handler for the current element. It can
 227   
      * use onStartChild() to set an alternate handler for the child.
 228   
      */
 229   
     public static class AntHandler  {
 230   
         /**
 231   
          * Handles the start of an element. This base implementation does
 232   
          * nothing.
 233   
          *
 234   
          * @param tag The name of the element being started.
 235   
          *            Will not be <code>null</code>.
 236   
          * @param attrs Attributes of the element being started.
 237   
          *              Will not be <code>null</code>.
 238   
          *
 239   
          * @exception SAXParseException if this method is not overridden, or in
 240   
          *                              case of error in an overridden version
 241   
          */
 242  0
         public void onStartElement(String uri, String tag, String qname,
 243   
                                    Attributes attrs,
 244   
                                    AntXMLContext context)
 245   
             throws SAXParseException {
 246   
         }
 247   
 
 248   
         /**
 249   
          * Handles the start of an element. This base implementation just
 250   
          * throws an exception - you must override this method if you expect
 251   
          * child elements.
 252   
          *
 253   
          * @param tag The name of the element being started.
 254   
          *            Will not be <code>null</code>.
 255   
          * @param attrs Attributes of the element being started.
 256   
          *              Will not be <code>null</code>.
 257   
          *
 258   
          * @exception SAXParseException if this method is not overridden, or in
 259   
          *                              case of error in an overridden version
 260   
          */
 261  0
         public AntHandler onStartChild(String uri, String tag, String qname,
 262   
                                        Attributes attrs,
 263   
                                        AntXMLContext context)
 264   
             throws SAXParseException {
 265  0
             throw new SAXParseException("Unexpected element \"" + qname
 266   
                 + " \"", context.getLocator());
 267   
         }
 268   
 
 269  30608
         public void onEndChild(String uri, String tag, String qname,
 270   
                                      AntXMLContext context)
 271   
             throws SAXParseException {
 272   
         }
 273   
 
 274   
         /**
 275   
          * Called when this element and all elements nested into it have been
 276   
          * handled (i.e. at the </end_tag_of_the_element> ).
 277   
          */
 278  564
         public void onEndElement(String uri, String tag,
 279   
                                  AntXMLContext context) {
 280   
         }
 281   
 
 282   
         /**
 283   
          * Handles text within an element. This base implementation just
 284   
          * throws an exception, you must override it if you expect content.
 285   
          *
 286   
          * @param buf A character array of the text within the element.
 287   
          *            Will not be <code>null</code>.
 288   
          * @param start The start element in the array.
 289   
          * @param count The number of characters to read from the array.
 290   
          *
 291   
          * @exception SAXParseException if this method is not overridden, or in
 292   
          *                              case of error in an overridden version
 293   
          */
 294  34467
         public void characters(char[] buf, int start, int count, AntXMLContext context)
 295   
             throws SAXParseException {
 296  34467
             String s = new String(buf, start, count).trim();
 297   
 
 298  34467
             if (s.length() > 0) {
 299  2
                 throw new SAXParseException("Unexpected text \"" + s
 300   
                     + "\"", context.getLocator());
 301   
             }
 302   
         }
 303   
 
 304   
         /**
 305   
          * Will be called every time a namespace is reached.
 306   
          * It'll verify if the ns was processed, and if not load the task
 307   
          * definitions.
 308   
          */
 309  0
         protected void checkNamespace(String uri) {
 310   
 
 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   
         private Stack antHandlers = new Stack();
 321   
         private AntHandler currentHandler = null;
 322   
         private AntXMLContext context;
 323   
 
 324  566
         public RootHandler(AntXMLContext context) {
 325  566
             currentHandler = ProjectHelper2.mainHandler;
 326  566
             antHandlers.push(currentHandler);
 327  566
             this.context = context;
 328   
         }
 329   
 
 330   
         /**
 331   
          * Resolves file: URIs relative to the build file.
 332   
          *
 333   
          * @param publicId The public identifer, or <code>null</code>
 334   
          *                 if none is available. Ignored in this
 335   
          *                 implementation.
 336   
          * @param systemId The system identifier provided in the XML
 337   
          *                 document. Will not be <code>null</code>.
 338   
          */
 339  10
         public InputSource resolveEntity(String publicId,
 340   
                                          String systemId) {
 341   
 
 342  10
             context.getProject().log("resolving systemId: " +
 343   
                     systemId, Project.MSG_VERBOSE);
 344   
 
 345  10
             if (systemId.startsWith("file:")) {
 346  10
                 String path = fu.fromURI(systemId);
 347   
 
 348  10
                 File file = new File(path);
 349  10
                 if (!file.isAbsolute()) {
 350  7
                     file = fu.resolveFile(context.getBuildFileParent(), path);
 351   
                 }
 352  10
                 try {
 353  10
                     InputSource inputSource =
 354   
                             new InputSource(new FileInputStream(file));
 355  10
                     inputSource.setSystemId(fu.toURI(file.getAbsolutePath()));
 356  10
                     return inputSource;
 357   
                 } catch (FileNotFoundException fne) {
 358  0
                     context.getProject().log(file.getAbsolutePath() +
 359   
                             " could not be found", Project.MSG_WARN);
 360   
                 }
 361   
 
 362   
             }
 363   
             // use default if not file or file not found
 364  0
             return null;
 365   
         }
 366   
 
 367   
         /**
 368   
          * Handles the start of a project element. A project handler is created
 369   
          * and initialised with the element name and attributes.
 370   
          *
 371   
          * @param tag The name of the element being started.
 372   
          *            Will not be <code>null</code>.
 373   
          * @param attrs Attributes of the element being started.
 374   
          *              Will not be <code>null</code>.
 375   
          *
 376   
          * @exception org.xml.sax.SAXParseException if the tag given is not
 377   
          *                              <code>"project"</code>
 378   
          */
 379  30611
         public void startElement(String uri, String tag, String qname, Attributes attrs)
 380   
             throws SAXParseException {
 381  30611
             AntHandler next
 382   
                 = currentHandler.onStartChild(uri, tag, qname, attrs, context);
 383  30611
             antHandlers.push(currentHandler);
 384  30611
             currentHandler = next;
 385  30611
             currentHandler.onStartElement(uri, tag, qname, attrs, context);
 386   
         }
 387   
 
 388   
         /**
 389   
          * Sets the locator in the project helper for future reference.
 390   
          *
 391   
          * @param locator The locator used by the parser.
 392   
          *                Will not be <code>null</code>.
 393   
          */
 394  566
         public void setDocumentLocator(Locator locator) {
 395  566
             context.setLocator(locator);
 396   
         }
 397   
 
 398   
         /**
 399   
          * Handles the end of an element. Any required clean-up is performed
 400   
          * by the onEndElement() method and then the original handler
 401   
          * is restored to the parser.
 402   
          *
 403   
          * @param name The name of the element which is ending.
 404   
          *             Will not be <code>null</code>.
 405   
          *
 406   
          * @exception SAXException in case of error (not thrown in
 407   
          *                         this implementation)
 408   
          *
 409   
          */
 410  30608
         public void endElement(String uri, String name, String qName) throws SAXException {
 411  30608
             currentHandler.onEndElement(uri, name, context);
 412  30608
             AntHandler prev = (AntHandler) antHandlers.pop();
 413  30608
             currentHandler = prev;
 414  30608
             if (currentHandler != null) {
 415  30608
                 currentHandler.onEndChild(uri, name, qName, context);
 416   
             }
 417   
         }
 418   
 
 419  49831
         public void characters(char[] buf, int start, int count)
 420   
             throws SAXParseException {
 421  49831
             currentHandler.characters(buf, start, count, context);
 422   
         }
 423   
     }
 424   
 
 425   
     public static class MainHandler extends AntHandler {
 426   
 
 427  566
         public AntHandler onStartChild(String uri, String name, String qname,
 428   
                                        Attributes attrs,
 429   
                                        AntXMLContext context)
 430   
             throws SAXParseException {
 431  566
             if (qname.equals("project")) {
 432  566
                 return ProjectHelper2.projectHandler;
 433   
             } else {
 434   
 //                 if (context.importlevel > 0 ) {
 435   
 //                     // we are in an imported file. Allow top-level <target>.
 436   
 //                     if (qname.equals( "target" ) )
 437   
 //                         return ProjectHelper2.targetHandler;
 438   
 //                 }
 439  0
                 throw new SAXParseException("Unexpected element \"" + qname
 440   
                     + "\" " + name, context.getLocator());
 441   
             }
 442   
         }
 443   
     }
 444   
 
 445   
     /**
 446   
      * Handler for the top level "project" element.
 447   
      */
 448   
     public static class ProjectHandler extends AntHandler {
 449   
 
 450   
         /**
 451   
          * Initialisation routine called after handler creation
 452   
          * with the element name and attributes. The attributes which
 453   
          * this handler can deal with are: <code>"default"</code>,
 454   
          * <code>"name"</code>, <code>"id"</code> and <code>"basedir"</code>.
 455   
          *
 456   
          * @param tag Name of the element which caused this handler
 457   
          *            to be created. Should not be <code>null</code>.
 458   
          *            Ignored in this implementation.
 459   
          * @param attrs Attributes of the element which caused this
 460   
          *              handler to be created. Must not be <code>null</code>.
 461   
          *
 462   
          * @exception SAXParseException if an unexpected attribute is
 463   
          *            encountered or if the <code>"default"</code> attribute
 464   
          *            is missing.
 465   
          */
 466  566
         public void onStartElement(String uri, String tag, String qname,
 467   
                                    Attributes attrs,
 468   
                                    AntXMLContext context)
 469   
             throws SAXParseException {
 470  566
             String id = null;
 471  566
             String baseDir = null;
 472   
 
 473  566
             Project project = context.getProject();
 474   
 
 475   
             /** XXX I really don't like this - the XML processor is still
 476   
              * too 'involved' in the processing. A better solution (IMO)
 477   
              * would be to create UE for Project and Target too, and
 478   
              * then process the tree and have Project/Target deal with
 479   
              * its attributes ( similar with Description ).
 480   
              *
 481   
              * If we eventually switch to ( or add support for ) DOM,
 482   
              * things will work smoothly - UE can be avoided almost completely
 483   
              * ( it could still be created on demand, for backward compat )
 484   
              */
 485   
 
 486  566
             for (int i = 0; i < attrs.getLength(); i++) {
 487  1634
                 String key = attrs.getQName(i);
 488  1634
                 String value = attrs.getValue(i);
 489   
 
 490  1634
                 if (key.equals("default")) {
 491  566
                     if (value != null && !value.equals("")) {
 492  566
                         if (!context.isIgnoringProjectTag()) {
 493  566
                             project.setDefaultTarget(value);
 494   
                         }
 495   
                     }
 496  1068
                 } else if (key.equals("name")) {
 497  520
                     if (value != null) {
 498  520
                         context.setCurrentProjectName(value);
 499   
 
 500  520
                         if (!context.isIgnoringProjectTag()) {
 501  520
                             project.setName(value);
 502  520
                             project.addReference(value, project);
 503   
                         }
 504   
                     }
 505  548
                 } else if (key.equals("id")) {
 506  0
                     if (value != null) {
 507   
                         // What's the difference between id and name ?
 508  0
                         if (!context.isIgnoringProjectTag()) {
 509  0
                             project.addReference(value, project);
 510   
                         }
 511   
                     }
 512  548
                 } else if (key.equals("basedir")) {
 513  548
                     if (!context.isIgnoringProjectTag()) {
 514  548
                         baseDir = value;
 515   
                     }
 516   
                 } else {
 517   
                     // XXX ignore attributes in a different NS ( maybe store them ? )
 518  0
                     throw new SAXParseException("Unexpected attribute \""
 519   
                         + attrs.getQName(i) + "\"", context.getLocator());
 520   
                 }
 521   
             }
 522   
 
 523   
             // XXX Move to Project ( so it is shared by all helpers )
 524  566
             String antFileProp = "ant.file." + context.getCurrentProjectName();
 525  566
             String dup = project.getProperty(antFileProp);
 526  566
             if (dup != null) {
 527  23
                 File dupFile = new File(dup);
 528  23
                 if (context.isIgnoringProjectTag() &&
 529   
                     !dupFile.equals(context.getBuildFile())) {
 530  0
                     project.log("Duplicated project name in import. Project " +
 531   
                         context.getCurrentProjectName() + " defined first in " +
 532   
                         dup + " and again in " + context.getBuildFile(),
 533   
                         Project.MSG_WARN);
 534   
                 }
 535   
             }
 536   
 
 537  566
             if (context.getBuildFile() != null) {
 538  566
                 project.setUserProperty("ant.file."
 539   
                     + context.getCurrentProjectName(),
 540   
                     context.getBuildFile().toString());
 541   
             }
 542   
 
 543  566
             if (context.isIgnoringProjectTag()) {
 544   
                 // no further processing
 545  0
                 return;
 546   
             }
 547   
             // set explicitely before starting ?
 548  566
             if (project.getProperty("basedir") != null) {
 549  40
                 project.setBasedir(project.getProperty("basedir"));
 550   
             } else {
 551   
                 // Default for baseDir is the location of the build file.
 552  526
                 if (baseDir == null) {
 553  15
                     project.setBasedir(context.getBuildFileParent().getAbsolutePath());
 554   
                 } else {
 555   
                     // check whether the user has specified an absolute path
 556  511
                     if ((new File(baseDir)).isAbsolute()) {
 557  0
                         project.setBasedir(baseDir);
 558   
                     } else {
 559  511
                         project.setBaseDir(project.resolveFile(baseDir,
 560   
                                                                context.getBuildFileParent()));
 561   
                     }
 562   
                 }
 563   
             }
 564   
 
 565  566
             project.addTarget("", context.getImplicitTarget());
 566  566
             context.setCurrentTarget(context.getImplicitTarget());
 567   
         }
 568   
 
 569   
         /**
 570   
          * Handles the start of a top-level element within the project. An
 571   
          * appropriate handler is created and initialised with the details
 572   
          * of the element.
 573   
          *
 574   
          * @param tag The name of the element being started.
 575   
          *            Will not be <code>null</code>.
 576   
          * @param attrs Attributes of the element being started.
 577   
          *              Will not be <code>null</code>.
 578   
          *
 579   
          * @exception org.xml.sax.SAXParseException if the tag given is not
 580   
          *            <code>"taskdef"</code>, <code>"typedef"</code>,
 581   
          *            <code>"property"</code>, <code>"target"</code>
 582   
          *            or a data type definition
 583   
          */
 584  8553
         public AntHandler onStartChild(String uri, String name, String qname,
 585   
                                        Attributes attrs,
 586   
                                        AntXMLContext context)
 587   
             throws SAXParseException {
 588  8553
             if (qname.equals("target")) {
 589  7960
                 return ProjectHelper2.targetHandler;
 590   
             } else {
 591  593
                 return ProjectHelper2.elementHandler;
 592   
             }
 593   
         }
 594   
 
 595   
     }
 596   
 
 597   
     /**
 598   
      * Handler for "target" elements.
 599   
      */
 600   
     public static class TargetHandler extends AntHandler {
 601   
 
 602   
         /**
 603   
          * Initialisation routine called after handler creation
 604   
          * with the element name and attributes. The attributes which
 605   
          * this handler can deal with are: <code>"name"</code>,
 606   
          * <code>"depends"</code>, <code>"if"</code>,
 607   
          * <code>"unless"</code>, <code>"id"</code> and
 608   
          * <code>"description"</code>.
 609   
          *
 610   
          * @param tag Name of the element which caused this handler
 611   
          *            to be created. Should not be <code>null</code>.
 612   
          *            Ignored in this implementation.
 613   
          * @param attrs Attributes of the element which caused this
 614   
          *              handler to be created. Must not be <code>null</code>.
 615   
          *
 616   
          * @exception SAXParseException if an unexpected attribute is encountered
 617   
          *            or if the <code>"name"</code> attribute is missing.
 618   
          */
 619  7960
         public void onStartElement(String uri, String tag, String qname,
 620   
                                    Attributes attrs,
 621   
                                    AntXMLContext context)
 622   
             throws SAXParseException {
 623  7960
             String name = null;
 624  7960
             String depends = "";
 625   
 
 626  7960
             Project project = context.getProject();
 627  7960
             Target target = new Target();
 628  7960
             context.addTarget(target);
 629   
 
 630  7960
             for (int i = 0; i < attrs.getLength(); i++) {
 631  9252
                 String key = attrs.getQName(i);
 632  9252
                 String value = attrs.getValue(i);
 633   
 
 634  9252
                 if (key.equals("name")) {
 635  7960
                     name = value;
 636  7960
                     if ("".equals(name)) {
 637  0
                         throw new BuildException("name attribute must "
 638   
                             + "not be empty");
 639   
                     }
 640  1292
                 } else if (key.equals("depends")) {
 641  1246
                     depends = value;
 642  46
                 } else if (key.equals("if")) {
 643  8
                     target.setIf(value);
 644  38
                 } else if (key.equals("unless")) {
 645  4
                     target.setUnless(value);
 646  34
                 } else if (key.equals("id")) {
 647  0
                     if (value != null && !value.equals("")) {
 648  0
                         context.getProject().addReference(value, target);
 649   
                     }
 650  34
                 } else if (key.equals("description")) {
 651  34
                     target.setDescription(value);
 652   
                 } else {
 653  0
                     throw new SAXParseException("Unexpected attribute \""
 654   
                         + key + "\"", context.getLocator());
 655   
                 }
 656   
             }
 657   
 
 658  7960
             if (name == null) {
 659  0
                 throw new SAXParseException("target element appears without "
 660   
                     + "a name attribute", context.getLocator());
 661   
             }
 662   
 
 663  7960
             Hashtable currentTargets = project.getTargets();
 664   
 
 665   
             // If the name has already beend defined ( import for example )
 666  7960
             if (currentTargets.containsKey(name)) {
 667   
                 // Alter the name.
 668  0
                 if (context.getCurrentProjectName() != null) {
 669  0
                     String newName = context.getCurrentProjectName()
 670   
                         + "." + name;
 671  0
                     project.log("Already defined in main or a previous import, "
 672   
                         + "define " + name + " as " + newName,
 673   
                                 Project.MSG_VERBOSE);
 674  0
                     name = newName;
 675   
                 } else {
 676  0
                     project.log("Already defined in main or a previous import, "
 677   
                         + "ignore " + name, Project.MSG_VERBOSE);
 678  0
                     name = null;
 679   
                 }
 680   
             }
 681   
 
 682  7960
             if (name != null) {
 683  7960
                 target.setName(name);
 684  7960
                 project.addOrReplaceTarget(name, target);
 685   
             }
 686   
 
 687   
             // take care of dependencies
 688  7960
             if (depends.length() > 0) {
 689  1246
                 target.setDepends(depends);
 690   
             }
 691   
         }
 692   
 
 693   
         /**
 694   
          * Handles the start of an element within a target.
 695   
          *
 696   
          * @param tag The name of the element being started.
 697   
          *            Will not be <code>null</code>.
 698   
          * @param attrs Attributes of the element being started.
 699   
          *              Will not be <code>null</code>.
 700   
          *
 701   
          * @exception SAXParseException if an error occurs when initialising
 702   
          *                              the appropriate child handler
 703   
          */
 704  14044
         public AntHandler onStartChild(String uri, String name, String qname,
 705   
                                        Attributes attrs,
 706   
                                        AntXMLContext context)
 707   
             throws SAXParseException {
 708  14044
             return ProjectHelper2.elementHandler;
 709   
         }
 710   
 
 711  7959
         public void onEndElement(String uri, String tag, AntXMLContext context) {
 712  7959
             context.setCurrentTarget(context.getImplicitTarget());
 713   
         }
 714   
     }
 715   
 
 716   
     /**
 717   
      * Handler for all project elements ( tasks, data types )
 718   
      */
 719   
     public static class ElementHandler extends AntHandler {
 720   
 
 721   
         /**
 722   
          * Constructor.
 723   
          */
 724  1
         public ElementHandler() {
 725   
         }
 726   
 
 727   
         /**
 728   
          * Initialisation routine called after handler creation
 729   
          * with the element name and attributes. This configures
 730   
          * the element with its attributes and sets it up with
 731   
          * its parent container (if any). Nested elements are then
 732   
          * added later as the parser encounters them.
 733   
          *
 734   
          * @param tag Name of the element which caused this handler
 735   
          *            to be created. Must not be <code>null</code>.
 736   
          *
 737   
          * @param attrs Attributes of the element which caused this
 738   
          *              handler to be created. Must not be <code>null</code>.
 739   
          *
 740   
          * @exception SAXParseException in case of error (not thrown in
 741   
          *                              this implementation)
 742   
          */
 743  22085
         public void onStartElement(String uri, String tag, String qname,
 744   
                                    Attributes attrs,
 745   
                                    AntXMLContext context)
 746   
             throws SAXParseException {
 747  22085
             RuntimeConfigurable parentWrapper = context.currentWrapper();
 748  22085
             Object parent = null;
 749   
 
 750  22085
             if (parentWrapper != null) {
 751  7448
                 parent = parentWrapper.getProxy();
 752   
             }
 753   
 
 754  22085
             if (parent != null) {
 755   
                 // nested elements. Backward compatibilitiy - only nested elements
 756   
                 // are lower cased in the original processor
 757  7448
                 qname = qname.toLowerCase(Locale.US);
 758   
                 // XXX What about nested elements that are inside TaskContainers ?
 759   
                 // We can't know that that we need lowercase until we know
 760   
                 // parent is not a TaskContainer. Maybe this test should
 761   
                 // be done in UnknownElement.
 762   
 
 763   
                 // Note: the original code seems to have a similar problem: the lowercase
 764   
                 // conversion happens only inside ProjectHelper, if we know that the
 765   
                 // parent is not TaskContainer. If the parent is not known - UE are used
 766   
                 // and AFAIK there is no code to deal with that, so the conversion will be
 767   
                 // different based on context ( if the enclosing task is taskdefed in target
 768   
                 // or known at top level ).
 769   
             }
 770   
 
 771   
             /* UnknownElement is used for tasks and data types - with
 772   
                delayed eval */
 773  22085
             UnknownElement task = new UnknownElement(qname);
 774  22085
             task.setProject(context.getProject());
 775   
             //XXX task.setTaskType(qname);
 776   
 
 777  22085
             task.setTaskName(qname);
 778   
 
 779  22085
             Location location = new Location(context.getLocator().getSystemId(),
 780   
                     context.getLocator().getLineNumber(),
 781   
                     context.getLocator().getColumnNumber());
 782  22085
             task.setLocation(location);
 783  22085
             task.setOwningTarget(context.getCurrentTarget());
 784   
 
 785  22085
             context.configureId(task, attrs);
 786   
 
 787  22085
             if (parent != null) {
 788   
                 // Nested element
 789  7448
                 ((UnknownElement) parent).addChild(task);
 790   
             }  else {
 791   
                 // Task included in a target ( including the default one ).
 792  14637
                 context.getCurrentTarget().addTask(task);
 793   
             }
 794   
 
 795   
             // container.addTask(task);
 796   
             // This is a nop in UE: task.init();
 797   
 
 798  22085
             RuntimeConfigurable wrapper 
 799   
                 = new RuntimeConfigurable(task, task.getTaskName());
 800   
 
 801  22085
             for (int i = 0; i < attrs.getLength(); i++) {
 802  32396
                 wrapper.setAttribute(attrs.getQName(i),
 803   
                         attrs.getValue(i));
 804   
             }
 805   
 
 806  22085
             if (parentWrapper != null) {
 807  7448
                 parentWrapper.addChild(wrapper);
 808   
             }
 809   
 
 810  22085
             context.pushWrapper(wrapper);
 811   
         }
 812   
 
 813   
         /**
 814   
          * Adds text to the task, using the wrapper
 815   
          *
 816   
          * @param buf A character array of the text within the element.
 817   
          *            Will not be <code>null</code>.
 818   
          * @param start The start element in the array.
 819   
          * @param count The number of characters to read from the array.
 820   
          *
 821   
          * @exception SAXParseException if the element doesn't support text
 822   
          *
 823   
          * @see ProjectHelper#addText(Project,java.lang.Object,char[],int,int)
 824   
          */
 825  15364
         public void characters(char[] buf, int start, int count,
 826   
                                AntXMLContext context)
 827   
             throws SAXParseException {
 828  15364
             RuntimeConfigurable wrapper = context.currentWrapper();
 829  15364
             wrapper.addText(buf, start, count);
 830   
         }
 831   
 
 832   
         /**
 833   
          * Handles the start of an element within a target. Task containers
 834   
          * will always use another task handler, and all other tasks
 835   
          * will always use a nested element handler.
 836   
          *
 837   
          * @param tag The name of the element being started.
 838   
          *            Will not be <code>null</code>.
 839   
          * @param attrs Attributes of the element being started.
 840   
          *              Will not be <code>null</code>.
 841   
          *
 842   
          * @exception SAXParseException if an error occurs when initialising
 843   
          *                              the appropriate child handler
 844   
          */
 845  7448
         public AntHandler onStartChild(String uri, String tag, String qname,
 846   
                                        Attributes attrs,
 847   
                                        AntXMLContext context)
 848   
             throws SAXParseException {
 849  7448
             return ProjectHelper2.elementHandler;
 850   
         }
 851   
 
 852  22085
         public void onEndElement(String uri, String tag, AntXMLContext context) {
 853  22085
             context.popWrapper();
 854   
         }
 855   
     }
 856   
 }
 857