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