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 "faked" <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: /** Constant for the namespace URI.*/
045: protected static final String NS_URI = "";
046:
047: /** Constant for the default name of the root element.*/
048: private static final String DEFAULT_ROOT_NAME = "config";
049:
050: /** An empty attributes object.*/
051: private static final Attributes EMPTY_ATTRS = new AttributesImpl();
052:
053: /** Stores the content handler.*/
054: private ContentHandler contentHandler;
055:
056: /** Stores an exception that occurred during parsing.*/
057: private SAXException exception;
058:
059: /** Stores the name for the root element.*/
060: private String rootName;
061:
062: /**
063: * Creates a new instance of <code>ConfigurationXMLReader</code>.
064: */
065: protected ConfigurationXMLReader() {
066: super ();
067: setRootName(DEFAULT_ROOT_NAME);
068: }
069:
070: /**
071: * Parses the acutal configuration object. The passed system ID will be
072: * ignored.
073: *
074: * @param systemId the system ID (ignored)
075: * @throws IOException if no configuration was specified
076: * @throws SAXException if an error occurs during parsing
077: */
078: public void parse(String systemId) throws IOException, SAXException {
079: parseConfiguration();
080: }
081:
082: /**
083: * Parses the acutal configuration object. The passed input source will be
084: * ignored.
085: *
086: * @param input the input source (ignored)
087: * @throws IOException if no configuration was specified
088: * @throws SAXException if an error occurs during parsing
089: */
090: public void parse(InputSource input) throws IOException,
091: SAXException {
092: parseConfiguration();
093: }
094:
095: /**
096: * Dummy implementation of the interface method.
097: *
098: * @param name the name of the feature
099: * @return always <b>false</b> (no features are supported)
100: */
101: public boolean getFeature(String name) {
102: return false;
103: }
104:
105: /**
106: * Dummy implementation of the interface method.
107: *
108: * @param name the name of the feature to be set
109: * @param value the value of the feature
110: */
111: public void setFeature(String name, boolean value) {
112: }
113:
114: /**
115: * Returns the actually set content handler.
116: *
117: * @return the content handler
118: */
119: public ContentHandler getContentHandler() {
120: return contentHandler;
121: }
122:
123: /**
124: * Sets the content handler. The object specified here will receive SAX
125: * events during parsing.
126: *
127: * @param handler the content handler
128: */
129: public void setContentHandler(ContentHandler handler) {
130: contentHandler = handler;
131: }
132:
133: /**
134: * Returns the DTD handler. This class does not support DTD handlers,
135: * so this method always returns <b>null</b>.
136: *
137: * @return the DTD handler
138: */
139: public DTDHandler getDTDHandler() {
140: return null;
141: }
142:
143: /**
144: * Sets the DTD handler. The passed value is ignored.
145: *
146: * @param handler the handler to be set
147: */
148: public void setDTDHandler(DTDHandler handler) {
149: }
150:
151: /**
152: * Returns the entity resolver. This class does not support an entity
153: * resolver, so this method always returns <b>null</b>.
154: *
155: * @return the entity resolver
156: */
157: public EntityResolver getEntityResolver() {
158: return null;
159: }
160:
161: /**
162: * Sets the entity resolver. The passed value is ignored.
163: *
164: * @param resolver the entity resolver
165: */
166: public void setEntityResolver(EntityResolver resolver) {
167: }
168:
169: /**
170: * Returns the error handler. This class does not support an error handler,
171: * so this method always returns <b>null</b>.
172: *
173: * @return the error handler
174: */
175: public ErrorHandler getErrorHandler() {
176: return null;
177: }
178:
179: /**
180: * Sets the error handler. The passed value is ignored.
181: *
182: * @param handler the error handler
183: */
184: public void setErrorHandler(ErrorHandler handler) {
185: }
186:
187: /**
188: * Dummy implementation of the interface method. No properties are
189: * supported, so this method always returns <b>null</b>.
190: *
191: * @param name the name of the requested property
192: * @return the property value
193: */
194: public Object getProperty(String name) {
195: return null;
196: }
197:
198: /**
199: * Dummy implementation of the interface method. No properties are
200: * supported, so a call of this method just has no effect.
201: *
202: * @param name the property name
203: * @param value the property value
204: */
205: public void setProperty(String name, Object value) {
206: }
207:
208: /**
209: * Returns the name to be used for the root element.
210: *
211: * @return the name for the root element
212: */
213: public String getRootName() {
214: return rootName;
215: }
216:
217: /**
218: * Sets the name for the root element.
219: *
220: * @param string the name for the root element.
221: */
222: public void setRootName(String string) {
223: rootName = string;
224: }
225:
226: /**
227: * Fires a SAX element start event.
228: *
229: * @param name the name of the actual element
230: * @param attribs the attributes of this element (can be <b>null</b>)
231: */
232: protected void fireElementStart(String name, Attributes attribs) {
233: if (getException() == null) {
234: try {
235: Attributes at = (attribs == null) ? EMPTY_ATTRS
236: : attribs;
237: getContentHandler()
238: .startElement(NS_URI, name, name, at);
239: } catch (SAXException ex) {
240: exception = ex;
241: }
242: }
243: }
244:
245: /**
246: * Fires a SAX element end event.
247: *
248: * @param name the name of the affected element
249: */
250: protected void fireElementEnd(String name) {
251: if (getException() == null) {
252: try {
253: getContentHandler().endElement(NS_URI, name, name);
254: } catch (SAXException ex) {
255: exception = ex;
256: }
257: }
258: }
259:
260: /**
261: * Fires a SAX characters event.
262: *
263: * @param text the text
264: */
265: protected void fireCharacters(String text) {
266: if (getException() == null) {
267: try {
268: char[] ch = text.toCharArray();
269: getContentHandler().characters(ch, 0, ch.length);
270: } catch (SAXException ex) {
271: exception = ex;
272: }
273: }
274: }
275:
276: /**
277: * Returns a reference to an exception that occurred during parsing.
278: *
279: * @return a SAXExcpetion or <b>null</b> if none occurred
280: */
281: public SAXException getException() {
282: return exception;
283: }
284:
285: /**
286: * Parses the configuration object and generates SAX events. This is the
287: * main processing method.
288: *
289: * @throws IOException if no configuration has been specified
290: * @throws SAXException if an error occurs during parsing
291: */
292: protected void parseConfiguration() throws IOException,
293: SAXException {
294: if (getParsedConfiguration() == null) {
295: throw new IOException("No configuration specified!");
296: }
297:
298: if (getContentHandler() != null) {
299: exception = null;
300: getContentHandler().startDocument();
301: processKeys();
302: if (getException() != null) {
303: throw getException();
304: }
305: getContentHandler().endDocument();
306: }
307: }
308:
309: /**
310: * Returns a reference to the configuration that is parsed by this object.
311: *
312: * @return the parsed configuration
313: */
314: public abstract Configuration getParsedConfiguration();
315:
316: /**
317: * Processes all keys stored in the actual configuration. This method is
318: * called by <code>parseConfiguration()</code> to start the main parsing
319: * process. <code>parseConfiguration()</code> calls the content handler's
320: * <code>startDocument()</code> and <code>endElement()</code> methods
321: * and cares for exception handling. The remaining actions are left to this
322: * method that must be implemented in a concrete sub class.
323: *
324: * @throws IOException if an IO error occurs
325: * @throws SAXException if a SAX error occurs
326: */
327: protected abstract void processKeys() throws IOException,
328: SAXException;
329: }
|