View Javadoc
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.commons.configuration2;
19  
20  import java.io.IOException;
21  
22  import org.xml.sax.Attributes;
23  import org.xml.sax.ContentHandler;
24  import org.xml.sax.DTDHandler;
25  import org.xml.sax.EntityResolver;
26  import org.xml.sax.ErrorHandler;
27  import org.xml.sax.InputSource;
28  import org.xml.sax.SAXException;
29  import org.xml.sax.XMLReader;
30  import org.xml.sax.helpers.AttributesImpl;
31  
32  /**
33   * <p>
34   * A base class for &quot;faked&quot; {@code XMLReader} classes that transform a configuration object in a set of SAX
35   * parsing events.
36   * </p>
37   * <p>
38   * This class provides dummy implementations for most of the methods defined in the {@code XMLReader} interface that are
39   * not used for this special purpose. There will be concrete sub classes that process specific configuration classes.
40   * </p>
41   */
42  public abstract class ConfigurationXMLReader implements XMLReader {
43      /** Constant for the namespace URI. */
44      protected static final String NS_URI = "";
45  
46      /** Constant for the default name of the root element. */
47      private static final String DEFAULT_ROOT_NAME = "config";
48  
49      /** An empty attributes object. */
50      private static final Attributes EMPTY_ATTRS = new AttributesImpl();
51  
52      /** Stores the content handler. */
53      private ContentHandler contentHandler;
54  
55      /** Stores an exception that occurred during parsing. */
56      private SAXException exception;
57  
58      /** Stores the name for the root element. */
59      private String rootName;
60  
61      /**
62       * Creates a new instance of {@code ConfigurationXMLReader}.
63       */
64      protected ConfigurationXMLReader() {
65          rootName = DEFAULT_ROOT_NAME;
66      }
67  
68      /**
69       * Fires a SAX characters event.
70       *
71       * @param text the text
72       */
73      protected void fireCharacters(final String text) {
74          if (getException() == null) {
75              try {
76                  final char[] ch = text.toCharArray();
77                  getContentHandler().characters(ch, 0, ch.length);
78              } catch (final SAXException ex) {
79                  exception = ex;
80              }
81          }
82      }
83  
84      /**
85       * Fires a SAX element end event.
86       *
87       * @param name the name of the affected element
88       */
89      protected void fireElementEnd(final String name) {
90          if (getException() == null) {
91              try {
92                  getContentHandler().endElement(NS_URI, name, name);
93              } catch (final SAXException ex) {
94                  exception = ex;
95              }
96          }
97      }
98  
99      /**
100      * Fires a SAX element start event.
101      *
102      * @param name the name of the actual element
103      * @param attribs the attributes of this element (can be <b>null</b>)
104      */
105     protected void fireElementStart(final String name, final Attributes attribs) {
106         if (getException() == null) {
107             try {
108                 final Attributes at = attribs == null ? EMPTY_ATTRS : attribs;
109                 getContentHandler().startElement(NS_URI, name, name, at);
110             } catch (final SAXException ex) {
111                 exception = ex;
112             }
113         }
114     }
115 
116     /**
117      * Gets the actually set content handler.
118      *
119      * @return the content handler
120      */
121     @Override
122     public ContentHandler getContentHandler() {
123         return contentHandler;
124     }
125 
126     /**
127      * Gets the DTD handler. This class does not support DTD handlers, so this method always returns <b>null</b>.
128      *
129      * @return the DTD handler
130      */
131     @Override
132     public DTDHandler getDTDHandler() {
133         return null;
134     }
135 
136     /**
137      * Gets the entity resolver. This class does not support an entity resolver, so this method always returns
138      * <b>null</b>.
139      *
140      * @return the entity resolver
141      */
142     @Override
143     public EntityResolver getEntityResolver() {
144         return null;
145     }
146 
147     /**
148      * Gets the error handler. This class does not support an error handler, so this method always returns <b>null</b>.
149      *
150      * @return the error handler
151      */
152     @Override
153     public ErrorHandler getErrorHandler() {
154         return null;
155     }
156 
157     /**
158      * Gets a reference to an exception that occurred during parsing.
159      *
160      * @return a SAXExcpetion or <b>null</b> if none occurred
161      */
162     public SAXException getException() {
163         return exception;
164     }
165 
166     /**
167      * Dummy implementation of the interface method.
168      *
169      * @param name the name of the feature
170      * @return always <b>false</b> (no features are supported)
171      */
172     @Override
173     public boolean getFeature(final String name) {
174         return false;
175     }
176 
177     /**
178      * Gets a reference to the configuration that is parsed by this object.
179      *
180      * @return the parsed configuration
181      */
182     public abstract Configuration getParsedConfiguration();
183 
184     /**
185      * Dummy implementation of the interface method. No properties are supported, so this method always returns <b>null</b>.
186      *
187      * @param name the name of the requested property
188      * @return the property value
189      */
190     @Override
191     public Object getProperty(final String name) {
192         return null;
193     }
194 
195     /**
196      * Gets the name to be used for the root element.
197      *
198      * @return the name for the root element
199      */
200     public String getRootName() {
201         return rootName;
202     }
203 
204     /**
205      * Parses the actual configuration object. The passed input source will be ignored.
206      *
207      * @param input the input source (ignored)
208      * @throws IOException if no configuration was specified
209      * @throws SAXException if an error occurs during parsing
210      */
211     @Override
212     public void parse(final InputSource input) throws IOException, SAXException {
213         parseConfiguration();
214     }
215 
216     /**
217      * Parses the current configuration object. The passed system ID will be ignored.
218      *
219      * @param systemId the system ID (ignored)
220      * @throws IOException if no configuration was specified
221      * @throws SAXException if an error occurs during parsing
222      */
223     @Override
224     public void parse(final String systemId) throws IOException, SAXException {
225         parseConfiguration();
226     }
227 
228     /**
229      * Parses the configuration object and generates SAX events. This is the main processing method.
230      *
231      * @throws IOException if no configuration has been specified
232      * @throws SAXException if an error occurs during parsing
233      */
234     protected void parseConfiguration() throws IOException, SAXException {
235         if (getParsedConfiguration() == null) {
236             throw new IOException("No configuration specified!");
237         }
238 
239         if (getContentHandler() != null) {
240             exception = null;
241             getContentHandler().startDocument();
242             processKeys();
243             if (getException() != null) {
244                 throw getException();
245             }
246             getContentHandler().endDocument();
247         }
248     }
249 
250     /**
251      * Processes all keys stored in the actual configuration. This method is called by {@code parseConfiguration()} to start
252      * the main parsing process. {@code parseConfiguration()} calls the content handler's {@code startDocument()} and
253      * {@code endElement()} methods and cares for exception handling. The remaining actions are left to this method that
254      * must be implemented in a concrete sub class.
255      *
256      * @throws IOException if an IO error occurs
257      * @throws SAXException if a SAX error occurs
258      */
259     protected abstract void processKeys() throws IOException, SAXException;
260 
261     /**
262      * Sets the content handler. The object specified here will receive SAX events during parsing.
263      *
264      * @param handler the content handler
265      */
266     @Override
267     public void setContentHandler(final ContentHandler handler) {
268         contentHandler = handler;
269     }
270 
271     /**
272      * Sets the DTD handler. The passed value is ignored.
273      *
274      * @param handler the handler to be set
275      */
276     @Override
277     public void setDTDHandler(final DTDHandler handler) {
278     }
279 
280     /**
281      * Sets the entity resolver. The passed value is ignored.
282      *
283      * @param resolver the entity resolver
284      */
285     @Override
286     public void setEntityResolver(final EntityResolver resolver) {
287     }
288 
289     /**
290      * Sets the error handler. The passed value is ignored.
291      *
292      * @param handler the error handler
293      */
294     @Override
295     public void setErrorHandler(final ErrorHandler handler) {
296     }
297 
298     /**
299      * Dummy implementation of the interface method.
300      *
301      * @param name the name of the feature to be set
302      * @param value the value of the feature
303      */
304     @Override
305     public void setFeature(final String name, final boolean value) {
306     }
307 
308     /**
309      * Dummy implementation of the interface method. No properties are supported, so a call of this method just has no
310      * effect.
311      *
312      * @param name the property name
313      * @param value the property value
314      */
315     @Override
316     public void setProperty(final String name, final Object value) {
317     }
318 
319     /**
320      * Sets the name for the root element.
321      *
322      * @param string the name for the root element.
323      */
324     public void setRootName(final String string) {
325         rootName = string;
326     }
327 }