1 /* 2 * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. 3 * @LastModified: Oct 2017 4 */ 5 /* 6 * Licensed to the Apache Software Foundation (ASF) under one or more 7 * contributor license agreements. See the NOTICE file distributed with 8 * this work for additional information regarding copyright ownership. 9 * The ASF licenses this file to You under the Apache License, Version 2.0 10 * (the "License"); you may not use this file except in compliance with 11 * the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22 package com.sun.org.apache.xerces.internal.parsers; 23 24 import com.sun.org.apache.xerces.internal.impl.Constants; 25 import com.sun.org.apache.xerces.internal.util.FeatureState; 26 import com.sun.org.apache.xerces.internal.util.ParserConfigurationSettings; 27 import com.sun.org.apache.xerces.internal.util.PropertyState; 28 import com.sun.org.apache.xerces.internal.util.Status; 29 import com.sun.org.apache.xerces.internal.util.SymbolTable; 30 import com.sun.org.apache.xerces.internal.xni.XMLDTDContentModelHandler; 31 import com.sun.org.apache.xerces.internal.xni.XMLDTDHandler; 32 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler; 33 import com.sun.org.apache.xerces.internal.xni.XNIException; 34 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent; 35 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager; 36 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException; 37 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource; 38 import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver; 39 import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler; 40 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource; 41 import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration; 42 import java.io.IOException; 43 import java.util.ArrayList; 44 import java.util.HashMap; 45 import java.util.List; 46 import java.util.Locale; 47 48 /** 49 * A very basic parser configuration. This configuration class can 50 * be used as a base class for custom parser configurations. The 51 * basic parser configuration creates the symbol table (if not 52 * specified at construction time) and manages all of the recognized 53 * features and properties. 54 * <p> 55 * The basic parser configuration does <strong>not</strong> mandate 56 * any particular pipeline configuration or the use of specific 57 * components except for the symbol table. If even this is too much 58 * for a basic parser configuration, the programmer can create a new 59 * configuration class that implements the 60 * <code>XMLParserConfiguration</code> interface. 61 * <p> 62 * Subclasses of the basic parser configuration can add their own 63 * recognized features and properties by calling the 64 * <code>addRecognizedFeature</code> and 65 * <code>addRecognizedProperty</code> methods, respectively. 66 * <p> 67 * The basic parser configuration assumes that the configuration 68 * will be made up of various parser components that implement the 69 * <code>XMLComponent</code> interface. If subclasses of this 70 * configuration create their own components for use in the 71 * parser configuration, then each component should be added to 72 * the list of components by calling the <code>addComponent</code> 73 * method. The basic parser configuration will make sure to call 74 * the <code>reset</code> method of each registered component 75 * before parsing an instance document. 76 * <p> 77 * This class recognizes the following features and properties: 78 * <ul> 79 * <li>Features 80 * <ul> 81 * <li>http://xml.org/sax/features/validation</li> 82 * <li>http://xml.org/sax/features/namespaces</li> 83 * <li>http://xml.org/sax/features/external-general-entities</li> 84 * <li>http://xml.org/sax/features/external-parameter-entities</li> 85 * </ul> 86 * <li>Properties 87 * <ul> 88 * <li>http://xml.org/sax/properties/xml-string</li> 89 * <li>http://apache.org/xml/properties/internal/symbol-table</li> 90 * <li>http://apache.org/xml/properties/internal/error-handler</li> 91 * <li>http://apache.org/xml/properties/internal/entity-resolver</li> 92 * </ul> 93 * </ul> 94 * 95 * @author Arnaud Le Hors, IBM 96 * @author Andy Clark, IBM 97 * 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 List<XMLComponent> 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 for (XMLComponent c : fComponents) { 446 c.setFeature(featureId, state); 447 } 448 // save state if noone "objects" 449 super.setFeature(featureId, state); 450 451 } // setFeature(String,boolean) 452 453 /** 454 * setProperty 455 * 456 * @param propertyId 457 * @param value 458 */ 459 public void setProperty(String propertyId, Object value) 460 throws XMLConfigurationException { 461 462 // forward to every component 463 for (XMLComponent c : fComponents) { 464 c.setProperty(propertyId, value); 465 } 466 467 // store value if noone "objects" 468 super.setProperty(propertyId, value); 469 470 } // setProperty(String,Object) 471 472 /** 473 * Set the locale to use for messages. 474 * 475 * @param locale The locale object to use for localization of messages. 476 * 477 * @exception XNIException Thrown if the parser does not support the 478 * specified locale. 479 */ 480 public void setLocale(Locale locale) throws XNIException { 481 fLocale = locale; 482 } // setLocale(Locale) 483 484 /** Returns the locale. */ 485 public Locale getLocale() { 486 return fLocale; 487 } // getLocale():Locale 488 489 // 490 // Protected methods 491 // 492 493 /** 494 * reset all components before parsing and namespace context 495 */ 496 protected void reset() throws XNIException { 497 // reset every component 498 for (XMLComponent c : fComponents) { 499 c.reset(this); 500 } 501 } // reset() 502 503 /** 504 * Check a property. If the property is known and supported, this method 505 * simply returns. Otherwise, the appropriate exception is thrown. 506 * 507 * @param propertyId The unique identifier (URI) of the property 508 * being set. 509 * @exception com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException If the 510 * requested feature is not known or supported. 511 */ 512 protected PropertyState checkProperty(String propertyId) 513 throws XMLConfigurationException { 514 515 // special cases 516 if (propertyId.startsWith(Constants.SAX_PROPERTY_PREFIX)) { 517 final int suffixLength = propertyId.length() - Constants.SAX_PROPERTY_PREFIX.length(); 518 519 // 520 // http://xml.org/sax/properties/xml-string 521 // Value type: String 522 // Access: read-only 523 // Get the literal string of characters associated with the 524 // current event. If the parser recognises and supports this 525 // property but is not currently parsing text, it should return 526 // null (this is a good way to check for availability before the 527 // parse begins). 528 // 529 if (suffixLength == Constants.XML_STRING_PROPERTY.length() && 530 propertyId.endsWith(Constants.XML_STRING_PROPERTY)) { 531 // REVISIT - we should probably ask xml-dev for a precise 532 // definition of what this is actually supposed to return, and 533 // in exactly which circumstances. 534 return PropertyState.NOT_SUPPORTED; 535 } 536 } 537 538 // check property 539 return super.checkProperty(propertyId); 540 541 } // checkProperty(String) 542 543 544 /** 545 * Check a feature. If feature is know and supported, this method simply 546 * returns. Otherwise, the appropriate exception is thrown. 547 * 548 * @param featureId The unique identifier (URI) of the feature. 549 * 550 * @throws XMLConfigurationException Thrown for configuration error. 551 * In general, components should 552 * only throw this exception if 553 * it is <strong>really</strong> 554 * a critical error. 555 */ 556 protected FeatureState checkFeature(String featureId) 557 throws XMLConfigurationException { 558 559 // 560 // Xerces Features 561 // 562 if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) { 563 final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length(); 564 565 // 566 // special performance feature: no one by component manager is allowed to set it 567 // 568 if (suffixLength == Constants.PARSER_SETTINGS.length() && 569 featureId.endsWith(Constants.PARSER_SETTINGS)) { 570 return FeatureState.NOT_SUPPORTED; 571 } 572 } 573 574 return super.checkFeature(featureId); 575 } // checkFeature(String) 576 577 578 } // class BasicParserConfiguration