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.jaxp;
  22 
  23 import java.io.IOException;
  24 import java.util.Hashtable;
  25 import java.util.Iterator;
  26 import java.util.Map;
  27 
  28 import javax.xml.parsers.DocumentBuilder;
  29 import javax.xml.validation.Schema;
  30 import javax.xml.XMLConstants;
  31 
  32 import com.sun.org.apache.xerces.internal.dom.DOMImplementationImpl;
  33 import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter;
  34 import com.sun.org.apache.xerces.internal.impl.Constants;
  35 import com.sun.org.apache.xerces.internal.impl.validation.ValidationManager;
  36 import com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator;
  37 import com.sun.org.apache.xerces.internal.jaxp.validation.XSGrammarPoolContainer;
  38 import com.sun.org.apache.xerces.internal.parsers.DOMParser;
  39 import com.sun.org.apache.xerces.internal.util.SecurityManager;
  40 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager;
  41 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager.Property;
  42 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager.State;
  43 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
  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.XMLDocumentSource;
  48 import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration;
  49 import javax.xml.XMLConstants;
  50 import org.w3c.dom.DOMImplementation;
  51 import org.w3c.dom.Document;
  52 import org.xml.sax.EntityResolver;
  53 import org.xml.sax.ErrorHandler;
  54 import org.xml.sax.InputSource;
  55 import org.xml.sax.SAXException;
  56 import org.xml.sax.SAXNotRecognizedException;
  57 import org.xml.sax.SAXNotSupportedException;
  58 
  59 /**
  60  * @author Rajiv Mordani
  61  * @author Edwin Goei
  62  * @version $Id: DocumentBuilderImpl.java,v 1.8 2010-11-01 04:40:06 joehw Exp $
  63  */
  64 public class DocumentBuilderImpl extends DocumentBuilder
  65         implements JAXPConstants
  66 {
  67     /** Feature identifier: namespaces. */
  68     private static final String NAMESPACES_FEATURE =
  69         Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE;
  70 
  71     /** Feature identifier: include ignorable white space. */
  72     private static final String INCLUDE_IGNORABLE_WHITESPACE =
  73         Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_IGNORABLE_WHITESPACE;
  74 
  75     /** Feature identifier: create entiry ref nodes feature. */
  76     private static final String CREATE_ENTITY_REF_NODES_FEATURE =
  77         Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_ENTITY_REF_NODES_FEATURE;
  78 
  79     /** Feature identifier: include comments feature. */
  80     private static final String INCLUDE_COMMENTS_FEATURE =
  81         Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_COMMENTS_FEATURE;
  82 
  83     /** Feature identifier: create cdata nodes feature. */
  84     private static final String CREATE_CDATA_NODES_FEATURE =
  85         Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_CDATA_NODES_FEATURE;
  86 
  87     /** Feature identifier: XInclude processing */
  88     private static final String XINCLUDE_FEATURE =
  89         Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FEATURE;
  90 
  91     /** feature identifier: XML Schema validation */
  92     private static final String XMLSCHEMA_VALIDATION_FEATURE =
  93         Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE;
  94 
  95     /** Feature identifier: validation */
  96     private static final String VALIDATION_FEATURE =
  97         Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
  98 
  99     /** Property identifier: security manager. */
 100     private static final String SECURITY_MANAGER =
 101         Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY;
 102 
 103     /** Property identifier: Security property manager. */
 104     private static final String XML_SECURITY_PROPERTY_MANAGER =
 105             Constants.XML_SECURITY_PROPERTY_MANAGER;
 106 
 107     /** property identifier: access external dtd. */
 108     public static final String ACCESS_EXTERNAL_DTD = XMLConstants.ACCESS_EXTERNAL_DTD;
 109 
 110     /** Property identifier: access to external schema */
 111     public static final String ACCESS_EXTERNAL_SCHEMA = XMLConstants.ACCESS_EXTERNAL_SCHEMA;
 112 
 113 
 114     private final DOMParser domParser;
 115     private final Schema grammar;
 116 
 117     private final XMLComponent fSchemaValidator;
 118     private final XMLComponentManager fSchemaValidatorComponentManager;
 119     private final ValidationManager fSchemaValidationManager;
 120     private final UnparsedEntityHandler fUnparsedEntityHandler;
 121 
 122     /** Initial ErrorHandler */
 123     private final ErrorHandler fInitErrorHandler;
 124 
 125     /** Initial EntityResolver */
 126     private final EntityResolver fInitEntityResolver;
 127 
 128     private XMLSecurityPropertyManager fSecurityPropertyMgr;
 129 
 130     DocumentBuilderImpl(DocumentBuilderFactoryImpl dbf, Hashtable dbfAttrs, Hashtable features)
 131         throws SAXNotRecognizedException, SAXNotSupportedException {
 132         this(dbf, dbfAttrs, features, false);
 133     }
 134 
 135     DocumentBuilderImpl(DocumentBuilderFactoryImpl dbf, Hashtable dbfAttrs, Hashtable features, boolean secureProcessing)
 136         throws SAXNotRecognizedException, SAXNotSupportedException
 137     {
 138         domParser = new DOMParser();
 139 
 140         // If validating, provide a default ErrorHandler that prints
 141         // validation errors with a warning telling the user to set an
 142         // ErrorHandler
 143         if (dbf.isValidating()) {
 144             fInitErrorHandler = new DefaultValidationErrorHandler();
 145             setErrorHandler(fInitErrorHandler);
 146         }
 147         else {
 148             fInitErrorHandler = domParser.getErrorHandler();
 149         }
 150 
 151         domParser.setFeature(VALIDATION_FEATURE, dbf.isValidating());
 152 
 153         // "namespaceAware" == SAX Namespaces feature
 154         domParser.setFeature(NAMESPACES_FEATURE, dbf.isNamespaceAware());
 155 
 156         // Set various parameters obtained from DocumentBuilderFactory
 157         domParser.setFeature(INCLUDE_IGNORABLE_WHITESPACE,
 158                 !dbf.isIgnoringElementContentWhitespace());
 159         domParser.setFeature(CREATE_ENTITY_REF_NODES_FEATURE,
 160                 !dbf.isExpandEntityReferences());
 161         domParser.setFeature(INCLUDE_COMMENTS_FEATURE,
 162                 !dbf.isIgnoringComments());
 163         domParser.setFeature(CREATE_CDATA_NODES_FEATURE,
 164                 !dbf.isCoalescing());
 165 
 166         // Avoid setting the XInclude processing feature if the value is false.
 167         // This will keep the configuration from throwing an exception if it
 168         // does not support XInclude.
 169         if (dbf.isXIncludeAware()) {
 170             domParser.setFeature(XINCLUDE_FEATURE, true);
 171         }
 172 
 173         fSecurityPropertyMgr = new XMLSecurityPropertyManager();
 174         domParser.setProperty(XML_SECURITY_PROPERTY_MANAGER, fSecurityPropertyMgr);
 175 
 176         // If the secure processing feature is on set a security manager.
 177         if (secureProcessing) {
 178             domParser.setProperty(SECURITY_MANAGER, new SecurityManager());
 179 
 180             /** 
 181              * If secure processing is explicitly set on the factory, the
 182              * access properties will be set unless the corresponding 
 183              * System Properties or jaxp.properties are set
 184              */
 185             if (features != null) {
 186                 Object temp = features.get(XMLConstants.FEATURE_SECURE_PROCESSING);
 187                 if (temp != null) {
 188                     boolean value = ((Boolean) temp).booleanValue();
 189                     if (value && Constants.IS_JDK8_OR_ABOVE) {
 190                         fSecurityPropertyMgr.setValue(Property.ACCESS_EXTERNAL_DTD, 
 191                                 State.FSP, Constants.EXTERNAL_ACCESS_DEFAULT_FSP);
 192                         fSecurityPropertyMgr.setValue(Property.ACCESS_EXTERNAL_SCHEMA, 
 193                                 State.FSP, Constants.EXTERNAL_ACCESS_DEFAULT_FSP);
 194                     }
 195                 }
 196             }
 197         }
 198 
 199         this.grammar = dbf.getSchema();
 200         if (grammar != null) {
 201             XMLParserConfiguration config = domParser.getXMLParserConfiguration();
 202             XMLComponent validatorComponent = null;
 203             /** For Xerces grammars, use built-in schema validator. **/
 204             if (grammar instanceof XSGrammarPoolContainer) {
 205                 validatorComponent = new XMLSchemaValidator();
 206                 fSchemaValidationManager = new ValidationManager();
 207                 fUnparsedEntityHandler = new UnparsedEntityHandler(fSchemaValidationManager);
 208                 config.setDTDHandler(fUnparsedEntityHandler);
 209                 fUnparsedEntityHandler.setDTDHandler(domParser);
 210                 domParser.setDTDSource(fUnparsedEntityHandler);
 211                 fSchemaValidatorComponentManager = new SchemaValidatorConfiguration(config,
 212                         (XSGrammarPoolContainer) grammar, fSchemaValidationManager);
 213             }
 214             /** For third party grammars, use the JAXP validator component. **/
 215             else {
 216                 validatorComponent = new JAXPValidatorComponent(grammar.newValidatorHandler());
 217                 fSchemaValidationManager = null;
 218                 fUnparsedEntityHandler = null;
 219                 fSchemaValidatorComponentManager = config;
 220             }
 221             config.addRecognizedFeatures(validatorComponent.getRecognizedFeatures());
 222             config.addRecognizedProperties(validatorComponent.getRecognizedProperties());
 223             setFeatures(features);      // Must set before calling setDocumentHandler()
 224             config.setDocumentHandler((XMLDocumentHandler) validatorComponent);
 225             ((XMLDocumentSource)validatorComponent).setDocumentHandler(domParser);
 226             domParser.setDocumentSource((XMLDocumentSource) validatorComponent);
 227             fSchemaValidator = validatorComponent;
 228         }
 229         else {
 230             fSchemaValidationManager = null;
 231             fUnparsedEntityHandler = null;
 232             fSchemaValidatorComponentManager = null;
 233             fSchemaValidator = null;
 234             setFeatures(features);
 235         }
 236 
 237         //setAttribute override those that may be set by other means
 238         setDocumentBuilderFactoryAttributes(dbfAttrs);
 239 
 240         // Initial EntityResolver
 241         fInitEntityResolver = domParser.getEntityResolver();
 242     }
 243 
 244     private void setFeatures(Hashtable features)
 245         throws SAXNotSupportedException, SAXNotRecognizedException {
 246         if (features != null) {
 247             Iterator entries = features.entrySet().iterator();
 248             while (entries.hasNext()) {
 249                 Map.Entry entry = (Map.Entry) entries.next();
 250                 String feature = (String) entry.getKey();
 251                 boolean value = ((Boolean) entry.getValue()).booleanValue();
 252                 domParser.setFeature(feature, value);
 253             }
 254         }
 255     }
 256 
 257     /**
 258      * Set any DocumentBuilderFactory attributes of our underlying DOMParser
 259      *
 260      * Note: code does not handle possible conflicts between DOMParser
 261      * attribute names and JAXP specific attribute names,
 262      * eg. DocumentBuilderFactory.setValidating()
 263      */
 264     private void setDocumentBuilderFactoryAttributes(Hashtable dbfAttrs)
 265         throws SAXNotSupportedException, SAXNotRecognizedException
 266     {
 267         if (dbfAttrs == null) {
 268             // Nothing to do
 269             return;
 270         }
 271 
 272         Iterator entries = dbfAttrs.entrySet().iterator();
 273         while (entries.hasNext()) {
 274             Map.Entry entry = (Map.Entry) entries.next();
 275             String name = (String) entry.getKey();
 276             Object val = entry.getValue();
 277             if (val instanceof Boolean) {
 278                 // Assume feature
 279                 domParser.setFeature(name, ((Boolean)val).booleanValue());
 280             } else {
 281                 // Assume property
 282                 if (JAXP_SCHEMA_LANGUAGE.equals(name)) {
 283                     // JAXP 1.2 support
 284                     //None of the properties will take effect till the setValidating(true) has been called
 285                     if ( W3C_XML_SCHEMA.equals(val) ) {
 286                         if( isValidating() ) {
 287                             domParser.setFeature(XMLSCHEMA_VALIDATION_FEATURE, true);
 288                             // this should allow us not to emit DTD errors, as expected by the
 289                             // spec when schema validation is enabled
 290                             domParser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
 291                         }
 292                      }
 293                  } else if(JAXP_SCHEMA_SOURCE.equals(name)){
 294                     if( isValidating() ) {
 295                         String value=(String)dbfAttrs.get(JAXP_SCHEMA_LANGUAGE);
 296                         if(value !=null && W3C_XML_SCHEMA.equals(value)){
 297                             domParser.setProperty(name, val);
 298                         }else{
 299                             throw new IllegalArgumentException(
 300                                 DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
 301                                 "jaxp-order-not-supported",
 302                                 new Object[] {JAXP_SCHEMA_LANGUAGE, JAXP_SCHEMA_SOURCE}));
 303                         }
 304                      }
 305                   } else {
 306                     int index = fSecurityPropertyMgr.getIndex(name);
 307                     if (index > -1) {
 308                         fSecurityPropertyMgr.setValue(index, 
 309                                 XMLSecurityPropertyManager.State.APIPROPERTY, (String)val);                    
 310                     } else {
 311                         // Let Xerces code handle the property
 312                         domParser.setProperty(name, val);
 313                     }
 314                   }
 315              }
 316         }
 317     }
 318 
 319     /**
 320      * Non-preferred: use the getDOMImplementation() method instead of this
 321      * one to get a DOM Level 2 DOMImplementation object and then use DOM
 322      * Level 2 methods to create a DOM Document object.
 323      */
 324     public Document newDocument() {
 325         return new com.sun.org.apache.xerces.internal.dom.DocumentImpl();
 326     }
 327 
 328     public DOMImplementation getDOMImplementation() {
 329         return DOMImplementationImpl.getDOMImplementation();
 330     }
 331 
 332     public Document parse(InputSource is) throws SAXException, IOException {
 333         if (is == null) {
 334             throw new IllegalArgumentException(
 335                 DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
 336                 "jaxp-null-input-source", null));
 337         }
 338         if (fSchemaValidator != null) {
 339             if (fSchemaValidationManager != null) {
 340                 fSchemaValidationManager.reset();
 341                 fUnparsedEntityHandler.reset();
 342             }
 343             resetSchemaValidator();
 344         }
 345         domParser.parse(is);
 346         Document doc = domParser.getDocument();
 347         domParser.dropDocumentReferences();
 348         return doc;
 349     }
 350 
 351     public boolean isNamespaceAware() {
 352         try {
 353             return domParser.getFeature(NAMESPACES_FEATURE);
 354         }
 355         catch (SAXException x) {
 356             throw new IllegalStateException(x.getMessage());
 357         }
 358     }
 359 
 360     public boolean isValidating() {
 361         try {
 362             return domParser.getFeature(VALIDATION_FEATURE);
 363         }
 364         catch (SAXException x) {
 365             throw new IllegalStateException(x.getMessage());
 366         }
 367     }
 368 
 369     /**
 370      * Gets the XInclude processing mode for this parser
 371      * @return the state of XInclude processing mode
 372      */
 373     public boolean isXIncludeAware() {
 374         try {
 375             return domParser.getFeature(XINCLUDE_FEATURE);
 376         }
 377         catch (SAXException exc) {
 378             return false;
 379         }
 380     }
 381 
 382     public void setEntityResolver(EntityResolver er) {
 383         domParser.setEntityResolver(er);
 384     }
 385 
 386     public void setErrorHandler(ErrorHandler eh) {
 387         domParser.setErrorHandler(eh);
 388     }
 389 
 390     public Schema getSchema() {
 391         return grammar;
 392     }
 393 
 394     public void reset() {
 395         /** Restore the initial error handler. **/
 396         if (domParser.getErrorHandler() != fInitErrorHandler) {
 397             domParser.setErrorHandler(fInitErrorHandler);
 398         }
 399         /** Restore the initial entity resolver. **/
 400         if (domParser.getEntityResolver() != fInitEntityResolver) {
 401             domParser.setEntityResolver(fInitEntityResolver);
 402         }
 403     }
 404 
 405     // package private
 406     DOMParser getDOMParser() {
 407         return domParser;
 408     }
 409 
 410     private void resetSchemaValidator() throws SAXException {
 411         try {
 412             fSchemaValidator.reset(fSchemaValidatorComponentManager);
 413         }
 414         // This should never be thrown from the schema validator.
 415         catch (XMLConfigurationException e) {
 416             throw new SAXException(e);
 417         }
 418     }
 419 }