    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements.  See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache License, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License.  You may obtain a copy of the License at
    008     *
    009     *     http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the License for the specific language governing permissions and
    015     * limitations under the License.
    016     */
    017
    018    package org.apache.commons.configuration;
    019
    020    import java.io.IOException;
    021
    022    import org.xml.sax.Attributes;
    023    import org.xml.sax.ContentHandler;
    024    import org.xml.sax.DTDHandler;
    025    import org.xml.sax.EntityResolver;
    026    import org.xml.sax.ErrorHandler;
    027    import org.xml.sax.InputSource;
    028    import org.xml.sax.SAXException;
    029    import org.xml.sax.XMLReader;
    030    import org.xml.sax.helpers.AttributesImpl;
    031
    032    /**
    033     * <p>A base class for &quot;faked&quot; <code>XMLReader</code> classes
    034     * that transform a configuration object in a set of SAX parsing events.</p>
    035     * <p>This class provides dummy implementations for most of the methods
    036     * defined in the <code>XMLReader</code> interface that are not used for this
    037     * special purpose. There will be concrete sub classes that process specific
    038     * configuration classes.</p>
    039     *
    040     * @author <a href="mailto:oliver.heger@t-online.de">Oliver Heger</a>
    041     * @version $Id: ConfigurationXMLReader.java 439648 2006-09-02 20:42:10Z oheger $
    042     */
    043    public abstract class ConfigurationXMLReader implements XMLReader
    044    {
    045        /** Constant for the namespace URI.*/
    046        protected static final String NS_URI = "";
    047
    048        /** Constant for the default name of the root element.*/
    049        private static final String DEFAULT_ROOT_NAME = "config";
    050
    051        /** An empty attributes object.*/
    052        private static final Attributes EMPTY_ATTRS = new AttributesImpl();
    053
    054        /** Stores the content handler.*/
    055        private ContentHandler contentHandler;
    056
    057        /** Stores an exception that occurred during parsing.*/
    058        private SAXException exception;
    059
    060        /** Stores the name for the root element.*/
    061        private String rootName;
    062
    063        /**
    064         * Creates a new instance of <code>ConfigurationXMLReader</code>.
    065         */
    066        protected ConfigurationXMLReader()
    067        {
    068            super();
    069            setRootName(DEFAULT_ROOT_NAME);
    070        }
    071
    072        /**
    073         * Parses the acutal configuration object. The passed system ID will be
    074         * ignored.
    075         *
    076         * @param systemId the system ID (ignored)
    077         * @throws IOException if no configuration was specified
    078         * @throws SAXException if an error occurs during parsing
    079         */
    080        public void parse(String systemId) throws IOException, SAXException
    081        {
    082            parseConfiguration();
    083        }
    084
    085        /**
    086         * Parses the acutal configuration object. The passed input source will be
    087         * ignored.
    088         *
    089         * @param input the input source (ignored)
    090         * @throws IOException if no configuration was specified
    091         * @throws SAXException if an error occurs during parsing
    092         */
    093        public void parse(InputSource input) throws IOException, SAXException
    094        {
    095            parseConfiguration();
    096        }
    097
    098        /**
    099         * Dummy implementation of the interface method.
    100         *
    101         * @param name the name of the feature
    102         * @return always <b>false</b> (no features are supported)
    103         */
    104        public boolean getFeature(String name)
    105        {
    106            return false;
    107        }
    108
    109        /**
    110         * Dummy implementation of the interface method.
    111         *
    112         * @param name the name of the feature to be set
    113         * @param value the value of the feature
    114         */
    115        public void setFeature(String name, boolean value)
    116        {
    117        }
    118
    119        /**
    120         * Returns the actually set content handler.
    121         *
    122         * @return the content handler
    123         */
    124        public ContentHandler getContentHandler()
    125        {
    126            return contentHandler;
    127        }
    128
    129        /**
    130         * Sets the content handler. The object specified here will receive SAX
    131         * events during parsing.
    132         *
    133         * @param handler the content handler
    134         */
    135        public void setContentHandler(ContentHandler handler)
    136        {
    137            contentHandler = handler;
    138        }
    139
    140        /**
    141         * Returns the DTD handler. This class does not support DTD handlers,
    142         * so this method always returns <b>null</b>.
    143         *
    144         * @return the DTD handler
    145         */
    146        public DTDHandler getDTDHandler()
    147        {
    148            return null;
    149        }
    150
    151        /**
    152         * Sets the DTD handler. The passed value is ignored.
    153         *
    154         * @param handler the handler to be set
    155         */
    156        public void setDTDHandler(DTDHandler handler)
    157        {
    158        }
    159
    160        /**
    161         * Returns the entity resolver. This class does not support an entity
    162         * resolver, so this method always returns <b>null</b>.
    163         *
    164         * @return the entity resolver
    165         */
    166        public EntityResolver getEntityResolver()
    167        {
    168            return null;
    169        }
    170
    171        /**
    172         * Sets the entity resolver. The passed value is ignored.
    173         *
    174         * @param resolver the entity resolver
    175         */
    176        public void setEntityResolver(EntityResolver resolver)
    177        {
    178        }
    179
    180        /**
    181         * Returns the error handler. This class does not support an error handler,
    182         * so this method always returns <b>null</b>.
    183         *
    184         * @return the error handler
    185         */
    186        public ErrorHandler getErrorHandler()
    187        {
    188            return null;
    189        }
    190
    191        /**
    192         * Sets the error handler. The passed value is ignored.
    193         *
    194         * @param handler the error handler
    195         */
    196        public void setErrorHandler(ErrorHandler handler)
    197        {
    198        }
    199
    200        /**
    201         * Dummy implementation of the interface method. No properties are
    202         * supported, so this method always returns <b>null</b>.
    203         *
    204         * @param name the name of the requested property
    205         * @return the property value
    206         */
    207        public Object getProperty(String name)
    208        {
    209            return null;
    210        }
    211
    212        /**
    213         * Dummy implementation of the interface method. No properties are
    214         * supported, so a call of this method just has no effect.
    215         *
    216         * @param name the property name
    217         * @param value the property value
    218         */
    219        public void setProperty(String name, Object value)
    220        {
    221        }
    222
    223        /**
    224         * Returns the name to be used for the root element.
    225         *
    226         * @return the name for the root element
    227         */
    228        public String getRootName()
    229        {
    230            return rootName;
    231        }
    232
    233        /**
    234         * Sets the name for the root element.
    235         *
    236         * @param string the name for the root element.
    237         */
    238        public void setRootName(String string)
    239        {
    240            rootName = string;
    241        }
    242
    243        /**
    244         * Fires a SAX element start event.
    245         *
    246         * @param name the name of the actual element
    247         * @param attribs the attributes of this element (can be <b>null</b>)
    248         */
    249        protected void fireElementStart(String name, Attributes attribs)
    250        {
    251            if (getException() == null)
    252            {
    253                try
    254                {
    255                    Attributes at = (attribs == null) ? EMPTY_ATTRS : attribs;
    256                    getContentHandler().startElement(NS_URI, name, name, at);
    257                }
    258                catch (SAXException ex)
    259                {
    260                    exception = ex;
    261                }
    262            }
    263        }
    264
    265        /**
    266         * Fires a SAX element end event.
    267         *
    268         * @param name the name of the affected element
    269         */
    270        protected void fireElementEnd(String name)
    271        {
    272            if (getException() == null)
    273            {
    274                try
    275                {
    276                    getContentHandler().endElement(NS_URI, name, name);
    277                }
    278                catch (SAXException ex)
    279                {
    280                    exception = ex;
    281                }
    282            }
    283        }
    284
    285        /**
    286         * Fires a SAX characters event.
    287         *
    288         * @param text the text
    289         */
    290        protected void fireCharacters(String text)
    291        {
    292            if (getException() == null)
    293            {
    294                try
    295                {
    296                    char[] ch = text.toCharArray();
    297                    getContentHandler().characters(ch, 0, ch.length);
    298                }
    299                catch (SAXException ex)
    300                {
    301                    exception = ex;
    302                }
    303            }
    304        }
    305
    306        /**
    307         * Returns a reference to an exception that occurred during parsing.
    308         *
    309         * @return a SAXExcpetion or <b>null</b> if none occurred
    310         */
    311        public SAXException getException()
    312        {
    313            return exception;
    314        }
    315
    316        /**
    317         * Parses the configuration object and generates SAX events. This is the
    318         * main processing method.
    319         *
    320         * @throws IOException if no configuration has been specified
    321         * @throws SAXException if an error occurs during parsing
    322         */
    323        protected void parseConfiguration() throws IOException, SAXException
    324        {
    325            if (getParsedConfiguration() == null)
    326            {
    327                throw new IOException("No configuration specified!");
    328            }
    329
    330            if (getContentHandler() != null)
    331            {
    332                exception = null;
    333                getContentHandler().startDocument();
    334                processKeys();
    335                if (getException() != null)
    336                {
    337                    throw getException();
    338                }
    339                getContentHandler().endDocument();
    340            }
    341        }
    342
    343        /**
    344         * Returns a reference to the configuration that is parsed by this object.
    345         *
    346         * @return the parsed configuration
    347         */
    348        public abstract Configuration getParsedConfiguration();
    349
    350        /**
    351         * Processes all keys stored in the actual configuration. This method is
    352         * called by <code>parseConfiguration()</code> to start the main parsing
    353         * process. <code>parseConfiguration()</code> calls the content handler's
    354         * <code>startDocument()</code> and <code>endElement()</code> methods
    355         * and cares for exception handling. The remaining actions are left to this
    356         * method that must be implemented in a concrete sub class.
    357         *
    358         * @throws IOException if an IO error occurs
    359         * @throws SAXException if a SAX error occurs
    360         */
    361        protected abstract void processKeys() throws IOException, SAXException;
    362    }