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