| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * Copyright (c) 2002 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, if |
| * any, must include the following acknowlegement: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowlegement may appear in the software itself, |
| * if and wherever such third-party acknowlegements normally appear. |
| * |
| * 4. The names "The Jakarta Project", "Ant", and "Apache Software |
| * Foundation" must not be used to endorse or promote products derived |
| * from this software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache" |
| * nor may "Apache" appear in their names without prior written |
| * permission of the Apache Group. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| package org.apache.ant.antcore.xml; |
| import java.net.URL; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| import org.apache.ant.common.util.Location; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.ContentHandler; |
| import org.xml.sax.Locator; |
| import org.xml.sax.SAXParseException; |
| import org.xml.sax.XMLReader; |
| import org.xml.sax.helpers.DefaultHandler; |
| import org.apache.ant.common.util.PropertyUtils; |
| |
| /** |
| * An Element Handler is a handler which handles a single element by |
| * becoming the handler for the parser while processing the element. Any sub |
| * elements must be delegated to separate handlers. When this element is |
| * finished, control returns to the parent handler. |
| * |
| * @author <a href="mailto:conor@apache.org">Conor MacNeill</a> |
| * @created 9 January 2002 |
| */ |
| public abstract class ElementHandler extends DefaultHandler { |
| /** The parsing context for parsing this element */ |
| private ParseContext context; |
| |
| /** |
| * Locator used to identify where in the build source particular |
| * elements occur. |
| */ |
| private Locator locator; |
| |
| /** The actual XML parser used to parse the build source */ |
| private XMLReader reader; |
| |
| /** The parent element handler */ |
| private ContentHandler parent; |
| |
| /** The URL from which we are reading source */ |
| private URL source; |
| |
| /** The name of this element */ |
| private String elementName; |
| |
| /** The attributes read from this element */ |
| private Map elementAttributes; |
| |
| /** The aspect attributes read from the element definition */ |
| private Map aspects; |
| |
| /** The content of this element */ |
| private String content; |
| |
| /** |
| * Get the source which contains this element |
| * |
| * @return the URL from which this element is being read |
| */ |
| public URL getElementSource() { |
| return source; |
| } |
| |
| /** |
| * Gets the attributeValue attribute of the ElementHandler object |
| * |
| * @param attributeName th name of the attribute |
| * @return The corresponding attribute value or null if the attribute wa |
| * snot defined. |
| */ |
| public String getAttribute(String attributeName) { |
| return (String)elementAttributes.get(attributeName); |
| } |
| |
| /** |
| * Get an attribute as a boolean value |
| * |
| * @param attributeName the name of the attribute |
| * @return the attribute value as a boolean |
| */ |
| protected boolean getBooleanAttribute(String attributeName) { |
| return PropertyUtils.toBoolean(getAttribute(attributeName)); |
| } |
| |
| /** |
| * Get an iterator to this elements attributes |
| * |
| * @return an iterator over the attribute names |
| */ |
| public Iterator getAttributes() { |
| return elementAttributes.keySet().iterator(); |
| } |
| |
| /** |
| * Get the aspect attributes of this element. |
| * |
| * @return The aspect attributes. |
| */ |
| public Map getAspects() { |
| return aspects; |
| } |
| |
| /** |
| * Gets the content of the element |
| * |
| * @return The content value |
| */ |
| public String getContent() { |
| return content; |
| } |
| |
| |
| /** |
| * Start this element handler. |
| * |
| * @param parent the element handler for the element which contains this |
| * one. |
| * @param locator the locator is used to get location information from |
| * elements. |
| * @param attributes the element's attributes. |
| * @param source the URL from which the XML source is being parsed. |
| * @param xmlReader the parser being used |
| * @param context the parser context for this element |
| * @param elementName the actual element Name for this element in the |
| * XML |
| * @exception SAXParseException if there is a problem parsing the |
| * element |
| */ |
| public final void start(ParseContext context, XMLReader xmlReader, |
| ContentHandler parent, Locator locator, |
| Attributes attributes, URL source, |
| String elementName) |
| throws SAXParseException { |
| this.context = context; |
| this.reader = xmlReader; |
| this.parent = parent; |
| this.locator = locator; |
| this.source = source; |
| this.elementName = elementName; |
| processAttributes(attributes); |
| processElement(elementName); |
| reader.setContentHandler(this); |
| } |
| |
| |
| /** |
| * By default an element handler does not support nested elements. This |
| * method will always throw an exception. Subclasses should override |
| * this method to support their own nested elements |
| * |
| * @param uri The Namespace URI. |
| * @param localName The local name (without prefix). |
| * @param qualifiedName The qualified name (with prefix) |
| * @param attributes The attributes attached to the element. |
| * @throws SAXParseException if there is a problem parsng the subelement |
| */ |
| public void startElement(String uri, String localName, String qualifiedName, |
| Attributes attributes) |
| throws SAXParseException { |
| // everything is a task |
| throw new SAXParseException("<" + elementName + "> does not support a <" |
| + qualifiedName + "> nested element", getLocator()); |
| } |
| |
| |
| /** |
| * Handle the end of this element by making the parent element handler |
| * the current content handler |
| * |
| * @param localName The local name (without prefix). |
| * @param namespaceURI The Namespace URI. |
| * @param qName the qualified name of the element |
| */ |
| public final void endElement(String namespaceURI, String localName, |
| String qName) { |
| finish(); |
| reader.setContentHandler(parent); |
| } |
| |
| /** |
| * Record content of this element |
| * |
| * @param buf the buffer containing the content to be added |
| * @param start start position in the buffer |
| * @param end end position in the buffer |
| * @exception SAXParseException if there is a parsing error. |
| * @see org.xml.sax.ContentHandler.characters() |
| */ |
| public void characters(char[] buf, int start, int end) |
| throws SAXParseException { |
| if (content == null) { |
| content = ""; |
| } |
| content += new String(buf, start, end); |
| } |
| |
| |
| /** |
| * Get the current parsing location |
| * |
| * @return a location instance representing the current parse position |
| */ |
| protected Location getLocation() { |
| return new Location(locator.getSystemId(), locator.getLineNumber(), |
| locator.getColumnNumber()); |
| } |
| |
| |
| /** |
| * Get the XML Reader being used to parse the XML. |
| * |
| * @return the XML Reader. |
| */ |
| protected XMLReader getXMLReader() { |
| return reader; |
| } |
| |
| |
| /** |
| * Get the parsing context |
| * |
| * @return the parsing context of this element |
| */ |
| protected ParseContext getParseContext() { |
| return context; |
| } |
| |
| |
| /** |
| * Get the locator used to locate elements in the XML source as they are |
| * parsed. |
| * |
| * @return the locator object which can be used to determine an elements |
| * location within the XML source |
| */ |
| protected Locator getLocator() { |
| return locator; |
| } |
| |
| |
| /** |
| * Process the element. |
| * |
| * @param elementName the name of the element |
| * @exception SAXParseException if there is a problem parsing the |
| * element |
| */ |
| protected abstract void processElement(String elementName) |
| throws SAXParseException; |
| |
| |
| /** |
| * Process all of the attributes of the element into maps, one for |
| * aspects and one for other attributes |
| * |
| * @param attributes The SAX attributes collection for the element |
| * @exception SAXParseException if there is a problem reading the |
| * attributes |
| */ |
| protected final void processAttributes(Attributes attributes) |
| throws SAXParseException { |
| aspects = new HashMap(); |
| elementAttributes = new HashMap(); |
| int length = attributes.getLength(); |
| for (int i = 0; i < length; ++i) { |
| String attributeName = attributes.getQName(i); |
| String attributeValue = attributes.getValue(i); |
| if (attributeName.indexOf(":") != -1) { |
| aspects.put(attributeName, attributeValue); |
| } else { |
| validateAttribute(attributeName, attributeValue); |
| elementAttributes.put(attributeName, attributeValue); |
| } |
| } |
| } |
| |
| /** |
| * Validate that the given attribute and value are valid. By default all |
| * attributes are considered invalid. This method should be overrider by |
| * subclasses to allow specific attributes |
| * |
| * @param attributeName The name of the attributes |
| * @param attributeValue The value of the attributes |
| * @exception SAXParseException if the attribute is not allowed on the |
| * element. |
| */ |
| protected void validateAttribute(String attributeName, |
| String attributeValue) |
| throws SAXParseException { |
| throwInvalidAttribute(attributeName); |
| } |
| |
| /** |
| * Throws an invalid attribute exception |
| * |
| * @param attributeName The name of the invalid attribute |
| * @exception SAXParseException always - indicating attribute is invalid |
| */ |
| protected final void throwInvalidAttribute(String attributeName) |
| throws SAXParseException { |
| throw new SAXParseException("The attribute '" + attributeName |
| + "' is not " + "supported by the <" + elementName |
| + "> element", getLocator()); |
| } |
| |
| |
| /** |
| * This method is called when this element is finished being processed. |
| * This is a template method allowing subclasses to complete any |
| * necessary processing. |
| */ |
| protected void finish() { |
| } |
| } |
| |