ConfigurationXMLReader.java

  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. package org.apache.commons.configuration2;

  18. import java.io.IOException;

  19. import org.xml.sax.Attributes;
  20. import org.xml.sax.ContentHandler;
  21. import org.xml.sax.DTDHandler;
  22. import org.xml.sax.EntityResolver;
  23. import org.xml.sax.ErrorHandler;
  24. import org.xml.sax.InputSource;
  25. import org.xml.sax.SAXException;
  26. import org.xml.sax.XMLReader;
  27. import org.xml.sax.helpers.AttributesImpl;

  28. /**
  29.  * <p>
  30.  * A base class for &quot;faked&quot; {@code XMLReader} classes that transform a configuration object in a set of SAX
  31.  * parsing events.
  32.  * </p>
  33.  * <p>
  34.  * This class provides dummy implementations for most of the methods defined in the {@code XMLReader} interface that are
  35.  * not used for this special purpose. There will be concrete sub classes that process specific configuration classes.
  36.  * </p>
  37.  */
  38. public abstract class ConfigurationXMLReader implements XMLReader {
  39.     /** Constant for the namespace URI. */
  40.     protected static final String NS_URI = "";

  41.     /** Constant for the default name of the root element. */
  42.     private static final String DEFAULT_ROOT_NAME = "config";

  43.     /** An empty attributes object. */
  44.     private static final Attributes EMPTY_ATTRS = new AttributesImpl();

  45.     /** Stores the content handler. */
  46.     private ContentHandler contentHandler;

  47.     /** Stores an exception that occurred during parsing. */
  48.     private SAXException exception;

  49.     /** Stores the name for the root element. */
  50.     private String rootName;

  51.     /**
  52.      * Creates a new instance of {@code ConfigurationXMLReader}.
  53.      */
  54.     protected ConfigurationXMLReader() {
  55.         rootName = DEFAULT_ROOT_NAME;
  56.     }

  57.     /**
  58.      * Fires a SAX characters event.
  59.      *
  60.      * @param text the text
  61.      */
  62.     protected void fireCharacters(final String text) {
  63.         if (getException() == null) {
  64.             try {
  65.                 final char[] ch = text.toCharArray();
  66.                 getContentHandler().characters(ch, 0, ch.length);
  67.             } catch (final SAXException ex) {
  68.                 exception = ex;
  69.             }
  70.         }
  71.     }

  72.     /**
  73.      * Fires a SAX element end event.
  74.      *
  75.      * @param name the name of the affected element
  76.      */
  77.     protected void fireElementEnd(final String name) {
  78.         if (getException() == null) {
  79.             try {
  80.                 getContentHandler().endElement(NS_URI, name, name);
  81.             } catch (final SAXException ex) {
  82.                 exception = ex;
  83.             }
  84.         }
  85.     }

  86.     /**
  87.      * Fires a SAX element start event.
  88.      *
  89.      * @param name the name of the actual element
  90.      * @param attribs the attributes of this element (can be <strong>null</strong>)
  91.      */
  92.     protected void fireElementStart(final String name, final Attributes attribs) {
  93.         if (getException() == null) {
  94.             try {
  95.                 final Attributes at = attribs == null ? EMPTY_ATTRS : attribs;
  96.                 getContentHandler().startElement(NS_URI, name, name, at);
  97.             } catch (final SAXException ex) {
  98.                 exception = ex;
  99.             }
  100.         }
  101.     }

  102.     /**
  103.      * Gets the actually set content handler.
  104.      *
  105.      * @return the content handler
  106.      */
  107.     @Override
  108.     public ContentHandler getContentHandler() {
  109.         return contentHandler;
  110.     }

  111.     /**
  112.      * Gets the DTD handler. This class does not support DTD handlers, so this method always returns <strong>null</strong>.
  113.      *
  114.      * @return the DTD handler
  115.      */
  116.     @Override
  117.     public DTDHandler getDTDHandler() {
  118.         return null;
  119.     }

  120.     /**
  121.      * Gets the entity resolver. This class does not support an entity resolver, so this method always returns
  122.      * <strong>null</strong>.
  123.      *
  124.      * @return the entity resolver
  125.      */
  126.     @Override
  127.     public EntityResolver getEntityResolver() {
  128.         return null;
  129.     }

  130.     /**
  131.      * Gets the error handler. This class does not support an error handler, so this method always returns <strong>null</strong>.
  132.      *
  133.      * @return the error handler
  134.      */
  135.     @Override
  136.     public ErrorHandler getErrorHandler() {
  137.         return null;
  138.     }

  139.     /**
  140.      * Gets a reference to an exception that occurred during parsing.
  141.      *
  142.      * @return a SAXExcpetion or <strong>null</strong> if none occurred
  143.      */
  144.     public SAXException getException() {
  145.         return exception;
  146.     }

  147.     /**
  148.      * Dummy implementation of the interface method.
  149.      *
  150.      * @param name the name of the feature
  151.      * @return always <strong>false</strong> (no features are supported)
  152.      */
  153.     @Override
  154.     public boolean getFeature(final String name) {
  155.         return false;
  156.     }

  157.     /**
  158.      * Gets a reference to the configuration that is parsed by this object.
  159.      *
  160.      * @return the parsed configuration
  161.      */
  162.     public abstract Configuration getParsedConfiguration();

  163.     /**
  164.      * Dummy implementation of the interface method. No properties are supported, so this method always returns <strong>null</strong>.
  165.      *
  166.      * @param name the name of the requested property
  167.      * @return the property value
  168.      */
  169.     @Override
  170.     public Object getProperty(final String name) {
  171.         return null;
  172.     }

  173.     /**
  174.      * Gets the name to be used for the root element.
  175.      *
  176.      * @return the name for the root element
  177.      */
  178.     public String getRootName() {
  179.         return rootName;
  180.     }

  181.     /**
  182.      * Parses the actual configuration object. The passed input source will be ignored.
  183.      *
  184.      * @param input the input source (ignored)
  185.      * @throws IOException if no configuration was specified
  186.      * @throws SAXException if an error occurs during parsing
  187.      */
  188.     @Override
  189.     public void parse(final InputSource input) throws IOException, SAXException {
  190.         parseConfiguration();
  191.     }

  192.     /**
  193.      * Parses the current configuration object. The passed system ID will be ignored.
  194.      *
  195.      * @param systemId the system ID (ignored)
  196.      * @throws IOException if no configuration was specified
  197.      * @throws SAXException if an error occurs during parsing
  198.      */
  199.     @Override
  200.     public void parse(final String systemId) throws IOException, SAXException {
  201.         parseConfiguration();
  202.     }

  203.     /**
  204.      * Parses the configuration object and generates SAX events. This is the main processing method.
  205.      *
  206.      * @throws IOException if no configuration has been specified
  207.      * @throws SAXException if an error occurs during parsing
  208.      */
  209.     protected void parseConfiguration() throws IOException, SAXException {
  210.         if (getParsedConfiguration() == null) {
  211.             throw new IOException("No configuration specified!");
  212.         }

  213.         if (getContentHandler() != null) {
  214.             exception = null;
  215.             getContentHandler().startDocument();
  216.             processKeys();
  217.             if (getException() != null) {
  218.                 throw getException();
  219.             }
  220.             getContentHandler().endDocument();
  221.         }
  222.     }

  223.     /**
  224.      * Processes all keys stored in the actual configuration. This method is called by {@code parseConfiguration()} to start
  225.      * the main parsing process. {@code parseConfiguration()} calls the content handler's {@code startDocument()} and
  226.      * {@code endElement()} methods and cares for exception handling. The remaining actions are left to this method that
  227.      * must be implemented in a concrete sub class.
  228.      *
  229.      * @throws IOException if an IO error occurs
  230.      * @throws SAXException if a SAX error occurs
  231.      */
  232.     protected abstract void processKeys() throws IOException, SAXException;

  233.     /**
  234.      * Sets the content handler. The object specified here will receive SAX events during parsing.
  235.      *
  236.      * @param handler the content handler
  237.      */
  238.     @Override
  239.     public void setContentHandler(final ContentHandler handler) {
  240.         contentHandler = handler;
  241.     }

  242.     /**
  243.      * Sets the DTD handler. The passed value is ignored.
  244.      *
  245.      * @param handler the handler to be set
  246.      */
  247.     @Override
  248.     public void setDTDHandler(final DTDHandler handler) {
  249.     }

  250.     /**
  251.      * Sets the entity resolver. The passed value is ignored.
  252.      *
  253.      * @param resolver the entity resolver
  254.      */
  255.     @Override
  256.     public void setEntityResolver(final EntityResolver resolver) {
  257.     }

  258.     /**
  259.      * Sets the error handler. The passed value is ignored.
  260.      *
  261.      * @param handler the error handler
  262.      */
  263.     @Override
  264.     public void setErrorHandler(final ErrorHandler handler) {
  265.     }

  266.     /**
  267.      * Dummy implementation of the interface method.
  268.      *
  269.      * @param name the name of the feature to be set
  270.      * @param value the value of the feature
  271.      */
  272.     @Override
  273.     public void setFeature(final String name, final boolean value) {
  274.     }

  275.     /**
  276.      * Dummy implementation of the interface method. No properties are supported, so a call of this method just has no
  277.      * effect.
  278.      *
  279.      * @param name the property name
  280.      * @param value the property value
  281.      */
  282.     @Override
  283.     public void setProperty(final String name, final Object value) {
  284.     }

  285.     /**
  286.      * Sets the name for the root element.
  287.      *
  288.      * @param string the name for the root element.
  289.      */
  290.     public void setRootName(final String string) {
  291.         rootName = string;
  292.     }
  293. }