Home » apache-ant-1.7.1-src » org.apache.tools » ant » helper » [javadoc | source]
    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one or more
    3    *  contributor license agreements.  See the NOTICE file distributed with
    4    *  this work for additional information regarding copyright ownership.
    5    *  The ASF licenses this file to You under the Apache License, Version 2.0
    6    *  (the "License"); you may not use this file except in compliance with
    7    *  the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    *  Unless required by applicable law or agreed to in writing, software
   12    *  distributed under the License is distributed on an "AS IS" BASIS,
   13    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    *  See the License for the specific language governing permissions and
   15    *  limitations under the License.
   16    *
   17    */
   18   
   19   package org.apache.tools.ant.helper;
   20   
   21   import java.io.File;
   22   import java.io.FileInputStream;
   23   import java.io.FileNotFoundException;
   24   import java.io.IOException;
   25   import java.io.UnsupportedEncodingException;
   26   import java.util.Locale;
   27   import org.apache.tools.ant.BuildException;
   28   import org.apache.tools.ant.IntrospectionHelper;
   29   import org.apache.tools.ant.Location;
   30   import org.apache.tools.ant.Project;
   31   import org.apache.tools.ant.ProjectHelper;
   32   import org.apache.tools.ant.RuntimeConfigurable;
   33   import org.apache.tools.ant.Target;
   34   import org.apache.tools.ant.Task;
   35   import org.apache.tools.ant.TypeAdapter;
   36   import org.apache.tools.ant.TaskContainer;
   37   import org.apache.tools.ant.UnknownElement;
   38   import org.apache.tools.ant.util.FileUtils;
   39   import org.apache.tools.ant.util.JAXPUtils;
   40   import org.xml.sax.AttributeList;
   41   import org.xml.sax.DocumentHandler;
   42   import org.xml.sax.HandlerBase;
   43   import org.xml.sax.InputSource;
   44   import org.xml.sax.Locator;
   45   import org.xml.sax.SAXException;
   46   import org.xml.sax.SAXParseException;
   47   import org.xml.sax.helpers.XMLReaderAdapter;
   48   
   49   /**
   50    * Original helper.
   51    *
   52    */
   53   public class ProjectHelperImpl extends ProjectHelper {
   54   
   55       /**
   56        * helper for path -> URI and URI -> path conversions.
   57        */
   58       private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
   59   
   60       /**
   61        * SAX 1 style parser used to parse the given file. This may
   62        * in fact be a SAX 2 XMLReader wrapped in an XMLReaderAdapter.
   63        */
   64       private org.xml.sax.Parser parser;
   65   
   66       /** The project to configure. */
   67       private Project project;
   68       /** The configuration file to parse. */
   69       private File buildFile;
   70       /**
   71        * Parent directory of the build file. Used for resolving entities
   72        * and setting the project's base directory.
   73        */
   74       private File buildFileParent;
   75       /**
   76        * Locator for the configuration file parser.
   77        * Used for giving locations of errors etc.
   78        */
   79       private Locator locator;
   80       /**
   81        * Target that all other targets will depend upon implicitly.
   82        *
   83        * <p>This holds all tasks and data type definitions that have
   84        * been placed outside of targets.</p>
   85        */
   86       private Target implicitTarget = new Target();
   87   
   88       /**
   89        * default constructor
   90        */
   91       public ProjectHelperImpl() {
   92           implicitTarget.setName("");
   93       }
   94   
   95       /**
   96        * Parses the project file, configuring the project as it goes.
   97        *
   98        * @param project project instance to be configured.
   99        * @param source the source from which the project is read.
  100        * @exception BuildException if the configuration is invalid or cannot
  101        *                           be read.
  102        */
  103       public void parse(Project project, Object source) throws BuildException {
  104           if (!(source instanceof File)) {
  105               throw new BuildException("Only File source supported by "
  106                   + "default plugin");
  107           }
  108           File bFile = (File) source;
  109           FileInputStream inputStream = null;
  110           InputSource inputSource = null;
  111   
  112           this.project = project;
  113           this.buildFile = new File(bFile.getAbsolutePath());
  114           buildFileParent = new File(this.buildFile.getParent());
  115   
  116           try {
  117               try {
  118                   parser = JAXPUtils.getParser();
  119               } catch (BuildException e) {
  120                   parser = new XMLReaderAdapter(JAXPUtils.getXMLReader());
  121               }
  122   
  123   
  124               String uri = FILE_UTILS.toURI(bFile.getAbsolutePath());
  125               inputStream = new FileInputStream(bFile);
  126               inputSource = new InputSource(inputStream);
  127               inputSource.setSystemId(uri);
  128               project.log("parsing buildfile " + bFile + " with URI = "
  129                   + uri, Project.MSG_VERBOSE);
  130               HandlerBase hb = new RootHandler(this);
  131               parser.setDocumentHandler(hb);
  132               parser.setEntityResolver(hb);
  133               parser.setErrorHandler(hb);
  134               parser.setDTDHandler(hb);
  135               parser.parse(inputSource);
  136           } catch (SAXParseException exc) {
  137               Location location =
  138                   new Location(exc.getSystemId(), exc.getLineNumber(),
  139                       exc.getColumnNumber());
  140   
  141               Throwable t = exc.getException();
  142               if (t instanceof BuildException) {
  143                   BuildException be = (BuildException) t;
  144                   if (be.getLocation() == Location.UNKNOWN_LOCATION) {
  145                       be.setLocation(location);
  146                   }
  147                   throw be;
  148               }
  149   
  150               throw new BuildException(exc.getMessage(), t, location);
  151           } catch (SAXException exc) {
  152               Throwable t = exc.getException();
  153               if (t instanceof BuildException) {
  154                   throw (BuildException) t;
  155               }
  156               throw new BuildException(exc.getMessage(), t);
  157           } catch (FileNotFoundException exc) {
  158               throw new BuildException(exc);
  159           } catch (UnsupportedEncodingException exc) {
  160               throw new BuildException("Encoding of project file is invalid.",
  161                                        exc);
  162           } catch (IOException exc) {
  163               throw new BuildException("Error reading project file: "
  164                                        + exc.getMessage(), exc);
  165           } finally {
  166               FileUtils.close(inputStream);
  167           }
  168       }
  169   
  170       /**
  171        * The common superclass for all SAX event handlers used to parse
  172        * the configuration file. Each method just throws an exception,
  173        * so subclasses should override what they can handle.
  174        *
  175        * Each type of XML element (task, target, etc.) in Ant has
  176        * a specific subclass.
  177        *
  178        * In the constructor, this class takes over the handling of SAX
  179        * events from the parent handler and returns
  180        * control back to the parent in the endElement method.
  181        */
  182       static class AbstractHandler extends HandlerBase {
  183           // CheckStyle:VisibilityModifier OFF - bc
  184   
  185           /**
  186            * Previous handler for the document.
  187            * When the next element is finished, control returns
  188            * to this handler.
  189            */
  190           protected DocumentHandler parentHandler;
  191   
  192           /** Helper impl. With non-static internal classes, the compiler will generate
  193               this automatically - but this will fail with some compilers ( reporting
  194               "Expecting to find object/array on stack" ). If we pass it
  195               explicitly it'll work with more compilers.
  196           */
  197           ProjectHelperImpl helperImpl;
  198           // CheckStyle:VisibilityModifier ON
  199   
  200           /**
  201            * Creates a handler and sets the parser to use it
  202            * for the current element.
  203            *
  204            * @param helperImpl the ProjectHelperImpl instance associated
  205            *                   with this handler.
  206            *
  207            * @param parentHandler The handler which should be restored to the
  208            *                      parser at the end of the element.
  209            *                      Must not be <code>null</code>.
  210            */
  211           public AbstractHandler(ProjectHelperImpl helperImpl, DocumentHandler parentHandler) {
  212               this.parentHandler = parentHandler;
  213               this.helperImpl = helperImpl;
  214   
  215               // Start handling SAX events
  216               helperImpl.parser.setDocumentHandler(this);
  217           }
  218   
  219           /**
  220            * Handles the start of an element. This base implementation just
  221            * throws an exception.
  222            *
  223            * @param tag The name of the element being started.
  224            *            Will not be <code>null</code>.
  225            * @param attrs Attributes of the element being started.
  226            *              Will not be <code>null</code>.
  227            *
  228            * @exception SAXParseException if this method is not overridden, or in
  229            *                              case of error in an overridden version
  230            */
  231           public void startElement(String tag, AttributeList attrs) throws SAXParseException {
  232               throw new SAXParseException("Unexpected element \"" + tag + "\"", helperImpl.locator);
  233           }
  234   
  235           /**
  236            * Handles text within an element. This base implementation just
  237            * throws an exception.
  238            *
  239            * @param buf A character array of the text within the element.
  240            *            Will not be <code>null</code>.
  241            * @param start The start element in the array.
  242            * @param count The number of characters to read from the array.
  243            *
  244            * @exception SAXParseException if this method is not overridden, or in
  245            *                              case of error in an overridden version
  246            */
  247           public void characters(char[] buf, int start, int count) throws SAXParseException {
  248               String s = new String(buf, start, count).trim();
  249   
  250               if (s.length() > 0) {
  251                   throw new SAXParseException("Unexpected text \"" + s + "\"", helperImpl.locator);
  252               }
  253           }
  254   
  255           /**
  256            * Handles the end of an element. Any required clean-up is performed
  257            * by the finished() method and then the original handler is restored to
  258            * the parser.
  259            *
  260            * @param name The name of the element which is ending.
  261            *             Will not be <code>null</code>.
  262            *
  263            * @exception SAXException in case of error (not thrown in
  264            *                         this implementation)
  265            */
  266           public void endElement(String name) throws SAXException {
  267               // Let parent resume handling SAX events
  268               helperImpl.parser.setDocumentHandler(parentHandler);
  269           }
  270       }
  271   
  272       /**
  273        * Handler for the root element. Its only child must be the "project" element.
  274        */
  275       static class RootHandler extends HandlerBase {
  276           // CheckStyle:VisibilityModifier OFF - bc
  277           ProjectHelperImpl helperImpl;
  278           // CheckStyle:VisibilityModifier ON
  279   
  280           public RootHandler(ProjectHelperImpl helperImpl) {
  281               this.helperImpl = helperImpl;
  282           }
  283   
  284           /**
  285            * Resolves file: URIs relative to the build file.
  286            *
  287            * @param publicId The public identifier, or <code>null</code>
  288            *                 if none is available. Ignored in this
  289            *                 implementation.
  290            * @param systemId The system identifier provided in the XML
  291            *                 document. Will not be <code>null</code>.
  292            */
  293           public InputSource resolveEntity(String publicId,
  294                                            String systemId) {
  295   
  296               helperImpl.project.log("resolving systemId: " + systemId, Project.MSG_VERBOSE);
  297   
  298               if (systemId.startsWith("file:")) {
  299                   String path = FILE_UTILS.fromURI(systemId);
  300   
  301                   File file = new File(path);
  302                   if (!file.isAbsolute()) {
  303                       file = FILE_UTILS.resolveFile(helperImpl.buildFileParent, path);
  304                       helperImpl.project.log(
  305                               "Warning: '" + systemId + "' in " + helperImpl.buildFile
  306                               + " should be expressed simply as '" + path.replace('\\', '/')
  307                               + "' for compliance with other XML tools",
  308                               Project.MSG_WARN);
  309                   }
  310                   try {
  311                       InputSource inputSource = new InputSource(new FileInputStream(file));
  312                       inputSource.setSystemId(FILE_UTILS.toURI(file.getAbsolutePath()));
  313                       return inputSource;
  314                   } catch (FileNotFoundException fne) {
  315                       helperImpl.project.log(file.getAbsolutePath() + " could not be found",
  316                                   Project.MSG_WARN);
  317                   }
  318               }
  319               // use default if not file or file not found
  320               return null;
  321           }
  322   
  323           /**
  324            * Handles the start of a project element. A project handler is created
  325            * and initialised with the element name and attributes.
  326            *
  327            * @param tag The name of the element being started.
  328            *            Will not be <code>null</code>.
  329            * @param attrs Attributes of the element being started.
  330            *              Will not be <code>null</code>.
  331            *
  332            * @exception SAXParseException if the tag given is not
  333            *                              <code>"project"</code>
  334            */
  335           public void startElement(String tag, AttributeList attrs) throws SAXParseException {
  336               if (tag.equals("project")) {
  337                   new ProjectHandler(helperImpl, this).init(tag, attrs);
  338               } else {
  339                   throw new SAXParseException("Config file is not of expected "
  340                       + "XML type", helperImpl.locator);
  341               }
  342           }
  343   
  344           /**
  345            * Sets the locator in the project helper for future reference.
  346            *
  347            * @param locator The locator used by the parser.
  348            *                Will not be <code>null</code>.
  349            */
  350           public void setDocumentLocator(Locator locator) {
  351               helperImpl.locator = locator;
  352           }
  353       }
  354   
  355       /**
  356        * Handler for the top level "project" element.
  357        */
  358       static class ProjectHandler extends AbstractHandler {
  359   
  360           /**
  361            * Constructor which just delegates to the superconstructor.
  362            *
  363            * @param parentHandler The handler which should be restored to the
  364            *                      parser at the end of the element.
  365            *                      Must not be <code>null</code>.
  366            */
  367           public ProjectHandler(ProjectHelperImpl helperImpl, DocumentHandler parentHandler) {
  368               super(helperImpl, parentHandler);
  369           }
  370   
  371           /**
  372            * Initialisation routine called after handler creation
  373            * with the element name and attributes. The attributes which
  374            * this handler can deal with are: <code>"default"</code>,
  375            * <code>"name"</code>, <code>"id"</code> and <code>"basedir"</code>.
  376            *
  377            * @param tag Name of the element which caused this handler
  378            *            to be created. Should not be <code>null</code>.
  379            *            Ignored in this implementation.
  380            * @param attrs Attributes of the element which caused this
  381            *              handler to be created. Must not be <code>null</code>.
  382            *
  383            * @exception SAXParseException if an unexpected attribute is
  384            *            encountered or if the <code>"default"</code> attribute
  385            *            is missing.
  386            */
  387           public void init(String tag, AttributeList attrs) throws SAXParseException {
  388               String def = null;
  389               String name = null;
  390               String id = null;
  391               String baseDir = null;
  392   
  393               for (int i = 0; i < attrs.getLength(); i++) {
  394                   String key = attrs.getName(i);
  395                   String value = attrs.getValue(i);
  396   
  397                   if (key.equals("default")) {
  398                       def = value;
  399                   } else if (key.equals("name")) {
  400                       name = value;
  401                   } else if (key.equals("id")) {
  402                       id = value;
  403                   } else if (key.equals("basedir")) {
  404                       baseDir = value;
  405                   } else {
  406                       throw new SAXParseException("Unexpected attribute \"" + attrs.getName(i) + "\"",
  407                                                   helperImpl.locator);
  408                   }
  409               }
  410   
  411               if (def != null && !def.equals("")) {
  412                   helperImpl.project.setDefaultTarget(def);
  413               } else {
  414                   throw new BuildException("The default attribute is required");
  415               }
  416   
  417               if (name != null) {
  418                   helperImpl.project.setName(name);
  419                   helperImpl.project.addReference(name, helperImpl.project);
  420               }
  421   
  422               if (id != null) {
  423                   helperImpl.project.addReference(id, helperImpl.project);
  424               }
  425   
  426               if (helperImpl.project.getProperty("basedir") != null) {
  427                   helperImpl.project.setBasedir(helperImpl.project.getProperty("basedir"));
  428               } else {
  429                   if (baseDir == null) {
  430                       helperImpl.project.setBasedir(helperImpl.buildFileParent.getAbsolutePath());
  431                   } else {
  432                       // check whether the user has specified an absolute path
  433                       if ((new File(baseDir)).isAbsolute()) {
  434                           helperImpl.project.setBasedir(baseDir);
  435                       } else {
  436                           File resolvedBaseDir = FILE_UTILS.resolveFile(
  437                                   helperImpl.buildFileParent, baseDir);
  438                           helperImpl.project.setBaseDir(resolvedBaseDir);
  439                       }
  440                   }
  441               }
  442   
  443               helperImpl.project.addTarget("", helperImpl.implicitTarget);
  444           }
  445   
  446           /**
  447            * Handles the start of a top-level element within the project. An
  448            * appropriate handler is created and initialised with the details
  449            * of the element.
  450            *
  451            * @param name The name of the element being started.
  452            *            Will not be <code>null</code>.
  453            * @param attrs Attributes of the element being started.
  454            *              Will not be <code>null</code>.
  455            *
  456            * @exception SAXParseException if the tag given is not
  457            *            <code>"taskdef"</code>, <code>"typedef"</code>,
  458            *            <code>"property"</code>, <code>"target"</code>
  459            *            or a data type definition
  460            */
  461           public void startElement(String name, AttributeList attrs) throws SAXParseException {
  462               if (name.equals("target")) {
  463                   handleTarget(name, attrs);
  464               } else {
  465                   handleElement(helperImpl, this, helperImpl.implicitTarget,
  466                                 name, attrs);
  467               }
  468           }
  469   
  470           /**
  471            * Handles a target definition element by creating a target handler
  472            * and initialising is with the details of the element.
  473            *
  474            * @param tag The name of the element to be handled.
  475            *            Will not be <code>null</code>.
  476            * @param attrs Attributes of the element to be handled.
  477            *              Will not be <code>null</code>.
  478            *
  479            * @exception SAXParseException if an error occurs initialising
  480            *                              the handler
  481            */
  482           private void handleTarget(String tag, AttributeList attrs) throws SAXParseException {
  483               new TargetHandler(helperImpl, this).init(tag, attrs);
  484           }
  485   
  486       }
  487   
  488       /**
  489        * Handler for "target" elements.
  490        */
  491       static class TargetHandler extends AbstractHandler {
  492           private Target target;
  493   
  494           /**
  495            * Constructor which just delegates to the superconstructor.
  496            *
  497            * @param parentHandler The handler which should be restored to the
  498            *                      parser at the end of the element.
  499            *                      Must not be <code>null</code>.
  500            */
  501           public TargetHandler(ProjectHelperImpl helperImpl, DocumentHandler parentHandler) {
  502               super(helperImpl, parentHandler);
  503           }
  504   
  505           /**
  506            * Initialisation routine called after handler creation
  507            * with the element name and attributes. The attributes which
  508            * this handler can deal with are: <code>"name"</code>,
  509            * <code>"depends"</code>, <code>"if"</code>,
  510            * <code>"unless"</code>, <code>"id"</code> and
  511            * <code>"description"</code>.
  512            *
  513            * @param tag Name of the element which caused this handler
  514            *            to be created. Should not be <code>null</code>.
  515            *            Ignored in this implementation.
  516            * @param attrs Attributes of the element which caused this
  517            *              handler to be created. Must not be <code>null</code>.
  518            *
  519            * @exception SAXParseException if an unexpected attribute is encountered
  520            *            or if the <code>"name"</code> attribute is missing.
  521            */
  522           public void init(String tag, AttributeList attrs) throws SAXParseException {
  523               String name = null;
  524               String depends = "";
  525               String ifCond = null;
  526               String unlessCond = null;
  527               String id = null;
  528               String description = null;
  529   
  530               for (int i = 0; i < attrs.getLength(); i++) {
  531                   String key = attrs.getName(i);
  532                   String value = attrs.getValue(i);
  533   
  534                   if (key.equals("name")) {
  535                       name = value;
  536                       if (name.equals("")) {
  537                           throw new BuildException("name attribute must not"
  538                                                    + " be empty",
  539                                                    new Location(helperImpl.locator));
  540                       }
  541                   } else if (key.equals("depends")) {
  542                       depends = value;
  543                   } else if (key.equals("if")) {
  544                       ifCond = value;
  545                   } else if (key.equals("unless")) {
  546                       unlessCond = value;
  547                   } else if (key.equals("id")) {
  548                       id = value;
  549                   } else if (key.equals("description")) {
  550                       description = value;
  551                   } else {
  552                       throw new SAXParseException("Unexpected attribute \""
  553                           + key + "\"", helperImpl.locator);
  554                   }
  555               }
  556   
  557               if (name == null) {
  558                   throw new SAXParseException("target element appears without a name attribute",
  559                                               helperImpl.locator);
  560               }
  561   
  562               target = new Target();
  563   
  564               // implicit target must be first on dependency list
  565               target.addDependency("");
  566   
  567               target.setName(name);
  568               target.setIf(ifCond);
  569               target.setUnless(unlessCond);
  570               target.setDescription(description);
  571               helperImpl.project.addTarget(name, target);
  572   
  573               if (id != null && !id.equals("")) {
  574                   helperImpl.project.addReference(id, target);
  575               }
  576   
  577               // take care of dependencies
  578   
  579               if (depends.length() > 0) {
  580                   target.setDepends(depends);
  581               }
  582           }
  583   
  584           /**
  585            * Handles the start of an element within a target.
  586            *
  587            * @param name The name of the element being started.
  588            *            Will not be <code>null</code>.
  589            * @param attrs Attributes of the element being started.
  590            *              Will not be <code>null</code>.
  591            *
  592            * @exception SAXParseException if an error occurs when initialising
  593            *                              the appropriate child handler
  594            */
  595           public void startElement(String name, AttributeList attrs) throws SAXParseException {
  596               handleElement(helperImpl, this, target, name, attrs);
  597           }
  598       }
  599   
  600       /**
  601        * Start a new DataTypeHandler if element is known to be a
  602        * data-type and a TaskHandler otherwise.
  603        *
  604        * <p>Factored out of TargetHandler.</p>
  605        *
  606        * @since Ant 1.6
  607        */
  608       private static void handleElement(ProjectHelperImpl helperImpl,
  609                                         DocumentHandler parent,
  610                                         Target target, String elementName,
  611                                         AttributeList attrs)
  612           throws SAXParseException {
  613           if (elementName.equals("description")) {
  614               new DescriptionHandler(helperImpl, parent);
  615           } else if (helperImpl.project.getDataTypeDefinitions()
  616                      .get(elementName) != null) {
  617               new DataTypeHandler(helperImpl, parent, target)
  618                   .init(elementName, attrs);
  619           } else {
  620               new TaskHandler(helperImpl, parent, target, null, target)
  621                   .init(elementName, attrs);
  622           }
  623       }
  624   
  625       /**
  626        * Handler for "description" elements.
  627        */
  628       static class DescriptionHandler extends AbstractHandler {
  629   
  630           /**
  631            * Constructor which just delegates to the superconstructor.
  632            *
  633            * @param parentHandler The handler which should be restored to the
  634            *                      parser at the end of the element.
  635            *                      Must not be <code>null</code>.
  636            */
  637           public DescriptionHandler(ProjectHelperImpl helperImpl,
  638                                     DocumentHandler parentHandler) {
  639               super(helperImpl, parentHandler);
  640           }
  641   
  642           /**
  643            * Adds the text as description to the project.
  644            *
  645            * @param buf A character array of the text within the element.
  646            *            Will not be <code>null</code>.
  647            * @param start The start element in the array.
  648            * @param count The number of characters to read from the array.
  649            */
  650           public void characters(char[] buf, int start, int count) {
  651               String text = new String(buf, start, count);
  652               String currentDescription = helperImpl.project.getDescription();
  653               if (currentDescription == null) {
  654                   helperImpl.project.setDescription(text);
  655               } else {
  656                   helperImpl.project.setDescription(currentDescription + text);
  657               }
  658           }
  659   
  660       }
  661   
  662       /**
  663        * Handler for all task elements.
  664        */
  665       static class TaskHandler extends AbstractHandler {
  666           /** Containing target, if any. */
  667           private Target target;
  668           /**
  669            * Container for the task, if any. If target is
  670            * non-<code>null</code>, this must be too.
  671            */
  672           private TaskContainer container;
  673           /**
  674            * Task created by this handler.
  675            */
  676           private Task task;
  677           /**
  678            * Wrapper for the parent element, if any. The wrapper for this
  679            * element will be added to this wrapper as a child.
  680            */
  681           private RuntimeConfigurable parentWrapper;
  682           /**
  683            * Wrapper for this element which takes care of actually configuring
  684            * the element, if this element is contained within a target.
  685            * Otherwise the configuration is performed with the configure method.
  686            * @see ProjectHelper#configure(Object,AttributeList,Project)
  687            */
  688           private RuntimeConfigurable wrapper = null;
  689   
  690           /**
  691            * Constructor.
  692            *
  693            * @param parentHandler The handler which should be restored to the
  694            *                      parser at the end of the element.
  695            *                      Must not be <code>null</code>.
  696            *
  697            * @param container     Container for the element.
  698            *                      Must not be <code>null</code>.
  699            *
  700            * @param parentWrapper Wrapper for the parent element, if any.
  701            *                      May be <code>null</code>.
  702            *
  703            * @param target        Target this element is part of.
  704            *                      Must not be <code>null</code>.
  705            */
  706           public TaskHandler(ProjectHelperImpl helperImpl, DocumentHandler parentHandler,
  707                              TaskContainer container,
  708                              RuntimeConfigurable parentWrapper, Target target) {
  709               super(helperImpl, parentHandler);
  710               this.container = container;
  711               this.parentWrapper = parentWrapper;
  712               this.target = target;
  713           }
  714   
  715           /**
  716            * Initialisation routine called after handler creation
  717            * with the element name and attributes. This configures
  718            * the element with its attributes and sets it up with
  719            * its parent container (if any). Nested elements are then
  720            * added later as the parser encounters them.
  721            *
  722            * @param tag Name of the element which caused this handler
  723            *            to be created. Must not be <code>null</code>.
  724            *
  725            * @param attrs Attributes of the element which caused this
  726            *              handler to be created. Must not be <code>null</code>.
  727            *
  728            * @exception SAXParseException in case of error (not thrown in
  729            *                              this implementation)
  730            */
  731           public void init(String tag, AttributeList attrs) throws SAXParseException {
  732               try {
  733                   task = helperImpl.project.createTask(tag);
  734               } catch (BuildException e) {
  735                   // swallow here, will be thrown again in
  736                   // UnknownElement.maybeConfigure if the problem persists.
  737               }
  738   
  739               if (task == null) {
  740                   task = new UnknownElement(tag);
  741                   task.setProject(helperImpl.project);
  742                   //XXX task.setTaskType(tag);
  743                   task.setTaskName(tag);
  744               }
  745   
  746               task.setLocation(new Location(helperImpl.locator));
  747               helperImpl.configureId(task, attrs);
  748   
  749               task.setOwningTarget(target);
  750               container.addTask(task);
  751               task.init();
  752               wrapper = task.getRuntimeConfigurableWrapper();
  753               wrapper.setAttributes(attrs);
  754               if (parentWrapper != null) {
  755                   parentWrapper.addChild(wrapper);
  756               }
  757           }
  758   
  759           /**
  760            * Adds text to the task, using the wrapper.
  761            *
  762            * @param buf A character array of the text within the element.
  763            *            Will not be <code>null</code>.
  764            * @param start The start element in the array.
  765            * @param count The number of characters to read from the array.
  766            */
  767           public void characters(char[] buf, int start, int count) {
  768               wrapper.addText(buf, start, count);
  769           }
  770   
  771           /**
  772            * Handles the start of an element within a target. Task containers
  773            * will always use another task handler, and all other tasks
  774            * will always use a nested element handler.
  775            *
  776            * @param name The name of the element being started.
  777            *            Will not be <code>null</code>.
  778            * @param attrs Attributes of the element being started.
  779            *              Will not be <code>null</code>.
  780            *
  781            * @exception SAXParseException if an error occurs when initialising
  782            *                              the appropriate child handler
  783            */
  784           public void startElement(String name, AttributeList attrs) throws SAXParseException {
  785               if (task instanceof TaskContainer) {
  786                   // task can contain other tasks - no other nested elements possible
  787                   new TaskHandler(helperImpl, this, (TaskContainer) task,
  788                       wrapper, target).init(name, attrs);
  789               } else {
  790                   new NestedElementHandler(helperImpl, this, task,
  791                       wrapper, target).init(name, attrs);
  792               }
  793           }
  794       }
  795   
  796       /**
  797        * Handler for all nested properties.
  798        */
  799       static class NestedElementHandler extends AbstractHandler {
  800           /** Parent object (task/data type/etc). */
  801           private Object parent;
  802           /** The nested element itself. */
  803           private Object child;
  804           /**
  805            * Wrapper for the parent element, if any. The wrapper for this
  806            * element will be added to this wrapper as a child.
  807            */
  808           private RuntimeConfigurable parentWrapper;
  809           /**
  810            * Wrapper for this element which takes care of actually configuring
  811            * the element, if a parent wrapper is provided.
  812            * Otherwise the configuration is performed with the configure method.
  813            * @see ProjectHelper#configure(Object,AttributeList,Project)
  814            */
  815           private RuntimeConfigurable childWrapper = null;
  816           /** Target this element is part of, if any. */
  817           private Target target;
  818   
  819           /**
  820            * Constructor.
  821            *
  822            * @param parentHandler The handler which should be restored to the
  823            *                      parser at the end of the element.
  824            *                      Must not be <code>null</code>.
  825            *
  826            * @param parent        Parent of this element (task/data type/etc).
  827            *                      Must not be <code>null</code>.
  828            *
  829            * @param parentWrapper Wrapper for the parent element, if any.
  830            *                      Must not be <code>null</code>.
  831            *
  832            * @param target        Target this element is part of.
  833            *                      Must not be <code>null</code>.
  834            */
  835           public NestedElementHandler(ProjectHelperImpl helperImpl,
  836                                       DocumentHandler parentHandler,
  837                                       Object parent,
  838                                       RuntimeConfigurable parentWrapper,
  839                                       Target target) {
  840               super(helperImpl, parentHandler);
  841   
  842               if (parent instanceof TypeAdapter) {
  843                   this.parent = ((TypeAdapter) parent).getProxy();
  844               } else {
  845                   this.parent = parent;
  846               }
  847               this.parentWrapper = parentWrapper;
  848               this.target = target;
  849           }
  850   
  851           /**
  852            * Initialisation routine called after handler creation
  853            * with the element name and attributes. This configures
  854            * the element with its attributes and sets it up with
  855            * its parent container (if any). Nested elements are then
  856            * added later as the parser encounters them.
  857            *
  858            * @param propType Name of the element which caused this handler
  859            *            to be created. Must not be <code>null</code>.
  860            *
  861            * @param attrs Attributes of the element which caused this
  862            *              handler to be created. Must not be <code>null</code>.
  863            *
  864            * @exception SAXParseException in case of error, such as a
  865            *            BuildException being thrown during configuration.
  866            */
  867           public void init(String propType, AttributeList attrs) throws SAXParseException {
  868               Class parentClass = parent.getClass();
  869               IntrospectionHelper ih =
  870                   IntrospectionHelper.getHelper(helperImpl.project, parentClass);
  871   
  872               try {
  873                   String elementName = propType.toLowerCase(Locale.US);
  874                   if (parent instanceof UnknownElement) {
  875                       UnknownElement uc = new UnknownElement(elementName);
  876                       uc.setProject(helperImpl.project);
  877                       ((UnknownElement) parent).addChild(uc);
  878                       child = uc;
  879                   } else {
  880                       child = ih.createElement(helperImpl.project, parent, elementName);
  881                   }
  882   
  883                   helperImpl.configureId(child, attrs);
  884   
  885                   childWrapper = new RuntimeConfigurable(child, propType);
  886                   childWrapper.setAttributes(attrs);
  887                   parentWrapper.addChild(childWrapper);
  888               } catch (BuildException exc) {
  889                   throw new SAXParseException(exc.getMessage(), helperImpl.locator, exc);
  890               }
  891           }
  892   
  893           /**
  894            * Adds text to the element, using the wrapper.
  895            *
  896            * @param buf A character array of the text within the element.
  897            *            Will not be <code>null</code>.
  898            * @param start The start element in the array.
  899            * @param count The number of characters to read from the array.
  900            */
  901           public void characters(char[] buf, int start, int count) {
  902               childWrapper.addText(buf, start, count);
  903           }
  904   
  905           /**
  906            * Handles the start of an element within this one. Task containers
  907            * will always use a task handler, and all other elements
  908            * will always use another nested element handler.
  909            *
  910            * @param name The name of the element being started.
  911            *            Will not be <code>null</code>.
  912            * @param attrs Attributes of the element being started.
  913            *              Will not be <code>null</code>.
  914            *
  915            * @exception SAXParseException if an error occurs when initialising
  916            *                              the appropriate child handler
  917            */
  918           public void startElement(String name, AttributeList attrs) throws SAXParseException {
  919               if (child instanceof TaskContainer) {
  920                   // taskcontainer nested element can contain other tasks - no other
  921                   // nested elements possible
  922                   new TaskHandler(helperImpl, this, (TaskContainer) child,
  923                       childWrapper, target).init(name, attrs);
  924               } else {
  925                   new NestedElementHandler(helperImpl, this, child,
  926                       childWrapper, target).init(name, attrs);
  927               }
  928           }
  929       }
  930   
  931       /**
  932        * Handler for all data types directly subordinate to project or target.
  933        */
  934       static class DataTypeHandler extends AbstractHandler {
  935           /** Parent target, if any. */
  936           private Target target;
  937           /** The element being configured. */
  938           private Object element;
  939           /** Wrapper for this element, if it's part of a target. */
  940           private RuntimeConfigurable wrapper = null;
  941   
  942           /**
  943            * Constructor with a target specified.
  944            *
  945            * @param parentHandler The handler which should be restored to the
  946            *                      parser at the end of the element.
  947            *                      Must not be <code>null</code>.
  948            *
  949            * @param target The parent target of this element.
  950            *               Must not be <code>null</code>.
  951            */
  952           public DataTypeHandler(ProjectHelperImpl helperImpl,
  953                                  DocumentHandler parentHandler, Target target) {
  954               super(helperImpl, parentHandler);
  955               this.target = target;
  956           }
  957   
  958           /**
  959            * Initialisation routine called after handler creation
  960            * with the element name and attributes. This configures
  961            * the element with its attributes and sets it up with
  962            * its parent container (if any). Nested elements are then
  963            * added later as the parser encounters them.
  964            *
  965            * @param propType Name of the element which caused this handler
  966            *            to be created. Must not be <code>null</code>.
  967            *
  968            * @param attrs Attributes of the element which caused this
  969            *              handler to be created. Must not be <code>null</code>.
  970            *
  971            * @exception SAXParseException in case of error, such as a
  972            *            BuildException being thrown during configuration.
  973            */
  974           public void init(String propType, AttributeList attrs) throws SAXParseException {
  975               try {
  976                   element = helperImpl.project.createDataType(propType);
  977                   if (element == null) {
  978                       throw new BuildException("Unknown data type " + propType);
  979                   }
  980   
  981                   wrapper = new RuntimeConfigurable(element, propType);
  982                   wrapper.setAttributes(attrs);
  983                   target.addDataType(wrapper);
  984               } catch (BuildException exc) {
  985                   throw new SAXParseException(exc.getMessage(), helperImpl.locator, exc);
  986               }
  987           }
  988   
  989           /**
  990            * Adds text to the using the wrapper.
  991            *
  992            * @param buf A character array of the text within the element.
  993            *            Will not be <code>null</code>.
  994            * @param start The start element in the array.
  995            * @param count The number of characters to read from the array.
  996            *
  997            * @see ProjectHelper#addText(Project,Object,char[],int,int)
  998            */
  999           public void characters(char[] buf, int start, int count) {
 1000               wrapper.addText(buf, start, count);
 1001           }
 1002   
 1003           /**
 1004            * Handles the start of an element within this one.
 1005            * This will always use a nested element handler.
 1006            *
 1007            * @param name The name of the element being started.
 1008            *            Will not be <code>null</code>.
 1009            * @param attrs Attributes of the element being started.
 1010            *              Will not be <code>null</code>.
 1011            *
 1012            * @exception SAXParseException if an error occurs when initialising
 1013            *                              the child handler
 1014            */
 1015           public void startElement(String name, AttributeList attrs) throws SAXParseException {
 1016               new NestedElementHandler(helperImpl, this, element, wrapper, target).init(name, attrs);
 1017           }
 1018       }
 1019   
 1020       /**
 1021        * Scans an attribute list for the <code>id</code> attribute and
 1022        * stores a reference to the target object in the project if an
 1023        * id is found.
 1024        * <p>
 1025        * This method was moved out of the configure method to allow
 1026        * it to be executed at parse time.
 1027        *
 1028        * @see #configure(Object,AttributeList,Project)
 1029        */
 1030       private void configureId(Object target, AttributeList attr) {
 1031           String id = attr.getValue("id");
 1032           if (id != null) {
 1033               project.addReference(id, target);
 1034           }
 1035       }
 1036   }

Save This Page
Home » apache-ant-1.7.1-src » org.apache.tools » ant » helper » [javadoc | source]