1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Copyright 2000-2005 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 
  25 import com.sun.org.apache.xerces.internal.impl.Constants;
  26 import com.sun.org.apache.xerces.internal.util.EntityResolverWrapper;
  27 import com.sun.org.apache.xerces.internal.util.EntityResolver2Wrapper;
  28 import com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper;
  29 import com.sun.org.apache.xerces.internal.util.SAXMessageFormatter;
  30 import com.sun.org.apache.xerces.internal.util.Status;
  31 import com.sun.org.apache.xerces.internal.util.SymbolTable;
  32 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager;
  33 import com.sun.org.apache.xerces.internal.xni.XNIException;
  34 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool;
  35 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  36 import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver;
  37 import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler;
  38 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
  39 import com.sun.org.apache.xerces.internal.xni.parser.XMLParseException;
  40 import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration;
  41 import org.w3c.dom.Node;
  42 import org.xml.sax.EntityResolver;
  43 import org.xml.sax.ErrorHandler;
  44 import org.xml.sax.InputSource;
  45 import org.xml.sax.SAXException;
  46 import org.xml.sax.SAXNotRecognizedException;
  47 import org.xml.sax.SAXNotSupportedException;
  48 import org.xml.sax.SAXParseException;
  49 import org.xml.sax.ext.EntityResolver2;
  50 import org.xml.sax.helpers.LocatorImpl;
  51 
  52 /**
  53  * This is the main Xerces DOM parser class. It uses the abstract DOM
  54  * parser with a document scanner, a dtd scanner, and a validator, as
  55  * well as a grammar pool.
  56  *
  57  * @author Arnaud  Le Hors, IBM
  58  * @author Andy Clark, IBM
  59  *
  60  * @version $Id: DOMParser.java,v 1.7 2010-11-01 04:40:09 joehw Exp $
  61  */
  62 public class DOMParser
  63     extends AbstractDOMParser {
  64 
  65     //
  66     // Constants
  67     //
  68 
  69     // features
  70 
  71     /** Feature identifier: EntityResolver2. */
  72     protected static final String USE_ENTITY_RESOLVER2 =
  73         Constants.SAX_FEATURE_PREFIX + Constants.USE_ENTITY_RESOLVER2_FEATURE;
  74 
  75     protected static final String REPORT_WHITESPACE =
  76             Constants.SUN_SCHEMA_FEATURE_PREFIX + Constants.SUN_REPORT_IGNORED_ELEMENT_CONTENT_WHITESPACE;
  77 
  78     /** Property identifier: Security property manager. */
  79     private static final String XML_SECURITY_PROPERTY_MANAGER =
  80             Constants.XML_SECURITY_PROPERTY_MANAGER;
  81 
  82     // recognized features:
  83     private static final String[] RECOGNIZED_FEATURES = {
  84         REPORT_WHITESPACE
  85     };
  86 
  87     // properties
  88 
  89     /** Property identifier: symbol table. */
  90     protected static final String SYMBOL_TABLE =
  91         Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
  92 
  93     /** Property identifier: XML grammar pool. */
  94     protected static final String XMLGRAMMAR_POOL =
  95         Constants.XERCES_PROPERTY_PREFIX+Constants.XMLGRAMMAR_POOL_PROPERTY;
  96 
  97     /** Recognized properties. */
  98     private static final String[] RECOGNIZED_PROPERTIES = {
  99         SYMBOL_TABLE,
 100         XMLGRAMMAR_POOL,
 101     };
 102 
 103     //
 104     // Data
 105     //
 106 
 107     // features
 108 
 109     /** Use EntityResolver2. */
 110     protected boolean fUseEntityResolver2 = true;
 111 
 112     //
 113     // Constructors
 114     //
 115 
 116     /**
 117      * Constructs a DOM parser using the specified parser configuration.
 118      */
 119     public DOMParser(XMLParserConfiguration config) {
 120         super(config);
 121     } // <init>(XMLParserConfiguration)
 122 
 123     /**
 124      * Constructs a DOM parser using the dtd/xml schema parser configuration.
 125      */
 126     public DOMParser() {
 127         this(null, null);
 128     } // <init>()
 129 
 130     /**
 131      * Constructs a DOM parser using the specified symbol table.
 132      */
 133     public DOMParser(SymbolTable symbolTable) {
 134         this(symbolTable, null);
 135     } // <init>(SymbolTable)
 136 
 137 
 138     /**
 139      * Constructs a DOM parser using the specified symbol table and
 140      * grammar pool.
 141      */
 142     public DOMParser(SymbolTable symbolTable, XMLGrammarPool grammarPool) {
 143         super(new XIncludeAwareParserConfiguration());
 144 
 145         // set properties
 146         fConfiguration.addRecognizedProperties(RECOGNIZED_PROPERTIES);
 147         if (symbolTable != null) {
 148             fConfiguration.setProperty(SYMBOL_TABLE, symbolTable);
 149         }
 150         if (grammarPool != null) {
 151             fConfiguration.setProperty(XMLGRAMMAR_POOL, grammarPool);
 152         }
 153 
 154         fConfiguration.addRecognizedFeatures(RECOGNIZED_FEATURES);
 155 
 156     } // <init>(SymbolTable,XMLGrammarPool)
 157 
 158     //
 159     // XMLReader methods
 160     //
 161 
 162     /**
 163      * Parses the input source specified by the given system identifier.
 164      * <p>
 165      * This method is equivalent to the following:
 166      * <pre>
 167      *     parse(new InputSource(systemId));
 168      * </pre>
 169      *
 170      * @param systemId The system identifier (URI).
 171      *
 172      * @exception org.xml.sax.SAXException Throws exception on SAX error.
 173      * @exception java.io.IOException Throws exception on i/o error.
 174      */
 175     public void parse(String systemId) throws SAXException, IOException {
 176 
 177         // parse document
 178         XMLInputSource source = new XMLInputSource(null, systemId, null);
 179         try {
 180             parse(source);
 181         }
 182 
 183         // wrap XNI exceptions as SAX exceptions
 184         catch (XMLParseException e) {
 185             Exception ex = e.getException();
 186             if (ex == null) {
 187                 // must be a parser exception; mine it for locator info and throw
 188                 // a SAXParseException
 189                 LocatorImpl locatorImpl = new LocatorImpl();
 190                 locatorImpl.setPublicId(e.getPublicId());
 191                 locatorImpl.setSystemId(e.getExpandedSystemId());
 192                 locatorImpl.setLineNumber(e.getLineNumber());
 193                 locatorImpl.setColumnNumber(e.getColumnNumber());
 194                 throw new SAXParseException(e.getMessage(), locatorImpl);
 195             }
 196             if (ex instanceof SAXException) {
 197                 // why did we create an XMLParseException?
 198                 throw (SAXException)ex;
 199             }
 200             if (ex instanceof IOException) {
 201                 throw (IOException)ex;
 202             }
 203             throw new SAXException(ex);
 204         }
 205         catch (XNIException e) {
 206             e.printStackTrace();
 207             Exception ex = e.getException();
 208             if (ex == null) {
 209                 throw new SAXException(e.getMessage());
 210             }
 211             if (ex instanceof SAXException) {
 212                 throw (SAXException)ex;
 213             }
 214             if (ex instanceof IOException) {
 215                 throw (IOException)ex;
 216             }
 217             throw new SAXException(ex);
 218         }
 219 
 220     } // parse(String)
 221 
 222     /**
 223      * parse
 224      *
 225      * @param inputSource
 226      *
 227      * @exception org.xml.sax.SAXException
 228      * @exception java.io.IOException
 229      */
 230     public void parse(InputSource inputSource)
 231         throws SAXException, IOException {
 232 
 233         // parse document
 234         try {
 235             XMLInputSource xmlInputSource =
 236                 new XMLInputSource(inputSource.getPublicId(),
 237                                    inputSource.getSystemId(),
 238                                    null);
 239             xmlInputSource.setByteStream(inputSource.getByteStream());
 240             xmlInputSource.setCharacterStream(inputSource.getCharacterStream());
 241             xmlInputSource.setEncoding(inputSource.getEncoding());
 242             parse(xmlInputSource);
 243         }
 244 
 245         // wrap XNI exceptions as SAX exceptions
 246         catch (XMLParseException e) {
 247             Exception ex = e.getException();
 248             if (ex == null) {
 249                 // must be a parser exception; mine it for locator info and throw
 250                 // a SAXParseException
 251                 LocatorImpl locatorImpl = new LocatorImpl();
 252                 locatorImpl.setPublicId(e.getPublicId());
 253                 locatorImpl.setSystemId(e.getExpandedSystemId());
 254                 locatorImpl.setLineNumber(e.getLineNumber());
 255                 locatorImpl.setColumnNumber(e.getColumnNumber());
 256                 throw new SAXParseException(e.getMessage(), locatorImpl);
 257             }
 258             if (ex instanceof SAXException) {
 259                 // why did we create an XMLParseException?
 260                 throw (SAXException)ex;
 261             }
 262             if (ex instanceof IOException) {
 263                 throw (IOException)ex;
 264             }
 265             throw new SAXException(ex);
 266         }
 267         catch (XNIException e) {
 268             Exception ex = e.getException();
 269             if (ex == null) {
 270                 throw new SAXException(e.getMessage());
 271             }
 272             if (ex instanceof SAXException) {
 273                 throw (SAXException)ex;
 274             }
 275             if (ex instanceof IOException) {
 276                 throw (IOException)ex;
 277             }
 278             throw new SAXException(ex);
 279         }
 280 
 281     } // parse(InputSource)
 282 
 283     /**
 284      * Sets the resolver used to resolve external entities. The EntityResolver
 285      * interface supports resolution of public and system identifiers.
 286      *
 287      * @param resolver The new entity resolver. Passing a null value will
 288      *                 uninstall the currently installed resolver.
 289      */
 290     public void setEntityResolver(EntityResolver resolver) {
 291 
 292         try {
 293             XMLEntityResolver xer = (XMLEntityResolver) fConfiguration.getProperty(ENTITY_RESOLVER);
 294             if (fUseEntityResolver2 && resolver instanceof EntityResolver2) {
 295                 if (xer instanceof EntityResolver2Wrapper) {
 296                     EntityResolver2Wrapper er2w = (EntityResolver2Wrapper) xer;
 297                     er2w.setEntityResolver((EntityResolver2) resolver);
 298                 }
 299                 else {
 300                     fConfiguration.setProperty(ENTITY_RESOLVER,
 301                             new EntityResolver2Wrapper((EntityResolver2) resolver));
 302                 }
 303             }
 304             else {
 305                 if (xer instanceof EntityResolverWrapper) {
 306                     EntityResolverWrapper erw = (EntityResolverWrapper) xer;
 307                     erw.setEntityResolver(resolver);
 308                 }
 309                 else {
 310                     fConfiguration.setProperty(ENTITY_RESOLVER,
 311                             new EntityResolverWrapper(resolver));
 312                 }
 313             }
 314         }
 315         catch (XMLConfigurationException e) {
 316             // do nothing
 317         }
 318 
 319     } // setEntityResolver(EntityResolver)
 320 
 321     /**
 322      * Return the current entity resolver.
 323      *
 324      * @return The current entity resolver, or null if none
 325      *         has been registered.
 326      * @see #setEntityResolver
 327      */
 328     public EntityResolver getEntityResolver() {
 329 
 330         EntityResolver entityResolver = null;
 331         try {
 332             XMLEntityResolver xmlEntityResolver =
 333                 (XMLEntityResolver)fConfiguration.getProperty(ENTITY_RESOLVER);
 334             if (xmlEntityResolver != null) {
 335                 if (xmlEntityResolver instanceof EntityResolverWrapper) {
 336                     entityResolver =
 337                         ((EntityResolverWrapper) xmlEntityResolver).getEntityResolver();
 338                 }
 339                 else if (xmlEntityResolver instanceof EntityResolver2Wrapper) {
 340                     entityResolver =
 341                         ((EntityResolver2Wrapper) xmlEntityResolver).getEntityResolver();
 342                 }
 343             }
 344         }
 345         catch (XMLConfigurationException e) {
 346             // do nothing
 347         }
 348         return entityResolver;
 349 
 350     } // getEntityResolver():EntityResolver
 351 
 352     /**
 353      * Allow an application to register an error event handler.
 354      *
 355      * <p>If the application does not register an error handler, all
 356      * error events reported by the SAX parser will be silently
 357      * ignored; however, normal processing may not continue.  It is
 358      * highly recommended that all SAX applications implement an
 359      * error handler to avoid unexpected bugs.</p>
 360      *
 361      * <p>Applications may register a new or different handler in the
 362      * middle of a parse, and the SAX parser must begin using the new
 363      * handler immediately.</p>
 364      *
 365      * @param errorHandler The error handler.
 366      * @exception java.lang.NullPointerException If the handler
 367      *            argument is null.
 368      * @see #getErrorHandler
 369      */
 370     public void setErrorHandler(ErrorHandler errorHandler) {
 371 
 372         try {
 373             XMLErrorHandler xeh = (XMLErrorHandler) fConfiguration.getProperty(ERROR_HANDLER);
 374             if (xeh instanceof ErrorHandlerWrapper) {
 375                 ErrorHandlerWrapper ehw = (ErrorHandlerWrapper) xeh;
 376                 ehw.setErrorHandler(errorHandler);
 377             }
 378             else {
 379                 fConfiguration.setProperty(ERROR_HANDLER,
 380                         new ErrorHandlerWrapper(errorHandler));
 381             }
 382         }
 383         catch (XMLConfigurationException e) {
 384             // do nothing
 385         }
 386 
 387     } // setErrorHandler(ErrorHandler)
 388 
 389     /**
 390      * Return the current error handler.
 391      *
 392      * @return The current error handler, or null if none
 393      *         has been registered.
 394      * @see #setErrorHandler
 395      */
 396     public ErrorHandler getErrorHandler() {
 397 
 398         ErrorHandler errorHandler = null;
 399         try {
 400             XMLErrorHandler xmlErrorHandler =
 401                 (XMLErrorHandler)fConfiguration.getProperty(ERROR_HANDLER);
 402             if (xmlErrorHandler != null &&
 403                 xmlErrorHandler instanceof ErrorHandlerWrapper) {
 404                 errorHandler = ((ErrorHandlerWrapper)xmlErrorHandler).getErrorHandler();
 405             }
 406         }
 407         catch (XMLConfigurationException e) {
 408             // do nothing
 409         }
 410         return errorHandler;
 411 
 412     } // getErrorHandler():ErrorHandler
 413 
 414     /**
 415      * Set the state of any feature in a SAX2 parser.  The parser
 416      * might not recognize the feature, and if it does recognize
 417      * it, it might not be able to fulfill the request.
 418      *
 419      * @param featureId The unique identifier (URI) of the feature.
 420      * @param state The requested state of the feature (true or false).
 421      *
 422      * @exception SAXNotRecognizedException If the
 423      *            requested feature is not known.
 424      * @exception SAXNotSupportedException If the
 425      *            requested feature is known, but the requested
 426      *            state is not supported.
 427      */
 428     public void setFeature(String featureId, boolean state)
 429         throws SAXNotRecognizedException, SAXNotSupportedException {
 430 
 431         try {
 432 
 433             // http://xml.org/sax/features/use-entity-resolver2
 434             //   controls whether the methods of an object implementing
 435             //   org.xml.sax.ext.EntityResolver2 will be used by the parser.
 436             //
 437             if (featureId.equals(USE_ENTITY_RESOLVER2)) {
 438                 if (state != fUseEntityResolver2) {
 439                     fUseEntityResolver2 = state;
 440                     // Refresh EntityResolver wrapper.
 441                     setEntityResolver(getEntityResolver());
 442                 }
 443                 return;
 444             }
 445 
 446             //
 447             // Default handling
 448             //
 449 
 450             fConfiguration.setFeature(featureId, state);
 451         }
 452         catch (XMLConfigurationException e) {
 453             String identifier = e.getIdentifier();
 454             if (e.getType() == Status.NOT_RECOGNIZED) {
 455                 throw new SAXNotRecognizedException(
 456                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 457                     "feature-not-recognized", new Object [] {identifier}));
 458             }
 459             else {
 460                 throw new SAXNotSupportedException(
 461                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 462                     "feature-not-supported", new Object [] {identifier}));
 463             }
 464         }
 465 
 466     } // setFeature(String,boolean)
 467 
 468     /**
 469      * Query the state of a feature.
 470      *
 471      * Query the current state of any feature in a SAX2 parser.  The
 472      * parser might not recognize the feature.
 473      *
 474      * @param featureId The unique identifier (URI) of the feature
 475      *                  being set.
 476      * @return The current state of the feature.
 477      * @exception org.xml.sax.SAXNotRecognizedException If the
 478      *            requested feature is not known.
 479      * @exception SAXNotSupportedException If the
 480      *            requested feature is known but not supported.
 481      */
 482     public boolean getFeature(String featureId)
 483         throws SAXNotRecognizedException, SAXNotSupportedException {
 484 
 485         try {
 486 
 487             // http://xml.org/sax/features/use-entity-resolver2
 488             //   controls whether the methods of an object implementing
 489             //   org.xml.sax.ext.EntityResolver2 will be used by the parser.
 490             //
 491             if (featureId.equals(USE_ENTITY_RESOLVER2)) {
 492                 return fUseEntityResolver2;
 493             }
 494 
 495             //
 496             // Default handling
 497             //
 498 
 499             return fConfiguration.getFeature(featureId);
 500         }
 501         catch (XMLConfigurationException e) {
 502             String identifier = e.getIdentifier();
 503             if (e.getType() == Status.NOT_RECOGNIZED) {
 504                 throw new SAXNotRecognizedException(
 505                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 506                     "feature-not-recognized", new Object [] {identifier}));
 507             }
 508             else {
 509                 throw new SAXNotSupportedException(
 510                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 511                     "feature-not-supported", new Object [] {identifier}));
 512             }
 513         }
 514 
 515     } // getFeature(String):boolean
 516 
 517     /**
 518      * Set the value of any property in a SAX2 parser.  The parser
 519      * might not recognize the property, and if it does recognize
 520      * it, it might not support the requested value.
 521      *
 522      * @param propertyId The unique identifier (URI) of the property
 523      *                   being set.
 524      * @param value The value to which the property is being set.
 525      *
 526      * @exception SAXNotRecognizedException If the
 527      *            requested property is not known.
 528      * @exception SAXNotSupportedException If the
 529      *            requested property is known, but the requested
 530      *            value is not supported.
 531      */
 532     public void setProperty(String propertyId, Object value)
 533         throws SAXNotRecognizedException, SAXNotSupportedException {
 534 
 535         try {
 536             fConfiguration.setProperty(propertyId, value);
 537         }
 538         catch (XMLConfigurationException e) {
 539             String identifier = e.getIdentifier();
 540             if (e.getType() == Status.NOT_RECOGNIZED) {
 541                 throw new SAXNotRecognizedException(
 542                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 543                     "property-not-recognized", new Object [] {identifier}));
 544             }
 545             else {
 546                 throw new SAXNotSupportedException(
 547                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 548                     "property-not-supported", new Object [] {identifier}));
 549             }
 550         }
 551 
 552     } // setProperty(String,Object)
 553 
 554     /**
 555      * Query the value of a property.
 556      *
 557      * Return the current value of a property in a SAX2 parser.
 558      * The parser might not recognize the property.
 559      *
 560      * @param propertyId The unique identifier (URI) of the property
 561      *                   being set.
 562      * @return The current value of the property.
 563      * @exception org.xml.sax.SAXNotRecognizedException If the
 564      *            requested property is not known.
 565      * @exception SAXNotSupportedException If the
 566      *            requested property is known but not supported.
 567      */
 568     public Object getProperty(String propertyId)
 569         throws SAXNotRecognizedException, SAXNotSupportedException {
 570 
 571        if (propertyId.equals(CURRENT_ELEMENT_NODE)) {
 572            boolean deferred = false;
 573            try {
 574                deferred = getFeature(DEFER_NODE_EXPANSION);
 575            }
 576            catch (XMLConfigurationException e){
 577                // ignore
 578            }
 579            if (deferred) {
 580                throw new SAXNotSupportedException("Current element node cannot be queried when node expansion is deferred.");
 581            }
 582            return (fCurrentNode!=null &&
 583                    fCurrentNode.getNodeType() == Node.ELEMENT_NODE)? fCurrentNode:null;
 584        }
 585 
 586         try {
 587             XMLSecurityPropertyManager spm = (XMLSecurityPropertyManager) 
 588                     fConfiguration.getProperty(XML_SECURITY_PROPERTY_MANAGER);
 589             int index = spm.getIndex(propertyId);
 590             if (index > -1) {
 591                 return spm.getValueByIndex(index);
 592             }
 593 
 594             return fConfiguration.getProperty(propertyId);
 595         }
 596         catch (XMLConfigurationException e) {
 597             String identifier = e.getIdentifier();
 598             if (e.getType() == Status.NOT_RECOGNIZED) {
 599                 throw new SAXNotRecognizedException(
 600                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 601                     "property-not-recognized", new Object [] {identifier}));
 602             }
 603             else {
 604                 throw new SAXNotSupportedException(
 605                     SAXMessageFormatter.formatMessage(fConfiguration.getLocale(),
 606                     "property-not-supported", new Object [] {identifier}));
 607             }
 608         }
 609 
 610     } // getProperty(String):Object
 611 
 612     /**
 613      * Returns this parser's XMLParserConfiguration.
 614      */
 615     public XMLParserConfiguration getXMLParserConfiguration() {
 616         return fConfiguration;
 617     } // getXMLParserConfiguration():XMLParserConfiguration
 618 
 619 } // class DOMParser