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