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