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