1 /*
   2  * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  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.Locale;
  25 
  26 import com.sun.org.apache.xerces.internal.impl.Constants;
  27 import com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl;
  28 import com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl;
  29 import com.sun.org.apache.xerces.internal.impl.XMLEntityManager;
  30 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
  31 import com.sun.org.apache.xerces.internal.impl.XMLNamespaceBinder;
  32 import com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDProcessor;
  33 import com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator;
  34 import com.sun.org.apache.xerces.internal.impl.dv.DTDDVFactory;
  35 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter;
  36 import com.sun.org.apache.xerces.internal.impl.validation.ValidationManager;
  37 import com.sun.org.apache.xerces.internal.util.FeatureState;
  38 import com.sun.org.apache.xerces.internal.util.PropertyState;
  39 import com.sun.org.apache.xerces.internal.util.SymbolTable;
  40 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager;
  41 import com.sun.org.apache.xerces.internal.xni.XMLLocator;
  42 import com.sun.org.apache.xerces.internal.xni.XNIException;
  43 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool;
  44 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
  45 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
  46 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  47 import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDScanner;
  48 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentScanner;
  49 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
  50 import com.sun.org.apache.xerces.internal.xni.parser.XMLPullParserConfiguration;
  51 import javax.xml.XMLConstants;
  52 import javax.xml.catalog.CatalogFeatures;
  53 import jdk.xml.internal.JdkXmlUtils;
  54 
  55 /**
  56  * This is the DTD-only parser configuration.  It extends the basic
  57  * configuration with a standard set of parser components appropriate
  58  * to DTD-centric validation. Since
  59  * the Xerces2 reference implementation document and DTD scanner
  60  * implementations are capable of acting as pull parsers, this
  61  * configuration implements the
  62  * <code>XMLPullParserConfiguration</code> interface.
  63  * <p>
  64  * In addition to the features and properties recognized by the base
  65  * parser configuration, this class recognizes these additional
  66  * features and properties:
  67  * <ul>
  68  * <li>Features
  69  *  <ul>
  70  *   <li>http://apache.org/xml/features/validation/warn-on-duplicate-attdef</li>
  71  *   <li>http://apache.org/xml/features/validation/warn-on-undeclared-elemdef</li>
  72  *   <li>http://apache.org/xml/features/allow-java-encodings</li>
  73  *   <li>http://apache.org/xml/features/continue-after-fatal-error</li>
  74  *   <li>http://apache.org/xml/features/load-external-dtd</li>
  75  *  </ul>
  76  * <li>Properties
  77  *  <ul>
  78  *   <li>http://apache.org/xml/properties/internal/error-reporter</li>
  79  *   <li>http://apache.org/xml/properties/internal/entity-manager</li>
  80  *   <li>http://apache.org/xml/properties/internal/document-scanner</li>
  81  *   <li>http://apache.org/xml/properties/internal/dtd-scanner</li>
  82  *   <li>http://apache.org/xml/properties/internal/grammar-pool</li>
  83  *   <li>http://apache.org/xml/properties/internal/validator/dtd</li>
  84  *   <li>http://apache.org/xml/properties/internal/datatype-validator-factory</li>
  85  *  </ul>
  86  * </ul>
  87  *
  88  * @author Arnaud  Le Hors, IBM
  89  * @author Andy Clark, IBM
  90  * @author Neil Graham, IBM
  91  *
  92  */
  93 public class DTDConfiguration
  94     extends BasicParserConfiguration
  95     implements XMLPullParserConfiguration {
  96 
  97     //
  98     // Constants
  99     //
 100 
 101     // feature identifiers
 102 
 103     /** Feature identifier: warn on duplicate attribute definition. */
 104     protected static final String WARN_ON_DUPLICATE_ATTDEF =
 105         Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_DUPLICATE_ATTDEF_FEATURE;
 106 
 107     /** Feature identifier: warn on duplicate entity definition. */
 108     protected static final String WARN_ON_DUPLICATE_ENTITYDEF =
 109         Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_DUPLICATE_ENTITYDEF_FEATURE;
 110 
 111     /** Feature identifier: warn on undeclared element definition. */
 112     protected static final String WARN_ON_UNDECLARED_ELEMDEF =
 113         Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_UNDECLARED_ELEMDEF_FEATURE;
 114 
 115     /** Feature identifier: allow Java encodings. */
 116     protected static final String ALLOW_JAVA_ENCODINGS =
 117         Constants.XERCES_FEATURE_PREFIX + Constants.ALLOW_JAVA_ENCODINGS_FEATURE;
 118 
 119     /** Feature identifier: continue after fatal error. */
 120     protected static final String CONTINUE_AFTER_FATAL_ERROR =
 121         Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE;
 122 
 123     /** Feature identifier: load external DTD. */
 124     protected static final String LOAD_EXTERNAL_DTD =
 125         Constants.XERCES_FEATURE_PREFIX + Constants.LOAD_EXTERNAL_DTD_FEATURE;
 126 
 127     /** Feature identifier: notify built-in refereces. */
 128     protected static final String NOTIFY_BUILTIN_REFS =
 129         Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_BUILTIN_REFS_FEATURE;
 130 
 131     /** Feature identifier: notify character refereces. */
 132     protected static final String NOTIFY_CHAR_REFS =
 133         Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_CHAR_REFS_FEATURE;
 134 
 135 
 136     // property identifiers
 137 
 138     /** Property identifier: error reporter. */
 139     protected static final String ERROR_REPORTER =
 140         Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
 141 
 142     /** Property identifier: entity manager. */
 143     protected static final String ENTITY_MANAGER =
 144         Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
 145 
 146     /** Property identifier document scanner: */
 147     protected static final String DOCUMENT_SCANNER =
 148         Constants.XERCES_PROPERTY_PREFIX + Constants.DOCUMENT_SCANNER_PROPERTY;
 149 
 150     /** Property identifier: DTD scanner. */
 151     protected static final String DTD_SCANNER =
 152         Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_SCANNER_PROPERTY;
 153 
 154     /** Property identifier: grammar pool. */
 155     protected static final String XMLGRAMMAR_POOL =
 156         Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
 157 
 158     /** Property identifier: DTD loader. */
 159     protected static final String DTD_PROCESSOR =
 160         Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_PROCESSOR_PROPERTY;
 161 
 162     /** Property identifier: DTD validator. */
 163     protected static final String DTD_VALIDATOR =
 164         Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_VALIDATOR_PROPERTY;
 165 
 166     /** Property identifier: namespace binder. */
 167     protected static final String NAMESPACE_BINDER =
 168         Constants.XERCES_PROPERTY_PREFIX + Constants.NAMESPACE_BINDER_PROPERTY;
 169 
 170     /** Property identifier: datatype validator factory. */
 171     protected static final String DATATYPE_VALIDATOR_FACTORY =
 172         Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY;
 173 
 174     protected static final String VALIDATION_MANAGER =
 175         Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY;
 176 
 177     /** Property identifier: JAXP schema language / DOM schema-type. */
 178     protected static final String JAXP_SCHEMA_LANGUAGE =
 179         Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE;
 180 
 181     /** Property identifier: JAXP schema source/ DOM schema-location. */
 182     protected static final String JAXP_SCHEMA_SOURCE =
 183         Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE;
 184 
 185     /** Property identifier: locale. */
 186     protected static final String LOCALE =
 187         Constants.XERCES_PROPERTY_PREFIX + Constants.LOCALE_PROPERTY;
 188 
 189       /** Property identifier: Security property manager. */
 190       protected static final String XML_SECURITY_PROPERTY_MANAGER =
 191               Constants.XML_SECURITY_PROPERTY_MANAGER;
 192 
 193      /** Property identifier: Security manager. */
 194      private static final String SECURITY_MANAGER = Constants.SECURITY_MANAGER;
 195 
 196     // debugging
 197 
 198     /** Set to true and recompile to print exception stack trace. */
 199     protected static final boolean PRINT_EXCEPTION_STACK_TRACE = false;
 200 
 201     //
 202     // Data
 203     //
 204 
 205     // components (non-configurable)
 206 
 207     /** Grammar pool. */
 208     protected XMLGrammarPool fGrammarPool;
 209 
 210     /** Datatype validator factory. */
 211     protected DTDDVFactory fDatatypeValidatorFactory;
 212 
 213     // components (configurable)
 214 
 215     /** Error reporter. */
 216     protected XMLErrorReporter fErrorReporter;
 217 
 218     /** Entity manager. */
 219     protected XMLEntityManager fEntityManager;
 220 
 221     /** Document scanner. */
 222     protected XMLDocumentScanner fScanner;
 223 
 224     /** Input Source */
 225     protected XMLInputSource fInputSource;
 226 
 227     /** DTD scanner. */
 228     protected XMLDTDScanner fDTDScanner;
 229 
 230     /** DTD Processor . */
 231     protected XMLDTDProcessor fDTDProcessor;
 232 
 233     /** DTD Validator. */
 234     protected XMLDTDValidator fDTDValidator;
 235 
 236     /** Namespace binder. */
 237     protected XMLNamespaceBinder fNamespaceBinder;
 238 
 239     protected ValidationManager fValidationManager;
 240     // state
 241 
 242     /** Locator */
 243     protected XMLLocator fLocator;
 244 
 245     /**
 246      * True if a parse is in progress. This state is needed because
 247      * some features/properties cannot be set while parsing (e.g.
 248      * validation and namespaces).
 249      */
 250     protected boolean fParseInProgress = false;
 251 
 252     //
 253     // Constructors
 254     //
 255 
 256     /** Default constructor. */
 257     public DTDConfiguration() {
 258         this(null, null, null);
 259     } // <init>()
 260 
 261     /**
 262      * Constructs a parser configuration using the specified symbol table.
 263      *
 264      * @param symbolTable The symbol table to use.
 265      */
 266     public DTDConfiguration(SymbolTable symbolTable) {
 267         this(symbolTable, null, null);
 268     } // <init>(SymbolTable)
 269 
 270     /**
 271      * Constructs a parser configuration using the specified symbol table and
 272      * grammar pool.
 273      * <p>
 274      * <strong>REVISIT:</strong>
 275      * Grammar pool will be updated when the new validation engine is
 276      * implemented.
 277      *
 278      * @param symbolTable The symbol table to use.
 279      * @param grammarPool The grammar pool to use.
 280      */
 281     public DTDConfiguration(SymbolTable symbolTable,
 282                                        XMLGrammarPool grammarPool) {
 283         this(symbolTable, grammarPool, null);
 284     } // <init>(SymbolTable,XMLGrammarPool)
 285 
 286     /**
 287      * Constructs a parser configuration using the specified symbol table,
 288      * grammar pool, and parent settings.
 289      * <p>
 290      * <strong>REVISIT:</strong>
 291      * Grammar pool will be updated when the new validation engine is
 292      * implemented.
 293      *
 294      * @param symbolTable    The symbol table to use.
 295      * @param grammarPool    The grammar pool to use.
 296      * @param parentSettings The parent settings.
 297      */
 298     public DTDConfiguration(SymbolTable symbolTable,
 299                                        XMLGrammarPool grammarPool,
 300                                        XMLComponentManager parentSettings) {
 301         super(symbolTable, parentSettings);
 302 
 303         // add default recognized features
 304         final String[] recognizedFeatures = {
 305             //WARN_ON_DUPLICATE_ATTDEF,     // from XMLDTDScannerImpl
 306             //WARN_ON_UNDECLARED_ELEMDEF,   // from XMLDTDScannerImpl
 307             //ALLOW_JAVA_ENCODINGS,         // from XMLEntityManager
 308             CONTINUE_AFTER_FATAL_ERROR,
 309             LOAD_EXTERNAL_DTD,    // from XMLDTDScannerImpl
 310             //NOTIFY_BUILTIN_REFS,  // from XMLDocumentFragmentScannerImpl
 311             //NOTIFY_CHAR_REFS,         // from XMLDocumentFragmentScannerImpl
 312             //WARN_ON_DUPLICATE_ENTITYDEF,  // from XMLEntityManager
 313             XMLConstants.USE_CATALOG
 314         };
 315         addRecognizedFeatures(recognizedFeatures);
 316 
 317         // set state for default features
 318         //setFeature(WARN_ON_DUPLICATE_ATTDEF, false);  // from XMLDTDScannerImpl
 319         //setFeature(WARN_ON_UNDECLARED_ELEMDEF, false);  // from XMLDTDScannerImpl
 320         //setFeature(ALLOW_JAVA_ENCODINGS, false);      // from XMLEntityManager
 321         setFeature(CONTINUE_AFTER_FATAL_ERROR, false);
 322         setFeature(LOAD_EXTERNAL_DTD, true);      // from XMLDTDScannerImpl
 323         //setFeature(NOTIFY_BUILTIN_REFS, false);   // from XMLDocumentFragmentScannerImpl
 324         //setFeature(NOTIFY_CHAR_REFS, false);      // from XMLDocumentFragmentScannerImpl
 325         //setFeature(WARN_ON_DUPLICATE_ENTITYDEF, false);   // from XMLEntityManager
 326         fFeatures.put(XMLConstants.USE_CATALOG, JdkXmlUtils.USE_CATALOG_DEFAULT);
 327 
 328         // add default recognized properties
 329         final String[] recognizedProperties = {
 330             ERROR_REPORTER,
 331             ENTITY_MANAGER,
 332             DOCUMENT_SCANNER,
 333             DTD_SCANNER,
 334             DTD_PROCESSOR,
 335             DTD_VALIDATOR,
 336             NAMESPACE_BINDER,
 337             XMLGRAMMAR_POOL,
 338             DATATYPE_VALIDATOR_FACTORY,
 339             VALIDATION_MANAGER,
 340             JAXP_SCHEMA_SOURCE,
 341             JAXP_SCHEMA_LANGUAGE,
 342             LOCALE,
 343             SECURITY_MANAGER,
 344             XML_SECURITY_PROPERTY_MANAGER,
 345             JdkXmlUtils.CATALOG_DEFER,
 346             JdkXmlUtils.CATALOG_FILES,
 347             JdkXmlUtils.CATALOG_PREFER,
 348             JdkXmlUtils.CATALOG_RESOLVE
 349         };
 350         addRecognizedProperties(recognizedProperties);
 351 
 352         fGrammarPool = grammarPool;
 353         if(fGrammarPool != null){
 354             setProperty(XMLGRAMMAR_POOL, fGrammarPool);
 355         }
 356 
 357         fEntityManager = createEntityManager();
 358         setProperty(ENTITY_MANAGER, fEntityManager);
 359         addComponent(fEntityManager);
 360 
 361         fErrorReporter = createErrorReporter();
 362         fErrorReporter.setDocumentLocator(fEntityManager.getEntityScanner());
 363         setProperty(ERROR_REPORTER, fErrorReporter);
 364         addComponent(fErrorReporter);
 365 
 366         fScanner = createDocumentScanner();
 367         setProperty(DOCUMENT_SCANNER, fScanner);
 368         if (fScanner instanceof XMLComponent) {
 369             addComponent((XMLComponent)fScanner);
 370         }
 371 
 372         fDTDScanner = createDTDScanner();
 373         if (fDTDScanner != null) {
 374             setProperty(DTD_SCANNER, fDTDScanner);
 375             if (fDTDScanner instanceof XMLComponent) {
 376                 addComponent((XMLComponent)fDTDScanner);
 377             }
 378         }
 379 
 380         fDTDProcessor = createDTDProcessor();
 381         if (fDTDProcessor != null) {
 382             setProperty(DTD_PROCESSOR, fDTDProcessor);
 383             if (fDTDProcessor instanceof XMLComponent) {
 384                 addComponent((XMLComponent)fDTDProcessor);
 385             }
 386         }
 387 
 388         fDTDValidator = createDTDValidator();
 389         if (fDTDValidator != null) {
 390             setProperty(DTD_VALIDATOR, fDTDValidator);
 391             addComponent(fDTDValidator);
 392         }
 393 
 394         fNamespaceBinder = createNamespaceBinder();
 395         if (fNamespaceBinder != null) {
 396             setProperty(NAMESPACE_BINDER, fNamespaceBinder);
 397             addComponent(fNamespaceBinder);
 398         }
 399 
 400         fDatatypeValidatorFactory = createDatatypeValidatorFactory();
 401         if (fDatatypeValidatorFactory != null) {
 402             setProperty(DATATYPE_VALIDATOR_FACTORY,
 403                         fDatatypeValidatorFactory);
 404         }
 405         fValidationManager = createValidationManager();
 406 
 407         if (fValidationManager != null) {
 408             setProperty (VALIDATION_MANAGER, fValidationManager);
 409         }
 410         // add message formatters
 411         if (fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN) == null) {
 412             XMLMessageFormatter xmft = new XMLMessageFormatter();
 413             fErrorReporter.putMessageFormatter(XMLMessageFormatter.XML_DOMAIN, xmft);
 414             fErrorReporter.putMessageFormatter(XMLMessageFormatter.XMLNS_DOMAIN, xmft);
 415         }
 416 
 417         // set locale
 418         try {
 419             setLocale(Locale.getDefault());
 420         }
 421         catch (XNIException e) {
 422             // do nothing
 423             // REVISIT: What is the right thing to do? -Ac
 424         }
 425 
 426         setProperty(XML_SECURITY_PROPERTY_MANAGER, new XMLSecurityPropertyManager());
 427 
 428         // Initialize Catalog features
 429         for( CatalogFeatures.Feature f : CatalogFeatures.Feature.values()) {
 430             setProperty(f.getPropertyName(), null);
 431         }
 432     } // <init>(SymbolTable,XMLGrammarPool)
 433 
 434     //
 435     // Public methods
 436     //
 437 
 438     public PropertyState getPropertyState(String propertyId)
 439         throws XMLConfigurationException {
 440         if (LOCALE.equals(propertyId)) {
 441             return PropertyState.is(getLocale());
 442         }
 443         return super.getPropertyState(propertyId);
 444     }
 445 
 446     public void setProperty(String propertyId, Object value)
 447         throws XMLConfigurationException {
 448         if (LOCALE.equals(propertyId)) {
 449             setLocale((Locale) value);
 450         }
 451         super.setProperty(propertyId, value);
 452     }
 453 
 454     /**
 455      * Set the locale to use for messages.
 456      *
 457      * @param locale The locale object to use for localization of messages.
 458      *
 459      * @exception XNIException Thrown if the parser does not support the
 460      *                         specified locale.
 461      */
 462     public void setLocale(Locale locale) throws XNIException {
 463         super.setLocale(locale);
 464         fErrorReporter.setLocale(locale);
 465     } // setLocale(Locale)
 466 
 467     //
 468     // XMLPullParserConfiguration methods
 469     //
 470 
 471     // parsing
 472 
 473     /**
 474      * Sets the input source for the document to parse.
 475      *
 476      * @param inputSource The document's input source.
 477      *
 478      * @exception XMLConfigurationException Thrown if there is a
 479      *                        configuration error when initializing the
 480      *                        parser.
 481      * @exception IOException Thrown on I/O error.
 482      *
 483      * @see #parse(boolean)
 484      */
 485     public void setInputSource(XMLInputSource inputSource)
 486         throws XMLConfigurationException, IOException {
 487 
 488         // REVISIT: this method used to reset all the components and
 489         //          construct the pipeline. Now reset() is called
 490         //          in parse (boolean) just before we parse the document
 491         //          Should this method still throw exceptions..?
 492 
 493         fInputSource = inputSource;
 494 
 495     } // setInputSource(XMLInputSource)
 496 
 497     /**
 498      * Parses the document in a pull parsing fashion.
 499      *
 500      * @param complete True if the pull parser should parse the
 501      *                 remaining document completely.
 502      *
 503      * @return True if there is more document to parse.
 504      *
 505      * @exception XNIException Any XNI exception, possibly wrapping
 506      *                         another exception.
 507      * @exception IOException  An IO exception from the parser, possibly
 508      *                         from a byte stream or character stream
 509      *                         supplied by the parser.
 510      *
 511      * @see #setInputSource
 512      */
 513     public boolean parse(boolean complete) throws XNIException, IOException {
 514         //
 515         // reset and configure pipeline and set InputSource.
 516         if (fInputSource !=null) {
 517             try {
 518                 // resets and sets the pipeline.
 519                 reset();
 520                 fScanner.setInputSource(fInputSource);
 521                 fInputSource = null;
 522             }
 523             catch (XNIException ex) {
 524                 if (PRINT_EXCEPTION_STACK_TRACE)
 525                     ex.printStackTrace();
 526                 throw ex;
 527             }
 528             catch (IOException ex) {
 529                 if (PRINT_EXCEPTION_STACK_TRACE)
 530                     ex.printStackTrace();
 531                 throw ex;
 532             }
 533             catch (RuntimeException ex) {
 534                 if (PRINT_EXCEPTION_STACK_TRACE)
 535                     ex.printStackTrace();
 536                 throw ex;
 537             }
 538             catch (Exception ex) {
 539                 if (PRINT_EXCEPTION_STACK_TRACE)
 540                     ex.printStackTrace();
 541                 throw new XNIException(ex);
 542             }
 543         }
 544 
 545         try {
 546             return fScanner.scanDocument(complete);
 547         }
 548         catch (XNIException ex) {
 549             if (PRINT_EXCEPTION_STACK_TRACE)
 550                 ex.printStackTrace();
 551             throw ex;
 552         }
 553         catch (IOException ex) {
 554             if (PRINT_EXCEPTION_STACK_TRACE)
 555                 ex.printStackTrace();
 556             throw ex;
 557         }
 558         catch (RuntimeException ex) {
 559             if (PRINT_EXCEPTION_STACK_TRACE)
 560                 ex.printStackTrace();
 561             throw ex;
 562         }
 563         catch (Exception ex) {
 564             if (PRINT_EXCEPTION_STACK_TRACE)
 565                 ex.printStackTrace();
 566             throw new XNIException(ex);
 567         }
 568 
 569     } // parse(boolean):boolean
 570 
 571     /**
 572      * If the application decides to terminate parsing before the xml document
 573      * is fully parsed, the application should call this method to free any
 574      * resource allocated during parsing. For example, close all opened streams.
 575      */
 576     public void cleanup() {
 577         fEntityManager.closeReaders();
 578     }
 579 
 580     //
 581     // XMLParserConfiguration methods
 582     //
 583 
 584     /**
 585      * Parses the specified input source.
 586      *
 587      * @param source The input source.
 588      *
 589      * @exception XNIException Throws exception on XNI error.
 590      * @exception java.io.IOException Throws exception on i/o error.
 591      */
 592     public void parse(XMLInputSource source) throws XNIException, IOException {
 593 
 594         if (fParseInProgress) {
 595             // REVISIT - need to add new error message
 596             throw new XNIException("FWK005 parse may not be called while parsing.");
 597         }
 598         fParseInProgress = true;
 599 
 600         try {
 601             setInputSource(source);
 602             parse(true);
 603         }
 604         catch (XNIException ex) {
 605             if (PRINT_EXCEPTION_STACK_TRACE)
 606                 ex.printStackTrace();
 607             throw ex;
 608         }
 609         catch (IOException ex) {
 610             if (PRINT_EXCEPTION_STACK_TRACE)
 611                 ex.printStackTrace();
 612             throw ex;
 613         }
 614         catch (RuntimeException ex) {
 615             if (PRINT_EXCEPTION_STACK_TRACE)
 616                 ex.printStackTrace();
 617             throw ex;
 618         }
 619         catch (Exception ex) {
 620             if (PRINT_EXCEPTION_STACK_TRACE)
 621                 ex.printStackTrace();
 622             throw new XNIException(ex);
 623         }
 624         finally {
 625             fParseInProgress = false;
 626             // close all streams opened by xerces
 627             this.cleanup();
 628         }
 629 
 630     } // parse(InputSource)
 631 
 632     //
 633     // Protected methods
 634     //
 635 
 636     /**
 637      * Reset all components before parsing.
 638      *
 639      * @throws XNIException Thrown if an error occurs during initialization.
 640      */
 641     protected void reset() throws XNIException {
 642 
 643         if (fValidationManager != null)
 644             fValidationManager.reset();
 645         // configure the pipeline and initialize the components
 646         configurePipeline();
 647         super.reset();
 648     } // reset()
 649 
 650     /** Configures the pipeline. */
 651         protected void configurePipeline() {
 652 
 653                 // REVISIT: This should be better designed. In other words, we
 654                 //          need to figure out what is the best way for people to
 655                 //          re-use *most* of the standard configuration but do
 656                 //          things common things such as remove a component (e.g.
 657                 //          the validator), insert a new component (e.g. XInclude),
 658                 //          etc... -Ac
 659 
 660                 // setup document pipeline
 661                 if (fDTDValidator != null) {
 662                         fScanner.setDocumentHandler(fDTDValidator);
 663                         if (fFeatures.get(NAMESPACES) == Boolean.TRUE) {
 664 
 665                                 // filters
 666                                 fDTDValidator.setDocumentHandler(fNamespaceBinder);
 667                                 fDTDValidator.setDocumentSource(fScanner);
 668                                 fNamespaceBinder.setDocumentHandler(fDocumentHandler);
 669                                 fNamespaceBinder.setDocumentSource(fDTDValidator);
 670                                 fLastComponent = fNamespaceBinder;
 671                         }
 672                         else {
 673                                 fDTDValidator.setDocumentHandler(fDocumentHandler);
 674                                 fDTDValidator.setDocumentSource(fScanner);
 675                                 fLastComponent = fDTDValidator;
 676                         }
 677                 }
 678                 else {
 679                         if (fFeatures.get(NAMESPACES) == Boolean.TRUE) {
 680                                 fScanner.setDocumentHandler(fNamespaceBinder);
 681                                 fNamespaceBinder.setDocumentHandler(fDocumentHandler);
 682                                 fNamespaceBinder.setDocumentSource(fScanner);
 683                                 fLastComponent = fNamespaceBinder;
 684                         }
 685                         else {
 686                                 fScanner.setDocumentHandler(fDocumentHandler);
 687                                 fLastComponent = fScanner;
 688                         }
 689                 }
 690 
 691         configureDTDPipeline();
 692         } // configurePipeline()
 693 
 694     protected void configureDTDPipeline (){
 695 
 696         // setup dtd pipeline
 697         if (fDTDScanner != null) {
 698             fProperties.put(DTD_SCANNER, fDTDScanner);
 699             if (fDTDProcessor != null) {
 700                 fProperties.put(DTD_PROCESSOR, fDTDProcessor);
 701                 fDTDScanner.setDTDHandler(fDTDProcessor);
 702                 fDTDProcessor.setDTDSource(fDTDScanner);
 703                 fDTDProcessor.setDTDHandler(fDTDHandler);
 704                 if (fDTDHandler != null) {
 705                     fDTDHandler.setDTDSource(fDTDProcessor);
 706                 }
 707 
 708                 fDTDScanner.setDTDContentModelHandler(fDTDProcessor);
 709                 fDTDProcessor.setDTDContentModelSource(fDTDScanner);
 710                 fDTDProcessor.setDTDContentModelHandler(fDTDContentModelHandler);
 711                 if (fDTDContentModelHandler != null) {
 712                     fDTDContentModelHandler.setDTDContentModelSource(fDTDProcessor);
 713                 }
 714             }
 715             else {
 716                 fDTDScanner.setDTDHandler(fDTDHandler);
 717                 if (fDTDHandler != null) {
 718                     fDTDHandler.setDTDSource(fDTDScanner);
 719                 }
 720                 fDTDScanner.setDTDContentModelHandler(fDTDContentModelHandler);
 721                 if (fDTDContentModelHandler != null) {
 722                     fDTDContentModelHandler.setDTDContentModelSource(fDTDScanner);
 723                 }
 724             }
 725         }
 726 
 727 
 728     }
 729 
 730     // features and properties
 731 
 732     /**
 733      * Check a feature. If feature is know and supported, this method simply
 734      * returns. Otherwise, the appropriate exception is thrown.
 735      *
 736      * @param featureId The unique identifier (URI) of the feature.
 737      *
 738      * @throws XMLConfigurationException Thrown for configuration error.
 739      *                                   In general, components should
 740      *                                   only throw this exception if
 741      *                                   it is <strong>really</strong>
 742      *                                   a critical error.
 743      */
 744     protected FeatureState checkFeature(String featureId)
 745         throws XMLConfigurationException {
 746 
 747         //
 748         // Xerces Features
 749         //
 750 
 751         if (featureId.startsWith(Constants.XERCES_FEATURE_PREFIX)) {
 752             final int suffixLength = featureId.length() - Constants.XERCES_FEATURE_PREFIX.length();
 753 
 754             //
 755             // http://apache.org/xml/features/validation/dynamic
 756             //   Allows the parser to validate a document only when it
 757             //   contains a grammar. Validation is turned on/off based
 758             //   on each document instance, automatically.
 759             //
 760             if (suffixLength == Constants.DYNAMIC_VALIDATION_FEATURE.length() &&
 761                 featureId.endsWith(Constants.DYNAMIC_VALIDATION_FEATURE)) {
 762                 return FeatureState.RECOGNIZED;
 763             }
 764 
 765             //
 766             // http://apache.org/xml/features/validation/default-attribute-values
 767             //
 768             if (suffixLength == Constants.DEFAULT_ATTRIBUTE_VALUES_FEATURE.length() &&
 769                 featureId.endsWith(Constants.DEFAULT_ATTRIBUTE_VALUES_FEATURE)) {
 770                 // REVISIT
 771                 return FeatureState.NOT_SUPPORTED;
 772             }
 773             //
 774             // http://apache.org/xml/features/validation/default-attribute-values
 775             //
 776             if (suffixLength == Constants.VALIDATE_CONTENT_MODELS_FEATURE.length() &&
 777                 featureId.endsWith(Constants.VALIDATE_CONTENT_MODELS_FEATURE)) {
 778                 // REVISIT
 779                 return FeatureState.NOT_SUPPORTED;
 780             }
 781             //
 782             // http://apache.org/xml/features/validation/nonvalidating/load-dtd-grammar
 783             //
 784             if (suffixLength == Constants.LOAD_DTD_GRAMMAR_FEATURE.length() &&
 785                 featureId.endsWith(Constants.LOAD_DTD_GRAMMAR_FEATURE)) {
 786                 return FeatureState.RECOGNIZED;
 787             }
 788             //
 789             // http://apache.org/xml/features/validation/nonvalidating/load-external-dtd
 790             //
 791             if (suffixLength == Constants.LOAD_EXTERNAL_DTD_FEATURE.length() &&
 792                 featureId.endsWith(Constants.LOAD_EXTERNAL_DTD_FEATURE)) {
 793                 return FeatureState.RECOGNIZED;
 794             }
 795 
 796             //
 797             // http://apache.org/xml/features/validation/default-attribute-values
 798             //
 799             if (suffixLength == Constants.VALIDATE_DATATYPES_FEATURE.length() &&
 800                 featureId.endsWith(Constants.VALIDATE_DATATYPES_FEATURE)) {
 801                 return FeatureState.NOT_SUPPORTED;
 802             }
 803         }
 804 
 805         //
 806         // Not recognized
 807         //
 808 
 809         return super.checkFeature(featureId);
 810 
 811     } // checkFeature(String)
 812 
 813     /**
 814      * Check a property. If the property is know and supported, this method
 815      * simply returns. Otherwise, the appropriate exception is thrown.
 816      *
 817      * @param propertyId The unique identifier (URI) of the property
 818      *                   being set.
 819      *
 820      * @throws XMLConfigurationException Thrown for configuration error.
 821      *                                   In general, components should
 822      *                                   only throw this exception if
 823      *                                   it is <strong>really</strong>
 824      *                                   a critical error.
 825      */
 826     protected PropertyState checkProperty(String propertyId)
 827         throws XMLConfigurationException {
 828 
 829         //
 830         // Xerces Properties
 831         //
 832 
 833         if (propertyId.startsWith(Constants.XERCES_PROPERTY_PREFIX)) {
 834             final int suffixLength = propertyId.length() - Constants.XERCES_PROPERTY_PREFIX.length();
 835 
 836             if (suffixLength == Constants.DTD_SCANNER_PROPERTY.length() &&
 837                 propertyId.endsWith(Constants.DTD_SCANNER_PROPERTY)) {
 838                 return PropertyState.RECOGNIZED;
 839             }
 840         }
 841 
 842         //
 843         // Not recognized
 844         //
 845 
 846         return super.checkProperty(propertyId);
 847 
 848     } // checkProperty(String)
 849 
 850     // factory methods
 851 
 852     /** Creates an entity manager. */
 853     protected XMLEntityManager createEntityManager() {
 854         return new XMLEntityManager();
 855     } // createEntityManager():XMLEntityManager
 856 
 857     /** Creates an error reporter. */
 858     protected XMLErrorReporter createErrorReporter() {
 859         return new XMLErrorReporter();
 860     } // createErrorReporter():XMLErrorReporter
 861 
 862     /** Create a document scanner. */
 863     protected XMLDocumentScanner createDocumentScanner() {
 864         return new XMLDocumentScannerImpl();
 865     } // createDocumentScanner():XMLDocumentScanner
 866 
 867     /** Create a DTD scanner. */
 868     protected XMLDTDScanner createDTDScanner() {
 869         return new XMLDTDScannerImpl();
 870     } // createDTDScanner():XMLDTDScanner
 871 
 872     /** Create a DTD loader . */
 873     protected XMLDTDProcessor createDTDProcessor() {
 874         return new XMLDTDProcessor();
 875     } // createDTDProcessor():XMLDTDProcessor
 876 
 877     /** Create a DTD validator. */
 878     protected XMLDTDValidator createDTDValidator() {
 879         return new XMLDTDValidator();
 880     } // createDTDValidator():XMLDTDValidator
 881 
 882     /** Create a namespace binder. */
 883     protected XMLNamespaceBinder createNamespaceBinder() {
 884         return new XMLNamespaceBinder();
 885     } // createNamespaceBinder():XMLNamespaceBinder
 886 
 887     /** Create a datatype validator factory. */
 888     protected DTDDVFactory createDatatypeValidatorFactory() {
 889         return DTDDVFactory.getInstance();
 890     } // createDatatypeValidatorFactory():DatatypeValidatorFactory
 891     protected ValidationManager createValidationManager(){
 892         return new ValidationManager();
 893     }
 894 
 895 } // class DTDConfiguration