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