1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Copyright 2001-2004 The Apache Software Foundation. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 21 package com.sun.org.apache.xerces.internal.parsers; 22 23 import java.io.IOException; 24 import java.util.ArrayList; 25 import java.util.HashMap; 26 import java.util.Locale; 27 28 import com.sun.org.apache.xerces.internal.impl.Constants; 29 import com.sun.org.apache.xerces.internal.util.FeatureState; 30 import com.sun.org.apache.xerces.internal.util.ParserConfigurationSettings; 31 import com.sun.org.apache.xerces.internal.util.PropertyState; 32 import com.sun.org.apache.xerces.internal.util.Status; 33 import com.sun.org.apache.xerces.internal.util.SymbolTable; 34 import com.sun.org.apache.xerces.internal.xni.XMLDTDContentModelHandler; 35 import com.sun.org.apache.xerces.internal.xni.XMLDTDHandler; 36 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler; 37 import com.sun.org.apache.xerces.internal.xni.XNIException; 38 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent; 39 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager; 40 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException; 41 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource; 42 import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver; 43 import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler; 44 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource; 45 import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration; 46 47 /** 48 * A very basic parser configuration. This configuration class can 49 * be used as a base class for custom parser configurations. The 50 * basic parser configuration creates the symbol table (if not 51 * specified at construction time) and manages all of the recognized 52 * features and properties. 53 * <p> 54 * The basic parser configuration does <strong>not</strong> mandate 55 * any particular pipeline configuration or the use of specific 56 * components except for the symbol table. If even this is too much 57 * for a basic parser configuration, the programmer can create a new 58 * configuration class that implements the 59 * <code>XMLParserConfiguration</code> interface. 60 * <p> 61 * Subclasses of the basic parser configuration can add their own 62 * recognized features and properties by calling the 63 * <code>addRecognizedFeature</code> and 64 * <code>addRecognizedProperty</code> methods, respectively. 65 * <p> 66 * The basic parser configuration assumes that the configuration 67 * will be made up of various parser components that implement the 68 * <code>XMLComponent</code> interface. If subclasses of this 69 * configuration create their own components for use in the 70 * parser configuration, then each component should be added to 71 * the list of components by calling the <code>addComponent</code> 72 * method. The basic parser configuration will make sure to call 73 * the <code>reset</code> method of each registered component 74 * before parsing an instance document. 75 * <p> 76 * This class recognizes the following features and properties: 77 * <ul> 78 * <li>Features 79 * <ul> 80 * <li>http://xml.org/sax/features/validation</li> 81 * <li>http://xml.org/sax/features/namespaces</li> 82 * <li>http://xml.org/sax/features/external-general-entities</li> 83 * <li>http://xml.org/sax/features/external-parameter-entities</li> 84 * </ul> 85 * <li>Properties 86 * <ul> 87 * <li>http://xml.org/sax/properties/xml-string</li> 88 * <li>http://apache.org/xml/properties/internal/symbol-table</li> 89 * <li>http://apache.org/xml/properties/internal/error-handler</li> 90 * <li>http://apache.org/xml/properties/internal/entity-resolver</li> 91 * </ul> 92 * </ul> 93 * 94 * @author Arnaud Le Hors, IBM 95 * @author Andy Clark, IBM 96 * 97 * @version $Id: BasicParserConfiguration.java,v 1.6 2010-11-01 04:40:09 joehw Exp $ 98 */ 99 public abstract class BasicParserConfiguration 100 extends ParserConfigurationSettings 101 implements XMLParserConfiguration { 102 103 // 104 // Constants 105 // 106 107 // feature identifiers 108 109 /** Feature identifier: validation. */ 110 protected static final String VALIDATION = 111 Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; 112 113 /** Feature identifier: namespaces. */ 114 protected static final String NAMESPACES = 115 Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; 116 117 /** Feature identifier: external general entities. */ 118 protected static final String EXTERNAL_GENERAL_ENTITIES = 119 Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_GENERAL_ENTITIES_FEATURE; 120 121 /** Feature identifier: external parameter entities. */ 122 protected static final String EXTERNAL_PARAMETER_ENTITIES = 123 Constants.SAX_FEATURE_PREFIX + Constants.EXTERNAL_PARAMETER_ENTITIES_FEATURE; 124 125 // property identifiers 126 127 /** Property identifier: xml string. */ 128 protected static final String XML_STRING = 129 Constants.SAX_PROPERTY_PREFIX + Constants.XML_STRING_PROPERTY; 130 131 /** Property identifier: symbol table. */ 132 protected static final String SYMBOL_TABLE = 133 Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; 134 135 /** Property identifier: error handler. */ 136 protected static final String ERROR_HANDLER = 137 Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY; 138 139 /** Property identifier: entity resolver. */ 140 protected static final String ENTITY_RESOLVER = 141 Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY; 142 143 // 144 // Data 145 // 146 147 // components (non-configurable) 148 149 /** Symbol table. */ 150 protected SymbolTable fSymbolTable; 151 152 153 // data 154 155 /** Locale. */ 156 protected Locale fLocale; 157 158 /** Components. */ 159 protected ArrayList fComponents; 160 161 // handlers 162 163 /** The document handler. */ 164 protected XMLDocumentHandler fDocumentHandler; 165 166 /** The DTD handler. */ 167 protected XMLDTDHandler fDTDHandler; 168 169 /** The DTD content model handler. */ 170 protected XMLDTDContentModelHandler fDTDContentModelHandler; 171 172 /** Last component in the document pipeline */ 173 protected XMLDocumentSource fLastComponent; 174 175 // 176 // Constructors 177 // 178 179 /** Default Constructor. */ 180 protected BasicParserConfiguration() { 181 this(null, null); 182 } // <init>() 183 184 /** 185 * Constructs a parser configuration using the specified symbol table. 186 * 187 * @param symbolTable The symbol table to use. 188 */ 189 protected BasicParserConfiguration(SymbolTable symbolTable) { 190 this(symbolTable, null); 191 } // <init>(SymbolTable) 192 193 /** 194 * Constructs a parser configuration using the specified symbol table 195 * and parent settings. 196 * 197 * @param symbolTable The symbol table to use. 198 * @param parentSettings The parent settings. 199 */ 200 protected BasicParserConfiguration(SymbolTable symbolTable, 201 XMLComponentManager parentSettings) { 202 super(parentSettings); 203 204 // create a vector to hold all the components in use 205 fComponents = new ArrayList(); 206 207 // create table for features and properties 208 fFeatures = new HashMap(); 209 fProperties = new HashMap(); 210 211 // add default recognized features 212 final String[] recognizedFeatures = { 213 PARSER_SETTINGS, 214 VALIDATION, 215 NAMESPACES, 216 EXTERNAL_GENERAL_ENTITIES, 217 EXTERNAL_PARAMETER_ENTITIES, 218 }; 219 addRecognizedFeatures(recognizedFeatures); 220 fFeatures.put(PARSER_SETTINGS, Boolean.TRUE); 221 // set state for default features 222 fFeatures.put(VALIDATION, Boolean.FALSE); 223 fFeatures.put(NAMESPACES, Boolean.TRUE); 224 fFeatures.put(EXTERNAL_GENERAL_ENTITIES, Boolean.TRUE); 225 fFeatures.put(EXTERNAL_PARAMETER_ENTITIES, Boolean.TRUE); 226 227 // add default recognized properties 228 final String[] recognizedProperties = { 229 XML_STRING, 230 SYMBOL_TABLE, 231 ERROR_HANDLER, 232 ENTITY_RESOLVER, 233 }; 234 addRecognizedProperties(recognizedProperties); 235 236 if (symbolTable == null) { 237 symbolTable = new SymbolTable(); 238 } 239 fSymbolTable = symbolTable; 240 fProperties.put(SYMBOL_TABLE, fSymbolTable); 241 242 } // <init>(SymbolTable) 243 244 /** 245 * Adds a component to the parser configuration. This method will 246 * also add all of the component's recognized features and properties 247 * to the list of default recognized features and properties. 248 * 249 * @param component The component to add. 250 */ 251 protected void addComponent(XMLComponent component) { 252 253 // don't add a component more than once 254 if (fComponents.contains(component)) { 255 return; 256 } 257 fComponents.add(component); 258 259 // register component's recognized features 260 String[] recognizedFeatures = component.getRecognizedFeatures(); 261 addRecognizedFeatures(recognizedFeatures); 262 263 // register component's recognized properties 264 String[] recognizedProperties = component.getRecognizedProperties(); 265 addRecognizedProperties(recognizedProperties); 266 267 // set default values 268 if (recognizedFeatures != null) { 269 for (int i = 0; i < recognizedFeatures.length; i++) { 270 String featureId = recognizedFeatures[i]; 271 Boolean state = component.getFeatureDefault(featureId); 272 if (state != null) { 273 super.setFeature(featureId, state.booleanValue()); 274 } 275 } 276 } 277 if (recognizedProperties != null) { 278 for (int i = 0; i < recognizedProperties.length; i++) { 279 String propertyId = recognizedProperties[i]; 280 Object value = component.getPropertyDefault(propertyId); 281 if (value != null) { 282 super.setProperty(propertyId, value); 283 } 284 } 285 } 286 287 } // addComponent(XMLComponent) 288 289 // 290 // XMLParserConfiguration methods 291 // 292 293 /** 294 * Parse an XML document. 295 * <p> 296 * The parser can use this method to instruct this configuration 297 * to begin parsing an XML document from any valid input source 298 * (a character stream, a byte stream, or a URI). 299 * <p> 300 * Parsers may not invoke this method while a parse is in progress. 301 * Once a parse is complete, the parser may then parse another XML 302 * document. 303 * <p> 304 * This method is synchronous: it will not return until parsing 305 * has ended. If a client application wants to terminate 306 * parsing early, it should throw an exception. 307 * 308 * @param inputSource The input source for the top-level of the 309 * XML document. 310 * 311 * @exception XNIException Any XNI exception, possibly wrapping 312 * another exception. 313 * @exception IOException An IO exception from the parser, possibly 314 * from a byte stream or character stream 315 * supplied by the parser. 316 */ 317 public abstract void parse(XMLInputSource inputSource) 318 throws XNIException, IOException; 319 320 /** 321 * Sets the document handler on the last component in the pipeline 322 * to receive information about the document. 323 * 324 * @param documentHandler The document handler. 325 */ 326 public void setDocumentHandler(XMLDocumentHandler documentHandler) { 327 fDocumentHandler = documentHandler; 328 if (fLastComponent != null) { 329 fLastComponent.setDocumentHandler(fDocumentHandler); 330 if (fDocumentHandler !=null){ 331 fDocumentHandler.setDocumentSource(fLastComponent); 332 } 333 } 334 } // setDocumentHandler(XMLDocumentHandler) 335 336 /** Returns the registered document handler. */ 337 public XMLDocumentHandler getDocumentHandler() { 338 return fDocumentHandler; 339 } // getDocumentHandler():XMLDocumentHandler 340 341 /** 342 * Sets the DTD handler. 343 * 344 * @param dtdHandler The DTD handler. 345 */ 346 public void setDTDHandler(XMLDTDHandler dtdHandler) { 347 fDTDHandler = dtdHandler; 348 } // setDTDHandler(XMLDTDHandler) 349 350 /** Returns the registered DTD handler. */ 351 public XMLDTDHandler getDTDHandler() { 352 return fDTDHandler; 353 } // getDTDHandler():XMLDTDHandler 354 355 /** 356 * Sets the DTD content model handler. 357 * 358 * @param handler The DTD content model handler. 359 */ 360 public void setDTDContentModelHandler(XMLDTDContentModelHandler handler) { 361 fDTDContentModelHandler = handler; 362 } // setDTDContentModelHandler(XMLDTDContentModelHandler) 363 364 /** Returns the registered DTD content model handler. */ 365 public XMLDTDContentModelHandler getDTDContentModelHandler() { 366 return fDTDContentModelHandler; 367 } // getDTDContentModelHandler():XMLDTDContentModelHandler 368 369 /** 370 * Sets the resolver used to resolve external entities. The EntityResolver 371 * interface supports resolution of public and system identifiers. 372 * 373 * @param resolver The new entity resolver. Passing a null value will 374 * uninstall the currently installed resolver. 375 */ 376 public void setEntityResolver(XMLEntityResolver resolver) { 377 // REVISIT: Should this be a property? 378 fProperties.put(ENTITY_RESOLVER, resolver); 379 } // setEntityResolver(XMLEntityResolver) 380 381 /** 382 * Return the current entity resolver. 383 * 384 * @return The current entity resolver, or null if none 385 * has been registered. 386 * @see #setEntityResolver 387 */ 388 public XMLEntityResolver getEntityResolver() { 389 // REVISIT: Should this be a property? 390 return (XMLEntityResolver)fProperties.get(ENTITY_RESOLVER); 391 } // getEntityResolver():XMLEntityResolver 392 393 /** 394 * Allow an application to register an error event handler. 395 * 396 * <p>If the application does not register an error handler, all 397 * error events reported by the SAX parser will be silently 398 * ignored; however, normal processing may not continue. It is 399 * highly recommended that all SAX applications implement an 400 * error handler to avoid unexpected bugs.</p> 401 * 402 * <p>Applications may register a new or different handler in the 403 * middle of a parse, and the SAX parser must begin using the new 404 * handler immediately.</p> 405 * 406 * @param errorHandler The error handler. 407 * @exception java.lang.NullPointerException If the handler 408 * argument is null. 409 * @see #getErrorHandler 410 */ 411 public void setErrorHandler(XMLErrorHandler errorHandler) { 412 // REVISIT: Should this be a property? 413 fProperties.put(ERROR_HANDLER, errorHandler); 414 } // setErrorHandler(XMLErrorHandler) 415 416 /** 417 * Return the current error handler. 418 * 419 * @return The current error handler, or null if none 420 * has been registered. 421 * @see #setErrorHandler 422 */ 423 public XMLErrorHandler getErrorHandler() { 424 // REVISIT: Should this be a property? 425 return (XMLErrorHandler)fProperties.get(ERROR_HANDLER); 426 } // getErrorHandler():XMLErrorHandler 427 428 /** 429 * Set the state of a feature. 430 * 431 * Set the state of any feature in a SAX2 parser. The parser 432 * might not recognize the feature, and if it does recognize 433 * it, it might not be able to fulfill the request. 434 * 435 * @param featureId The unique identifier (URI) of the feature. 436 * @param state The requested state of the feature (true or false). 437 * 438 * @exception com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException If the 439 * requested feature is not known. 440 */ 441 public void setFeature(String featureId, boolean state) 442 throws XMLConfigurationException { 443 444 // forward to every component 445 int count = fComponents.size(); 446 for (int i = 0; i < count; i++) { 447 XMLComponent c = (XMLComponent) fComponents.get(i); 448 c.setFeature(featureId, state); 449 } 450 // save state if noone "objects" 451 super.setFeature(featureId, state); 452 453 } // setFeature(String,boolean) 454 455 /** 456 * setProperty 457 * 458 * @param propertyId 459 * @param value 460 */ 461 public void setProperty(String propertyId, Object value) 462 throws XMLConfigurationException { 463 464 // forward to every component 465 int count = fComponents.size(); 466 for (int i = 0; i < count; i++) { 467 XMLComponent c = (XMLComponent) fComponents.get(i); 468 c.setProperty(propertyId, value); 469 } 470 471 // store value if noone "objects" 472 super.setProperty(propertyId, value); 473 474 } // setProperty(String,Object) 475 476 /** 477 * Set the locale to use for messages. 478 * 479 * @param locale The locale object to use for localization of messages. 480 * 481 * @exception XNIException Thrown if the parser does not support the 482 * specified locale. 483 */ 484 public void setLocale(Locale locale) throws XNIException { 485 fLocale = locale; 486 } // setLocale(Locale) 487 488 /** Returns the locale. */ 489 public Locale getLocale() { 490 return fLocale; 491 } // getLocale():Locale 492 493 // 494 // Protected methods 495 // 496 497 /** 498 * reset all components before parsing and namespace context 499 */ 500 protected void reset() throws XNIException { 501 502 // reset every component 503 int count = fComponents.size(); 504 for (int i = 0; i < count; i++) { 505 XMLComponent c = (XMLComponent) fComponents.get(i); 506 c.reset(this); 507 } 508 509 } // reset() 510 511 /** 512 * Check a property. If the property is known and supported, this method 513 * simply returns. Otherwise, the appropriate exception is thrown. 514 * 515 * @param propertyId The unique identifier (URI) of the property 516 * being set. 517 * @exception com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException If the 518 * requested feature is not known or supported. 519 */ 520 protected PropertyState checkProperty(String propertyId) 521 throws XMLConfigurationException { 522 523 // special cases 524 if (propertyId.startsWith(Constants.SAX_PROPERTY_PREFIX)) { 525 final int suffixLength = propertyId.length() - Constants.SAX_PROPERTY_PREFIX.length(); 526 527 // 528 // http://xml.org/sax/properties/xml-string 529 // Value type: String 530 // Access: read-only 531 // Get the literal string of characters associated with the 532 // current event. If the parser recognises and supports this 533 // property but is not currently parsing text, it should return 534 // null (this is a good way to check for availability before the 535 // parse begins). 536 // 537 if (suffixLength == Constants.XML_STRING_PROPERTY.length() && 538 propertyId.endsWith(Constants.XML_STRING_PROPERTY)) { 539 // REVISIT - we should probably ask xml-dev for a precise 540 // definition of what this is actually supposed to return, and 541 // in exactly which circumstances. 542 return PropertyState.NOT_SUPPORTED; 543 } 544 } 545 546 // check property 547 return super.checkProperty(propertyId); 548 549 } // checkProperty(String) 550 551 552 /** 553 * Check a feature. If feature is know and supported, this method simply 554 * returns. Otherwise, the appropriate exception is thrown. 555 * 556 * @param featureId The unique identifier (URI) of the feature. 557 * 558 * @throws XMLConfigurationException Thrown for configuration error. 559 * In general, components should 560 * only throw this exception if 561 * it is <strong>really</strong> 562 * a critical error. 563 */ 564 protected FeatureState checkFeature(String featureId) 565 throws XMLConfigurationException { 566 567 // 568 // Xerces Features 569 // 570 if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) { 571 final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length(); 572 573 // 574 // special performance feature: no one by component manager is allowed to set it 575 // 576 if (suffixLength == Constants.PARSER_SETTINGS.length() && 577 featureId.endsWith(Constants.PARSER_SETTINGS)) { 578 return FeatureState.NOT_SUPPORTED; 579 } 580 } 581 582 return super.checkFeature(featureId); 583 } // checkFeature(String) 584 585 586 } // class BasicParserConfiguration