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   package org.apache.tools.ant.helper;
   19   
   20   import org.apache.tools.ant.BuildException;
   21   import org.apache.tools.ant.Location;
   22   import org.apache.tools.ant.MagicNames;
   23   import org.apache.tools.ant.Project;
   24   import org.apache.tools.ant.ProjectHelper;
   25   import org.apache.tools.ant.RuntimeConfigurable;
   26   import org.apache.tools.ant.Target;
   27   import org.apache.tools.ant.Task;
   28   import org.apache.tools.ant.UnknownElement;
   29   import org.apache.tools.ant.util.FileUtils;
   30   import org.apache.tools.ant.util.StringUtils;
   31   import org.apache.tools.ant.util.JAXPUtils;
   32   import org.xml.sax.Attributes;
   33   import org.xml.sax.InputSource;
   34   import org.xml.sax.Locator;
   35   import org.xml.sax.SAXException;
   36   import org.xml.sax.SAXParseException;
   37   import org.xml.sax.XMLReader;
   38   import org.xml.sax.helpers.DefaultHandler;
   39   
   40   import java.io.File;
   41   import java.io.FileInputStream;
   42   import java.io.FileNotFoundException;
   43   import java.io.IOException;
   44   import java.io.InputStream;
   45   import java.io.UnsupportedEncodingException;
   46   import java.net.URL;
   47   import java.util.HashMap;
   48   import java.util.Hashtable;
   49   import java.util.Map;
   50   import java.util.Stack;
   51   
   52   /**
   53    * Sax2 based project reader
   54    *
   55    */
   56   public class ProjectHelper2 extends ProjectHelper {
   57       /** Reference holding the (ordered) target Vector */
   58       public static final String REFID_TARGETS = "ant.targets";
   59   
   60       /* Stateless */
   61   
   62       // singletons - since all state is in the context
   63       private static AntHandler elementHandler = new ElementHandler();
   64       private static AntHandler targetHandler = new TargetHandler();
   65       private static AntHandler mainHandler = new MainHandler();
   66       private static AntHandler projectHandler = new ProjectHandler();
   67   
   68       /** Specific to ProjectHelper2 so not a true Ant "magic name:" */
   69       private static final String REFID_CONTEXT = "ant.parsing.context";
   70   
   71       /**
   72        * helper for path -> URI and URI -> path conversions.
   73        */
   74       private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
   75   
   76       /**
   77        * Parse an unknown element from a url
   78        *
   79        * @param project the current project
   80        * @param source  the url containing the task
   81        * @return a configured task
   82        * @exception BuildException if an error occurs
   83        */
   84       public UnknownElement parseUnknownElement(Project project, URL source) throws BuildException {
   85           Target dummyTarget = new Target();
   86           dummyTarget.setProject(project);
   87   
   88           AntXMLContext context = new AntXMLContext(project);
   89           context.addTarget(dummyTarget);
   90           context.setImplicitTarget(dummyTarget);
   91   
   92           parse(context.getProject(), source, new RootHandler(context, elementHandler));
   93           Task[] tasks = dummyTarget.getTasks();
   94           if (tasks.length != 1) {
   95               throw new BuildException("No tasks defined");
   96           }
   97           return (UnknownElement) tasks[0];
   98       }
   99   
  100       /**
  101        * Parse a source xml input.
  102        *
  103        * @param project the current project
  104        * @param source  the xml source
  105        * @exception BuildException if an error occurs
  106        */
  107       public void parse(Project project, Object source) throws BuildException {
  108           getImportStack().addElement(source);
  109           AntXMLContext context = null;
  110           context = (AntXMLContext) project.getReference(REFID_CONTEXT);
  111           if (context == null) {
  112               context = new AntXMLContext(project);
  113               project.addReference(REFID_CONTEXT, context);
  114               project.addReference(REFID_TARGETS, context.getTargets());
  115           }
  116   
  117           if (getImportStack().size() > 1) {
  118               // we are in an imported file.
  119               context.setIgnoreProjectTag(true);
  120               Target currentTarget = context.getCurrentTarget();
  121               Target currentImplicit = context.getImplicitTarget();
  122               Map    currentTargets = context.getCurrentTargets();
  123               try {
  124                   Target newCurrent = new Target();
  125                   newCurrent.setProject(project);
  126                   newCurrent.setName("");
  127                   context.setCurrentTarget(newCurrent);
  128                   context.setCurrentTargets(new HashMap());
  129                   context.setImplicitTarget(newCurrent);
  130                   parse(project, source, new RootHandler(context, mainHandler));
  131                   newCurrent.execute();
  132               } finally {
  133                   context.setCurrentTarget(currentTarget);
  134                   context.setImplicitTarget(currentImplicit);
  135                   context.setCurrentTargets(currentTargets);
  136               }
  137           } else {
  138               // top level file
  139               context.setCurrentTargets(new HashMap());
  140               parse(project, source, new RootHandler(context, mainHandler));
  141               // Execute the top-level target
  142               context.getImplicitTarget().execute();
  143           }
  144       }
  145   
  146       /**
  147        * Parses the project file, configuring the project as it goes.
  148        *
  149        * @param project the current project
  150        * @param source  the xml source
  151        * @param handler the root handler to use (contains the current context)
  152        * @exception BuildException if the configuration is invalid or cannot
  153        *                           be read
  154        */
  155       public void parse(Project project, Object source, RootHandler handler) throws BuildException {
  156   
  157           AntXMLContext context = handler.context;
  158   
  159           File buildFile = null;
  160           URL  url = null;
  161           String buildFileName = null;
  162   
  163           if (source instanceof File) {
  164               buildFile = (File) source;
  165               buildFile = FILE_UTILS.normalize(buildFile.getAbsolutePath());
  166               context.setBuildFile(buildFile);
  167               buildFileName = buildFile.toString();
  168   //         } else if (source instanceof InputStream ) {
  169           } else if (source instanceof URL) {
  170               url = (URL) source;
  171               buildFileName = url.toString();
  172   //         } else if (source instanceof InputSource ) {
  173           } else {
  174               throw new BuildException("Source " + source.getClass().getName()
  175                                        + " not supported by this plugin");
  176           }
  177   
  178           InputStream inputStream = null;
  179           InputSource inputSource = null;
  180   
  181           try {
  182               /**
  183                * SAX 2 style parser used to parse the given file.
  184                */
  185               XMLReader parser = JAXPUtils.getNamespaceXMLReader();
  186   
  187               String uri = null;
  188               if (buildFile != null) {
  189                   uri = FILE_UTILS.toURI(buildFile.getAbsolutePath());
  190                   inputStream = new FileInputStream(buildFile);
  191               } else {
  192                   inputStream = url.openStream();
  193                   uri = url.toString(); // ?? OK ??
  194               }
  195   
  196               inputSource = new InputSource(inputStream);
  197               if (uri != null) {
  198                   inputSource.setSystemId(uri);
  199               }
  200               project.log("parsing buildfile " + buildFileName
  201                           + " with URI = " + uri, Project.MSG_VERBOSE);
  202   
  203               DefaultHandler hb = handler;
  204   
  205               parser.setContentHandler(hb);
  206               parser.setEntityResolver(hb);
  207               parser.setErrorHandler(hb);
  208               parser.setDTDHandler(hb);
  209               parser.parse(inputSource);
  210           } catch (SAXParseException exc) {
  211               Location location = new Location(exc.getSystemId(),
  212                   exc.getLineNumber(), exc.getColumnNumber());
  213   
  214               Throwable t = exc.getException();
  215               if (t instanceof BuildException) {
  216                   BuildException be = (BuildException) t;
  217                   if (be.getLocation() == Location.UNKNOWN_LOCATION) {
  218                       be.setLocation(location);
  219                   }
  220                   throw be;
  221               }
  222               throw new BuildException(exc.getMessage(), t == null ? exc : t, location);
  223           } catch (SAXException exc) {
  224               Throwable t = exc.getException();
  225               if (t instanceof BuildException) {
  226                   throw (BuildException) t;
  227               }
  228               throw new BuildException(exc.getMessage(), t == null ? exc : t);
  229           } catch (FileNotFoundException exc) {
  230               throw new BuildException(exc);
  231           } catch (UnsupportedEncodingException exc) {
  232                 throw new BuildException("Encoding of project file "
  233                                          + buildFileName + " is invalid.", exc);
  234           } catch (IOException exc) {
  235               throw new BuildException("Error reading project file "
  236                                        + buildFileName + ": " + exc.getMessage(), exc);
  237           } finally {
  238               FileUtils.close(inputStream);
  239           }
  240       }
  241   
  242       /**
  243        * Returns main handler
  244        * @return main handler
  245        */
  246       protected static AntHandler getMainHandler() {
  247           return mainHandler;
  248       }
  249   
  250       /**
  251        * Sets main handler
  252        * @param handler  new main handler
  253        */
  254       protected static void setMainHandler(AntHandler handler) {
  255           mainHandler = handler;
  256       }
  257   
  258       /**
  259        * Returns project handler
  260        * @return project handler
  261        */
  262       protected static AntHandler getProjectHandler() {
  263           return projectHandler;
  264       }
  265   
  266       /**
  267        * Sets project handler
  268        * @param handler  new project handler
  269        */
  270       protected static void setProjectHandler(AntHandler handler) {
  271           projectHandler = handler;
  272       }
  273   
  274       /**
  275        * Returns target handler
  276        * @return target handler
  277        */
  278       protected static AntHandler getTargetHandler() {
  279           return targetHandler;
  280       }
  281   
  282       /**
  283        * Sets target handler
  284        * @param handler  new target handler
  285        */
  286       protected static void setTargetHandler(AntHandler handler) {
  287           targetHandler = handler;
  288       }
  289   
  290       /**
  291        * Returns element handler
  292        * @return element handler
  293        */
  294       protected static AntHandler getElementHandler() {
  295           return elementHandler;
  296       }
  297   
  298       /**
  299        * Sets element handler
  300        * @param handler  new element handler
  301        */
  302       protected static void setElementHandler(AntHandler handler) {
  303           elementHandler = handler;
  304       }
  305   
  306       /**
  307        * The common superclass for all SAX event handlers used to parse
  308        * the configuration file.
  309        *
  310        * The context will hold all state information. At each time
  311        * there is one active handler for the current element. It can
  312        * use onStartChild() to set an alternate handler for the child.
  313        */
  314       public static class AntHandler  {
  315           /**
  316            * Handles the start of an element. This base implementation does
  317            * nothing.
  318            *
  319            * @param uri the namespace URI for the tag
  320            * @param tag The name of the element being started.
  321            *            Will not be <code>null</code>.
  322            * @param qname The qualified name of the element.
  323            * @param attrs Attributes of the element being started.
  324            *              Will not be <code>null</code>.
  325            * @param context The context that this element is in.
  326            *
  327            * @exception SAXParseException if this method is not overridden, or in
  328            *                              case of error in an overridden version
  329            */
  330           public void onStartElement(String uri, String tag, String qname, Attributes attrs,
  331                                      AntXMLContext context) throws SAXParseException {
  332           }
  333   
  334           /**
  335            * Handles the start of an element. This base implementation just
  336            * throws an exception - you must override this method if you expect
  337            * child elements.
  338            *
  339            * @param uri The namespace uri for this element.
  340            * @param tag The name of the element being started.
  341            *            Will not be <code>null</code>.
  342            * @param qname The qualified name for this element.
  343            * @param attrs Attributes of the element being started.
  344            *              Will not be <code>null</code>.
  345            * @param context The current context.
  346            * @return a handler (in the derived classes)
  347            *
  348            * @exception SAXParseException if this method is not overridden, or in
  349            *                              case of error in an overridden version
  350            */
  351           public AntHandler onStartChild(String uri, String tag, String qname, Attributes attrs,
  352                                          AntXMLContext context) throws SAXParseException {
  353               throw new SAXParseException("Unexpected element \"" + qname
  354                       + " \"", context.getLocator());
  355           }
  356   
  357           /**
  358            * Handle the end of a element.
  359            *
  360            * @param uri the namespace uri of the element
  361            * @param tag the tag of the element
  362            * @param qname the qualified name of the element
  363            * @param context the current context
  364            * @exception SAXParseException if an error occurs
  365            */
  366           public void onEndChild(String uri, String tag, String qname,
  367                                        AntXMLContext context) throws SAXParseException {
  368           }
  369   
  370           /**
  371            * This method is called when this element and all elements nested into it have been
  372            * handled. I.e., this happens at the &lt;/end_tag_of_the_element&gt;.
  373            * @param uri the namespace uri for this element
  374            * @param tag the element name
  375            * @param context the current context
  376            */
  377           public void onEndElement(String uri, String tag, AntXMLContext context) {
  378           }
  379   
  380           /**
  381            * Handles text within an element. This base implementation just
  382            * throws an exception, you must override it if you expect content.
  383            *
  384            * @param buf A character array of the text within the element.
  385            *            Will not be <code>null</code>.
  386            * @param start The start element in the array.
  387            * @param count The number of characters to read from the array.
  388            * @param context The current context.
  389            *
  390            * @exception SAXParseException if this method is not overridden, or in
  391            *                              case of error in an overridden version
  392            */
  393           public void characters(char[] buf, int start, int count, AntXMLContext context)
  394               throws SAXParseException {
  395               String s = new String(buf, start, count).trim();
  396   
  397               if (s.length() > 0) {
  398                   throw new SAXParseException("Unexpected text \"" + s + "\"", context.getLocator());
  399               }
  400           }
  401   
  402           /**
  403            * Will be called every time a namespace is reached.
  404            * It'll verify if the ns was processed, and if not load the task definitions.
  405            * @param uri The namespace uri.
  406            */
  407           protected void checkNamespace(String uri) {
  408           }
  409       }
  410   
  411       /**
  412        * Handler for ant processing. Uses a stack of AntHandlers to
  413        * implement each element ( the original parser used a recursive behavior,
  414        * with the implicit execution stack )
  415        */
  416       public static class RootHandler extends DefaultHandler {
  417           private Stack antHandlers = new Stack();
  418           private AntHandler currentHandler = null;
  419           private AntXMLContext context;
  420   
  421           /**
  422            * Creates a new RootHandler instance.
  423            *
  424            * @param context The context for the handler.
  425            * @param rootHandler The handler for the root element.
  426            */
  427           public RootHandler(AntXMLContext context, AntHandler rootHandler) {
  428               currentHandler = rootHandler;
  429               antHandlers.push(currentHandler);
  430               this.context = context;
  431           }
  432   
  433           /**
  434            * Returns the current ant handler object.
  435            * @return the current ant handler.
  436            */
  437           public AntHandler getCurrentAntHandler() {
  438               return currentHandler;
  439           }
  440   
  441           /**
  442            * Resolves file: URIs relative to the build file.
  443            *
  444            * @param publicId The public identifier, or <code>null</code>
  445            *                 if none is available. Ignored in this
  446            *                 implementation.
  447            * @param systemId The system identifier provided in the XML
  448            *                 document. Will not be <code>null</code>.
  449            * @return an inputsource for this identifier
  450            */
  451           public InputSource resolveEntity(String publicId, String systemId) {
  452   
  453               context.getProject().log("resolving systemId: " + systemId, Project.MSG_VERBOSE);
  454   
  455               if (systemId.startsWith("file:")) {
  456                   String path = FILE_UTILS.fromURI(systemId);
  457   
  458                   File file = new File(path);
  459                   if (!file.isAbsolute()) {
  460                       file = FILE_UTILS.resolveFile(context.getBuildFileParent(), path);
  461                       context.getProject().log(
  462                               "Warning: '" + systemId + "' in " + context.getBuildFile()
  463                               + " should be expressed simply as '" + path.replace('\\', '/')
  464                               + "' for compliance with other XML tools", Project.MSG_WARN);
  465                   }
  466                   context.getProject().log("file=" + file, Project.MSG_DEBUG);
  467                   try {
  468                       InputSource inputSource = new InputSource(new FileInputStream(file));
  469                       inputSource.setSystemId(FILE_UTILS.toURI(file.getAbsolutePath()));
  470                       return inputSource;
  471                   } catch (FileNotFoundException fne) {
  472                       context.getProject().log(file.getAbsolutePath()
  473                               + " could not be found", Project.MSG_WARN);
  474                   }
  475   
  476               }
  477               // use default if not file or file not found
  478               context.getProject().log("could not resolve systemId", Project.MSG_DEBUG);
  479               return null;
  480           }
  481   
  482           /**
  483            * Handles the start of a project element. A project handler is created
  484            * and initialised with the element name and attributes.
  485            *
  486            * @param uri The namespace uri for this element.
  487            * @param tag The name of the element being started.
  488            *            Will not be <code>null</code>.
  489            * @param qname The qualified name for this element.
  490            * @param attrs Attributes of the element being started.
  491            *              Will not be <code>null</code>.
  492            *
  493            * @exception org.xml.sax.SAXParseException if the tag given is not
  494            *                              <code>"project"</code>
  495            */
  496           public void startElement(String uri, String tag, String qname, Attributes attrs)
  497               throws SAXParseException {
  498               AntHandler next = currentHandler.onStartChild(uri, tag, qname, attrs, context);
  499               antHandlers.push(currentHandler);
  500               currentHandler = next;
  501               currentHandler.onStartElement(uri, tag, qname, attrs, context);
  502           }
  503   
  504           /**
  505            * Sets the locator in the project helper for future reference.
  506            *
  507            * @param locator The locator used by the parser.
  508            *                Will not be <code>null</code>.
  509            */
  510           public void setDocumentLocator(Locator locator) {
  511               context.setLocator(locator);
  512           }
  513   
  514           /**
  515            * Handles the end of an element. Any required clean-up is performed
  516            * by the onEndElement() method and then the original handler is restored to the parser.
  517            *
  518            * @param uri  The namespace URI for this element.
  519            * @param name The name of the element which is ending.
  520            *             Will not be <code>null</code>.
  521            * @param qName The qualified name for this element.
  522            *
  523            * @exception SAXException in case of error (not thrown in this implementation)
  524            */
  525           public void endElement(String uri, String name, String qName) throws SAXException {
  526               currentHandler.onEndElement(uri, name, context);
  527               AntHandler prev = (AntHandler) antHandlers.pop();
  528               currentHandler = prev;
  529               if (currentHandler != null) {
  530                   currentHandler.onEndChild(uri, name, qName, context);
  531               }
  532           }
  533   
  534           /**
  535            * Handle text within an element, calls currentHandler.characters.
  536            *
  537            * @param buf  A character array of the test.
  538            * @param start The start offset in the array.
  539            * @param count The number of characters to read.
  540            * @exception SAXParseException if an error occurs
  541            */
  542           public void characters(char[] buf, int start, int count) throws SAXParseException {
  543               currentHandler.characters(buf, start, count, context);
  544           }
  545   
  546           /**
  547            * Start a namespace prefix to uri mapping
  548            *
  549            * @param prefix the namespace prefix
  550            * @param uri the namespace uri
  551            */
  552           public void startPrefixMapping(String prefix, String uri) {
  553               context.startPrefixMapping(prefix, uri);
  554           }
  555   
  556           /**
  557            * End a namepace prefix to uri mapping
  558            *
  559            * @param prefix the prefix that is not mapped anymore
  560            */
  561           public void endPrefixMapping(String prefix) {
  562               context.endPrefixMapping(prefix);
  563           }
  564       }
  565   
  566       /**
  567        * The main handler - it handles the &lt;project&gt; tag.
  568        *
  569        * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler
  570        */
  571       public static class MainHandler extends AntHandler {
  572   
  573           /**
  574            * Handle the project tag
  575            *
  576            * @param uri The namespace uri.
  577            * @param name The element tag.
  578            * @param qname The element qualified name.
  579            * @param attrs The attributes of the element.
  580            * @param context The current context.
  581            * @return The project handler that handles subelements of project
  582            * @exception SAXParseException if the qualified name is not "project".
  583            */
  584           public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs,
  585                                          AntXMLContext context) throws SAXParseException {
  586               if (name.equals("project")
  587                   && (uri.equals("") || uri.equals(ANT_CORE_URI))) {
  588                   return ProjectHelper2.projectHandler;
  589               }
  590   //            if (context.importlevel > 0) {
  591   //                // we are in an imported file. Allow top-level <target>.
  592   //                if (qname.equals( "target" ) )
  593   //                    return ProjectHelper2.targetHandler;
  594   //            }
  595               if (name.equals(qname)) {
  596                   throw new SAXParseException("Unexpected element \"{" + uri
  597                       + "}" + name + "\" {" + ANT_CORE_URI + "}" + name, context.getLocator());
  598               }
  599               throw new SAXParseException("Unexpected element \"" + qname
  600                       + "\" " + name, context.getLocator());
  601           }
  602       }
  603   
  604       /**
  605        * Handler for the top level "project" element.
  606        */
  607       public static class ProjectHandler extends AntHandler {
  608   
  609           /**
  610            * Initialisation routine called after handler creation
  611            * with the element name and attributes. The attributes which
  612            * this handler can deal with are: <code>"default"</code>,
  613            * <code>"name"</code>, <code>"id"</code> and <code>"basedir"</code>.
  614            *
  615            * @param uri The namespace URI for this element.
  616            * @param tag Name of the element which caused this handler
  617            *            to be created. Should not be <code>null</code>.
  618            *            Ignored in this implementation.
  619            * @param qname The qualified name for this element.
  620            * @param attrs Attributes of the element which caused this
  621            *              handler to be created. Must not be <code>null</code>.
  622            * @param context The current context.
  623            *
  624            * @exception SAXParseException if an unexpected attribute is
  625            *            encountered or if the <code>"default"</code> attribute
  626            *            is missing.
  627            */
  628           public void onStartElement(String uri, String tag, String qname, Attributes attrs,
  629                                      AntXMLContext context) throws SAXParseException {
  630               String baseDir = null;
  631               boolean nameAttributeSet = false;
  632   
  633               Project project = context.getProject();
  634               // Set the location of the implicit target associated with the project tag
  635               context.getImplicitTarget().setLocation(new Location(context.getLocator()));
  636   
  637               /** XXX I really don't like this - the XML processor is still
  638                * too 'involved' in the processing. A better solution (IMO)
  639                * would be to create UE for Project and Target too, and
  640                * then process the tree and have Project/Target deal with
  641                * its attributes ( similar with Description ).
  642                *
  643                * If we eventually switch to ( or add support for ) DOM,
  644                * things will work smoothly - UE can be avoided almost completely
  645                * ( it could still be created on demand, for backward compatibility )
  646                */
  647   
  648               for (int i = 0; i < attrs.getLength(); i++) {
  649                   String attrUri = attrs.getURI(i);
  650                   if (attrUri != null && !attrUri.equals("") && !attrUri.equals(uri)) {
  651                       continue; // Ignore attributes from unknown uris
  652                   }
  653                   String key = attrs.getLocalName(i);
  654                   String value = attrs.getValue(i);
  655   
  656                   if (key.equals("default")) {
  657                       if (value != null && !value.equals("")) {
  658                           if (!context.isIgnoringProjectTag()) {
  659                               project.setDefault(value);
  660                           }
  661                       }
  662                   } else if (key.equals("name")) {
  663                       if (value != null) {
  664                           context.setCurrentProjectName(value);
  665                           nameAttributeSet = true;
  666                           if (!context.isIgnoringProjectTag()) {
  667                               project.setName(value);
  668                               project.addReference(value, project);
  669                           }
  670                       }
  671                   } else if (key.equals("id")) {
  672                       if (value != null) {
  673                           // What's the difference between id and name ?
  674                           if (!context.isIgnoringProjectTag()) {
  675                               project.addReference(value, project);
  676                           }
  677                       }
  678                   } else if (key.equals("basedir")) {
  679                       if (!context.isIgnoringProjectTag()) {
  680                           baseDir = value;
  681                       }
  682                   } else {
  683                       // XXX ignore attributes in a different NS ( maybe store them ? )
  684                       throw new SAXParseException("Unexpected attribute \""
  685                           + attrs.getQName(i) + "\"", context.getLocator());
  686                   }
  687               }
  688   
  689               // XXX Move to Project ( so it is shared by all helpers )
  690               String antFileProp = "ant.file." + context.getCurrentProjectName();
  691               String dup = project.getProperty(antFileProp);
  692               if (dup != null && nameAttributeSet) {
  693                   File dupFile = new File(dup);
  694                   if (context.isIgnoringProjectTag() && !dupFile.equals(context.getBuildFile())) {
  695                       project.log("Duplicated project name in import. Project "
  696                               + context.getCurrentProjectName() + " defined first in "
  697                               + dup + " and again in " + context.getBuildFile(), Project.MSG_WARN);
  698                   }
  699               }
  700   
  701               if (context.getBuildFile() != null && nameAttributeSet) {
  702                   project.setUserProperty(MagicNames.ANT_FILE + "."
  703                       + context.getCurrentProjectName(), context.getBuildFile().toString());
  704               }
  705   
  706               if (context.isIgnoringProjectTag()) {
  707                   // no further processing
  708                   return;
  709               }
  710               // set explicitly before starting ?
  711               if (project.getProperty("basedir") != null) {
  712                   project.setBasedir(project.getProperty("basedir"));
  713               } else {
  714                   // Default for baseDir is the location of the build file.
  715                   if (baseDir == null) {
  716                       project.setBasedir(context.getBuildFileParent().getAbsolutePath());
  717                   } else {
  718                       // check whether the user has specified an absolute path
  719                       if ((new File(baseDir)).isAbsolute()) {
  720                           project.setBasedir(baseDir);
  721                       } else {
  722                           project.setBaseDir(FILE_UTILS.resolveFile(
  723                                                  context.getBuildFileParent(), baseDir));
  724                       }
  725                   }
  726               }
  727   
  728               project.addTarget("", context.getImplicitTarget());
  729               context.setCurrentTarget(context.getImplicitTarget());
  730           }
  731   
  732           /**
  733            * Handles the start of a top-level element within the project. An
  734            * appropriate handler is created and initialised with the details
  735            * of the element.
  736            *
  737            * @param uri The namespace URI for this element.
  738            * @param name The name of the element being started.
  739            *            Will not be <code>null</code>.
  740            * @param qname The qualified name for this element.
  741            * @param attrs Attributes of the element being started.
  742            *              Will not be <code>null</code>.
  743            * @param context The context for this element.
  744            * @return a target or an element handler.
  745            *
  746            * @exception org.xml.sax.SAXParseException if the tag given is not
  747            *            <code>"taskdef"</code>, <code>"typedef"</code>,
  748            *            <code>"property"</code>, <code>"target"</code>
  749            *            or a data type definition
  750            */
  751           public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs,
  752                                          AntXMLContext context) throws SAXParseException {
  753               return name.equals("target") && (uri.equals("") || uri.equals(ANT_CORE_URI))
  754                       ? ProjectHelper2.targetHandler : ProjectHelper2.elementHandler;
  755           }
  756       }
  757   
  758       /**
  759        * Handler for "target" elements.
  760        */
  761       public static class TargetHandler extends AntHandler {
  762   
  763           /**
  764            * Initialisation routine called after handler creation
  765            * with the element name and attributes. The attributes which
  766            * this handler can deal with are: <code>"name"</code>,
  767            * <code>"depends"</code>, <code>"if"</code>,
  768            * <code>"unless"</code>, <code>"id"</code> and
  769            * <code>"description"</code>.
  770            *
  771            * @param uri The namespace URI for this element.
  772            * @param tag Name of the element which caused this handler
  773            *            to be created. Should not be <code>null</code>.
  774            *            Ignored in this implementation.
  775            * @param qname The qualified name for this element.
  776            * @param attrs Attributes of the element which caused this
  777            *              handler to be created. Must not be <code>null</code>.
  778            * @param context The current context.
  779            *
  780            * @exception SAXParseException if an unexpected attribute is encountered
  781            *            or if the <code>"name"</code> attribute is missing.
  782            */
  783           public void onStartElement(String uri, String tag, String qname, Attributes attrs,
  784                                      AntXMLContext context) throws SAXParseException {
  785               String name = null;
  786               String depends = "";
  787   
  788               Project project = context.getProject();
  789               Target target = new Target();
  790               target.setProject(project);
  791               target.setLocation(new Location(context.getLocator()));
  792               context.addTarget(target);
  793   
  794               for (int i = 0; i < attrs.getLength(); i++) {
  795                   String attrUri = attrs.getURI(i);
  796                   if (attrUri != null && !attrUri.equals("") && !attrUri.equals(uri)) {
  797                       continue; // Ignore attributes from unknown uris
  798                   }
  799                   String key = attrs.getLocalName(i);
  800                   String value = attrs.getValue(i);
  801   
  802                   if (key.equals("name")) {
  803                       name = value;
  804                       if ("".equals(name)) {
  805                           throw new BuildException("name attribute must " + "not be empty");
  806                       }
  807                   } else if (key.equals("depends")) {
  808                       depends = value;
  809                   } else if (key.equals("if")) {
  810                       target.setIf(value);
  811                   } else if (key.equals("unless")) {
  812                       target.setUnless(value);
  813                   } else if (key.equals("id")) {
  814                       if (value != null && !value.equals("")) {
  815                           context.getProject().addReference(value, target);
  816                       }
  817                   } else if (key.equals("description")) {
  818                       target.setDescription(value);
  819                   } else {
  820                       throw new SAXParseException("Unexpected attribute \""
  821                               + key + "\"", context.getLocator());
  822                   }
  823               }
  824   
  825               if (name == null) {
  826                   throw new SAXParseException("target element appears without a name attribute",
  827                           context.getLocator());
  828               }
  829   
  830               // Check if this target is in the current build file
  831               if (context.getCurrentTargets().get(name) != null) {
  832                   throw new BuildException("Duplicate target '" + name + "'", target.getLocation());
  833               }
  834   
  835               Hashtable projectTargets = project.getTargets();
  836               boolean   usedTarget = false;
  837               // If the name has not already been defined define it
  838               if (projectTargets.containsKey(name)) {
  839                   project.log("Already defined in main or a previous import, ignore "
  840                           + name, Project.MSG_VERBOSE);
  841               } else {
  842                   target.setName(name);
  843                   context.getCurrentTargets().put(name, target);
  844                   project.addOrReplaceTarget(name, target);
  845                   usedTarget = true;
  846               }
  847   
  848               if (depends.length() > 0) {
  849                   target.setDepends(depends);
  850               }
  851   
  852               if (context.isIgnoringProjectTag() && context.getCurrentProjectName() != null
  853                   && context.getCurrentProjectName().length() != 0) {
  854                   // In an impored file (and not completely
  855                   // ignoring the project tag)
  856                   String newName = context.getCurrentProjectName() + "." + name;
  857                   Target newTarget = usedTarget ? new Target(target) : target;
  858                   newTarget.setName(newName);
  859                   context.getCurrentTargets().put(newName, newTarget);
  860                   project.addOrReplaceTarget(newName, newTarget);
  861               }
  862           }
  863   
  864           /**
  865            * Handles the start of an element within a target.
  866            *
  867            * @param uri The namespace URI for this element.
  868            * @param name The name of the element being started.
  869            *            Will not be <code>null</code>.
  870            * @param qname The qualified name for this element.
  871            * @param attrs Attributes of the element being started.
  872            *              Will not be <code>null</code>.
  873            * @param context The current context.
  874            * @return an element handler.
  875            *
  876            * @exception SAXParseException if an error occurs when initialising
  877            *                              the appropriate child handler
  878            */
  879           public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs,
  880                                          AntXMLContext context) throws SAXParseException {
  881               return ProjectHelper2.elementHandler;
  882           }
  883   
  884           /**
  885            * Handle the end of the project, sets the current target of the
  886            * context to be the implicit target.
  887            *
  888            * @param uri The namespace URI of the element.
  889            * @param tag The name of the element.
  890            * @param context The current context.
  891            */
  892           public void onEndElement(String uri, String tag, AntXMLContext context) {
  893               context.setCurrentTarget(context.getImplicitTarget());
  894           }
  895       }
  896   
  897       /**
  898        * Handler for all project elements ( tasks, data types )
  899        */
  900       public static class ElementHandler extends AntHandler {
  901   
  902           /**
  903            * Constructor.
  904            */
  905           public ElementHandler() {
  906           }
  907   
  908           /**
  909            * Initialisation routine called after handler creation
  910            * with the element name and attributes. This configures
  911            * the element with its attributes and sets it up with
  912            * its parent container (if any). Nested elements are then
  913            * added later as the parser encounters them.
  914            *
  915            * @param uri The namespace URI for this element.
  916            * @param tag Name of the element which caused this handler
  917            *            to be created. Must not be <code>null</code>.
  918            * @param qname The qualified name for this element.
  919            * @param attrs Attributes of the element which caused this
  920            *              handler to be created. Must not be <code>null</code>.
  921            * @param context The current context.
  922            *
  923            * @exception SAXParseException in case of error (not thrown in
  924            *                              this implementation)
  925            */
  926           public void onStartElement(String uri, String tag, String qname, Attributes attrs,
  927                                      AntXMLContext context) throws SAXParseException {
  928               RuntimeConfigurable parentWrapper = context.currentWrapper();
  929               Object parent = null;
  930   
  931               if (parentWrapper != null) {
  932                   parent = parentWrapper.getProxy();
  933               }
  934   
  935               /* UnknownElement is used for tasks and data types - with
  936                  delayed eval */
  937               UnknownElement task = new UnknownElement(tag);
  938               task.setProject(context.getProject());
  939               task.setNamespace(uri);
  940               task.setQName(qname);
  941               task.setTaskType(ProjectHelper.genComponentName(task.getNamespace(), tag));
  942               task.setTaskName(qname);
  943   
  944               Location location = new Location(context.getLocator().getSystemId(),
  945                       context.getLocator().getLineNumber(), context.getLocator().getColumnNumber());
  946               task.setLocation(location);
  947               task.setOwningTarget(context.getCurrentTarget());
  948   
  949               if (parent != null) {
  950                   // Nested element
  951                   ((UnknownElement) parent).addChild(task);
  952               }  else {
  953                   // Task included in a target ( including the default one ).
  954                   context.getCurrentTarget().addTask(task);
  955               }
  956   
  957               context.configureId(task, attrs);
  958   
  959               // container.addTask(task);
  960               // This is a nop in UE: task.init();
  961   
  962               RuntimeConfigurable wrapper = new RuntimeConfigurable(task, task.getTaskName());
  963   
  964               for (int i = 0; i < attrs.getLength(); i++) {
  965                   String name = attrs.getLocalName(i);
  966                   String attrUri = attrs.getURI(i);
  967                   if (attrUri != null && !attrUri.equals("") && !attrUri.equals(uri)) {
  968                       name = attrUri + ":" + attrs.getQName(i);
  969                   }
  970                   String value = attrs.getValue(i);
  971                   // PR: Hack for ant-type value
  972                   //  an ant-type is a component name which can
  973                   // be namespaced, need to extract the name
  974                   // and convert from qualified name to uri/name
  975                   if (ANT_TYPE.equals(name) || (ANT_CORE_URI.equals(attrUri)
  976                           && ANT_TYPE.equals(attrs.getLocalName(i)))) {
  977                       context.getProject().log(
  978                           "WARNING: "
  979                           + "the ant-type mechanism has been deprecated"
  980                           + StringUtils.LINE_SEP
  981                           + "         and"
  982                           + " will not be available in Ant 1.8.0 or higher",
  983                           Project.MSG_WARN);
  984                       name = ANT_TYPE;
  985                       int index = value.indexOf(":");
  986                       if (index >= 0) {
  987                           String prefix = value.substring(0, index);
  988                           String mappedUri = context.getPrefixMapping(prefix);
  989                           if (mappedUri == null) {
  990                               throw new BuildException(
  991                                       "Unable to find XML NS prefix \"" + prefix + "\"");
  992                           }
  993                           value = ProjectHelper.genComponentName(
  994                                   mappedUri, value.substring(index + 1));
  995                       }
  996                   }
  997                   wrapper.setAttribute(name, value);
  998               }
  999               if (parentWrapper != null) {
 1000                   parentWrapper.addChild(wrapper);
 1001               }
 1002               context.pushWrapper(wrapper);
 1003           }
 1004   
 1005           /**
 1006            * Adds text to the task, using the wrapper
 1007            *
 1008            * @param buf A character array of the text within the element.
 1009            *            Will not be <code>null</code>.
 1010            * @param start The start element in the array.
 1011            * @param count The number of characters to read from the array.
 1012            * @param context The current context.
 1013            *
 1014            * @exception SAXParseException if the element doesn't support text
 1015            *
 1016            * @see ProjectHelper#addText(Project,java.lang.Object,char[],int,int)
 1017            */
 1018           public void characters(char[] buf, int start, int count,
 1019                                  AntXMLContext context) throws SAXParseException {
 1020               RuntimeConfigurable wrapper = context.currentWrapper();
 1021               wrapper.addText(buf, start, count);
 1022           }
 1023   
 1024           /**
 1025            * Handles the start of an element within a target. Task containers
 1026            * will always use another task handler, and all other tasks
 1027            * will always use a nested element handler.
 1028            *
 1029            * @param uri The namespace URI for this element.
 1030            * @param tag The name of the element being started.
 1031            *            Will not be <code>null</code>.
 1032            * @param qname The qualified name for this element.
 1033            * @param attrs Attributes of the element being started.
 1034            *              Will not be <code>null</code>.
 1035            * @param context The current context.
 1036            * @return The handler for elements.
 1037            *
 1038            * @exception SAXParseException if an error occurs when initialising
 1039            *                              the appropriate child handler
 1040            */
 1041           public AntHandler onStartChild(String uri, String tag, String qname, Attributes attrs,
 1042                                          AntXMLContext context) throws SAXParseException {
 1043               return ProjectHelper2.elementHandler;
 1044           }
 1045   
 1046           /**
 1047            * Handles the end of the element. This pops the wrapper from
 1048            * the context.
 1049            *
 1050            * @param uri The namespace URI for the element.
 1051            * @param tag The name of the element.
 1052            * @param context The current context.
 1053            */
 1054           public void onEndElement(String uri, String tag, AntXMLContext context) {
 1055               context.popWrapper();
 1056           }
 1057       }
 1058   }

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