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 xni.parser; 19 20 import java.io.FileInputStream; 21 import java.io.IOException; 22 import java.io.InputStream; 23 import java.net.MalformedURLException; 24 import java.net.URL; 25 import java.util.Hashtable; 26 import java.util.Locale; 27 import java.util.Vector; 28 29 import org.apache.xerces.xni.XMLDTDContentModelHandler; 30 import org.apache.xerces.xni.XMLDTDHandler; 31 import org.apache.xerces.xni.XMLDocumentHandler; 32 import org.apache.xerces.xni.XNIException; 33 import org.apache.xerces.xni.parser.XMLComponent; 34 import org.apache.xerces.xni.parser.XMLConfigurationException; 35 import org.apache.xerces.xni.parser.XMLEntityResolver; 36 import org.apache.xerces.xni.parser.XMLErrorHandler; 37 import org.apache.xerces.xni.parser.XMLInputSource; 38 import org.apache.xerces.xni.parser.XMLParserConfiguration; 39 40 /** 41 * This abstract parser configuration simply helps manage components, 42 * features and properties, and other tasks common to all parser 43 * configurations. In order to subclass this configuration and use 44 * it effectively, the subclass is required to do the following: 45 * <ul> 46 * <li> 47 * Add all configurable components using the <code>addComponent</code> 48 * method,</li> 49 * <li>Implement the <code>parse</code> method, and</li> 50 * <li>Call the <code>resetComponents</code> before parsing.</li> 51 * </ul> 52 * 53 * @author Andy Clark, IBM 54 * 55 * @version $Id: AbstractConfiguration.java 699895 2008-09-28 21:21:24Z mrglavas $ 56 */ 57 public abstract class AbstractConfiguration 58 implements XMLParserConfiguration { 59 60 // 61 // Data 62 // 63 64 // features and properties 65 66 /** Recognized features. */ 67 protected final Vector fRecognizedFeatures = new Vector(); 68 69 /** Recognized properties. */ 70 protected final Vector fRecognizedProperties = new Vector(); 71 72 /** Features. */ 73 protected final Hashtable fFeatures = new Hashtable(); 74 75 /** Properties. */ 76 protected final Hashtable fProperties = new Hashtable(); 77 78 // other parser configuration fields 79 80 /** The registered entity resolver. */ 81 protected XMLEntityResolver fEntityResolver; 82 83 /** The registered error handler. */ 84 protected XMLErrorHandler fErrorHandler; 85 86 /** The registered document handler. */ 87 protected XMLDocumentHandler fDocumentHandler; 88 89 /** The registered DTD handler. */ 90 protected XMLDTDHandler fDTDHandler; 91 92 /** The registered DTD content model handler. */ 93 protected XMLDTDContentModelHandler fDTDContentModelHandler; 94 95 /** Locale for error messages. */ 96 protected Locale fLocale; 97 98 // components 99 100 /** List of configurable components. */ 101 protected final Vector fComponents = new Vector(); 102 103 // 104 // XMLParserConfiguration methods 105 // 106 107 /** 108 * Allows a parser to add parser specific features to be recognized 109 * and managed by the parser configuration. 110 * 111 * @param featureIds An array of the additional feature identifiers 112 * to be recognized. 113 */ addRecognizedFeatures(String[] featureIds)114 public void addRecognizedFeatures(String[] featureIds) { 115 int length = featureIds != null ? featureIds.length : 0; 116 for (int i = 0; i < length; i++) { 117 String featureId = featureIds[i]; 118 if (!fRecognizedFeatures.contains(featureId)) { 119 fRecognizedFeatures.addElement(featureId); 120 } 121 } 122 } // addRecognizedFeatures(String[]) 123 124 /** 125 * Sets the state of a feature. This method is called by the parser 126 * and gets propagated to components in this parser configuration. 127 * 128 * @param featureId The feature identifier. 129 * @param state The state of the feature. 130 * 131 * @throws XMLConfigurationException Thrown if there is a configuration 132 * error. 133 */ setFeature(String featureId, boolean state)134 public void setFeature(String featureId, boolean state) 135 throws XMLConfigurationException { 136 if (!fRecognizedFeatures.contains(featureId)) { 137 short type = XMLConfigurationException.NOT_RECOGNIZED; 138 throw new XMLConfigurationException(type, featureId); 139 } 140 fFeatures.put(featureId, state ? Boolean.TRUE : Boolean.FALSE); 141 int length = fComponents.size(); 142 for (int i = 0; i < length; i++) { 143 XMLComponent component = (XMLComponent)fComponents.elementAt(i); 144 component.setFeature(featureId, state); 145 } 146 } // setFeature(String,boolean) 147 148 /** 149 * Returns the state of a feature. 150 * 151 * @param featureId The feature identifier. 152 * 153 * @throws XMLConfigurationException Thrown if there is a configuration 154 * error. 155 */ getFeature(String featureId)156 public boolean getFeature(String featureId) 157 throws XMLConfigurationException { 158 if (!fRecognizedFeatures.contains(featureId)) { 159 short type = XMLConfigurationException.NOT_RECOGNIZED; 160 throw new XMLConfigurationException(type, featureId); 161 } 162 Boolean state = (Boolean)fFeatures.get(featureId); 163 return state != null ? state.booleanValue() : false; 164 } // getFeature(String):boolean 165 166 /** 167 * Allows a parser to add parser specific properties to be recognized 168 * and managed by the parser configuration. 169 * 170 * @param propertyIds An array of the additional property identifiers 171 * to be recognized. 172 */ addRecognizedProperties(String[] propertyIds)173 public void addRecognizedProperties(String[] propertyIds) { 174 int length = propertyIds != null ? propertyIds.length : 0; 175 for (int i = 0; i < length; i++) { 176 String propertyId = propertyIds[i]; 177 if (!fRecognizedProperties.contains(propertyId)) { 178 fRecognizedProperties.addElement(propertyId); 179 } 180 } 181 } // addRecognizedProperties(String[]) 182 183 /** 184 * Sets the value of a property. This method is called by the parser 185 * and gets propagated to components in this parser configuration. 186 * 187 * @param propertyId The property identifier. 188 * @param value The value of the property. 189 * 190 * @throws XMLConfigurationException Thrown if there is a configuration 191 * error. 192 */ setProperty(String propertyId, Object value)193 public void setProperty(String propertyId, Object value) 194 throws XMLConfigurationException { 195 if (!fRecognizedProperties.contains(propertyId)) { 196 short type = XMLConfigurationException.NOT_RECOGNIZED; 197 throw new XMLConfigurationException(type, propertyId); 198 } 199 if (value != null) { 200 fProperties.put(propertyId, value); 201 } 202 else { 203 fProperties.remove(propertyId); 204 } 205 int length = fComponents.size(); 206 for (int i = 0; i < length; i++) { 207 XMLComponent component = (XMLComponent)fComponents.elementAt(i); 208 component.setProperty(propertyId, value); 209 } 210 } // setProperty(String,Object) 211 212 /** 213 * Returns the value of a property. 214 * 215 * @param propertyId The property identifier. 216 * 217 * @throws XMLConfigurationException Thrown if there is a configuration 218 * error. 219 */ getProperty(String propertyId)220 public Object getProperty(String propertyId) 221 throws XMLConfigurationException { 222 if (!fRecognizedProperties.contains(propertyId)) { 223 short type = XMLConfigurationException.NOT_RECOGNIZED; 224 throw new XMLConfigurationException(type, propertyId); 225 } 226 Object value = fProperties.get(propertyId); 227 return value; 228 } // getProperty(String):Object 229 230 /** 231 * Sets the entity resolver. 232 * 233 * @param resolver The new entity resolver. 234 */ setEntityResolver(XMLEntityResolver resolver)235 public void setEntityResolver(XMLEntityResolver resolver) { 236 fEntityResolver = resolver; 237 } // setEntityResolver(XMLEntityResolver) 238 239 /** Returns the registered entity resolver. */ getEntityResolver()240 public XMLEntityResolver getEntityResolver() { 241 return fEntityResolver; 242 } // getEntityResolver():XMLEntityResolver 243 244 /** 245 * Sets the error handler. 246 * 247 * @param handler The error resolver. 248 */ setErrorHandler(XMLErrorHandler handler)249 public void setErrorHandler(XMLErrorHandler handler) { 250 fErrorHandler = handler; 251 } // setErrorHandler(XMLErrorHandler) 252 253 /** Returns the registered error handler. */ getErrorHandler()254 public XMLErrorHandler getErrorHandler() { 255 return fErrorHandler; 256 } // getErrorHandler():XMLErrorHandler 257 258 /** 259 * Sets the document handler to receive information about the document. 260 * 261 * @param handler The document handler. 262 */ setDocumentHandler(XMLDocumentHandler handler)263 public void setDocumentHandler(XMLDocumentHandler handler) { 264 fDocumentHandler = handler; 265 } // setDocumentHandler(XMLDocumentHandler) 266 267 /** Returns the registered document handler. */ getDocumentHandler()268 public XMLDocumentHandler getDocumentHandler() { 269 return fDocumentHandler; 270 } // getDocumentHandler():XMLDocumentHandler 271 272 /** 273 * Sets the DTD handler. 274 * 275 * @param handler The DTD handler. 276 */ setDTDHandler(XMLDTDHandler handler)277 public void setDTDHandler(XMLDTDHandler handler) { 278 fDTDHandler = handler; 279 } // setDTDHandler(XMLDTDHandler) 280 281 /** Returns the registered DTD handler. */ getDTDHandler()282 public XMLDTDHandler getDTDHandler() { 283 return fDTDHandler; 284 } // getDTDHandler():XMLDTDHandler 285 286 /** 287 * Sets the DTD content model handler. 288 * 289 * @param handler The DTD content model handler. 290 */ setDTDContentModelHandler(XMLDTDContentModelHandler handler)291 public void setDTDContentModelHandler(XMLDTDContentModelHandler handler) { 292 fDTDContentModelHandler = handler; 293 } // setDTDContentModelHandler(XMLDTDContentModelHandler) 294 295 /** Returns the registered DTD content model handler. */ getDTDContentModelHandler()296 public XMLDTDContentModelHandler getDTDContentModelHandler() { 297 return fDTDContentModelHandler; 298 } // getDTDContentModelHandler():XMLDTDContentModelHandler 299 300 /** 301 * Parse an XML document. 302 * <p> 303 * The parser can use this method to instruct this configuration 304 * to begin parsing an XML document from any valid input source 305 * (a character stream, a byte stream, or a URI). 306 * <p> 307 * Parsers may not invoke this method while a parse is in progress. 308 * Once a parse is complete, the parser may then parse another XML 309 * document. 310 * <p> 311 * This method is synchronous: it will not return until parsing 312 * has ended. If a client application wants to terminate 313 * parsing early, it should throw an exception. 314 * <p> 315 * <strong>Note:</strong> This method needs to be implemented 316 * by the subclass. 317 * 318 * @param source The input source for the top-level of the 319 * XML document. 320 * 321 * @exception XNIException Any XNI exception, possibly wrapping 322 * another exception. 323 * @exception IOException An IO exception from the parser, possibly 324 * from a byte stream or character stream 325 * supplied by the parser. 326 */ parse(XMLInputSource inputSource)327 public abstract void parse(XMLInputSource inputSource) 328 throws IOException, XNIException; 329 330 /** 331 * Set the locale to use for messages. 332 * 333 * @param locale The locale object to use for localization of messages. 334 * 335 * @exception XNIException Thrown if the parser does not support the 336 * specified locale. 337 */ setLocale(Locale locale)338 public void setLocale(Locale locale) { 339 fLocale = locale; 340 } // setLocale(Locale) 341 342 343 /** Returns the locale. */ getLocale()344 public Locale getLocale() { 345 return fLocale; 346 } // getLocale():Locale 347 348 // 349 // Protected methods 350 // 351 352 /** 353 * Adds a component to list of configurable components. If the 354 * same component is added multiple times, the component is 355 * added only the first time. 356 * <p> 357 * This method helps manage the components in the configuration. 358 * Therefore, all subclasses should call this method to add the 359 * components specific to the configuration. 360 * 361 * @param component The component to add. 362 * 363 * @see #resetComponents 364 */ addComponent(XMLComponent component)365 protected void addComponent(XMLComponent component) { 366 if (!fComponents.contains(component)) { 367 fComponents.addElement(component); 368 addRecognizedFeatures(component.getRecognizedFeatures()); 369 addRecognizedProperties(component.getRecognizedProperties()); 370 } 371 } // addComponent(XMLComponent) 372 373 /** 374 * Resets all of the registered components. Before the subclassed 375 * configuration begins parsing, it should call this method to 376 * reset the components. 377 * 378 * @see #addComponent 379 */ resetComponents()380 protected void resetComponents() 381 throws XMLConfigurationException { 382 int length = fComponents.size(); 383 for (int i = 0; i < length; i++) { 384 XMLComponent component = (XMLComponent)fComponents.elementAt(i); 385 component.reset(this); 386 } 387 } // resetComponents() 388 389 /** 390 * This method tries to open the necessary stream for the given 391 * XMLInputSource. If the input source already has a character 392 * stream (java.io.Reader) or a byte stream (java.io.InputStream) 393 * set, this method returns immediately. However, if no character 394 * or byte stream is already open, this method attempts to open 395 * an input stream using the source's system identifier. 396 * 397 * @param source The input source to open. 398 */ openInputSourceStream(XMLInputSource source)399 protected void openInputSourceStream(XMLInputSource source) 400 throws IOException { 401 if (source.getCharacterStream() != null) { 402 return; 403 } 404 InputStream stream = source.getByteStream(); 405 if (stream == null) { 406 String systemId = source.getSystemId(); 407 try { 408 URL url = new URL(systemId); 409 stream = url.openStream(); 410 } 411 catch (MalformedURLException e) { 412 stream = new FileInputStream(systemId); 413 } 414 source.setByteStream(stream); 415 } 416 } // openInputSourceStream(XMLInputSource) 417 418 } // class AbstractConfiguration 419