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