1 /* 2 * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. 3 */ 4 /* 5 * Licensed to the Apache Software Foundation (ASF) under one or more 6 * contributor license agreements. See the NOTICE file distributed with 7 * this work for additional information regarding copyright ownership. 8 * The ASF licenses this file to You under the Apache License, Version 2.0 9 * (the "License"); you may not use this file except in compliance with 10 * the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 21 package com.sun.org.apache.xerces.internal.jaxp; 22 23 import java.io.IOException; 24 import java.util.Iterator; 25 import java.util.Map; 26 27 import javax.xml.parsers.DocumentBuilder; 28 import javax.xml.validation.Schema; 29 import javax.xml.XMLConstants; 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.utils.XMLSecurityManager; 39 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager; 40 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager.Property; 41 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager.State; 42 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler; 43 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent; 44 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager; 45 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException; 46 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource; 47 import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration; 48 import org.w3c.dom.DOMImplementation; 49 import org.w3c.dom.Document; 50 import org.xml.sax.EntityResolver; 51 import org.xml.sax.ErrorHandler; 52 import org.xml.sax.InputSource; 53 import org.xml.sax.SAXException; 54 import org.xml.sax.SAXNotRecognizedException; 55 import org.xml.sax.SAXNotSupportedException; 56 57 /** 58 * @author Rajiv Mordani 59 * @author Edwin Goei 60 */ 61 public class DocumentBuilderImpl extends DocumentBuilder 62 implements JAXPConstants 63 { 64 /** Feature identifier: namespaces. */ 65 private static final String NAMESPACES_FEATURE = 66 Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; 67 68 /** Feature identifier: include ignorable white space. */ 69 private static final String INCLUDE_IGNORABLE_WHITESPACE = 70 Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_IGNORABLE_WHITESPACE; 71 72 /** Feature identifier: create entiry ref nodes feature. */ 73 private static final String CREATE_ENTITY_REF_NODES_FEATURE = 74 Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_ENTITY_REF_NODES_FEATURE; 75 76 /** Feature identifier: include comments feature. */ 77 private static final String INCLUDE_COMMENTS_FEATURE = 78 Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_COMMENTS_FEATURE; 79 80 /** Feature identifier: create cdata nodes feature. */ 81 private static final String CREATE_CDATA_NODES_FEATURE = 82 Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_CDATA_NODES_FEATURE; 83 84 /** Feature identifier: XInclude processing */ 85 private static final String XINCLUDE_FEATURE = 86 Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FEATURE; 87 88 /** feature identifier: XML Schema validation */ 89 private static final String XMLSCHEMA_VALIDATION_FEATURE = 90 Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE; 91 92 /** Feature identifier: validation */ 93 private static final String VALIDATION_FEATURE = 94 Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; 95 96 /** Property identifier: security manager. */ 97 private static final String SECURITY_MANAGER = 98 Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY; 99 100 /** Property identifier: Security property manager. */ 101 private static final String XML_SECURITY_PROPERTY_MANAGER = 102 Constants.XML_SECURITY_PROPERTY_MANAGER; 103 104 /** property identifier: access external dtd. */ 105 public static final String ACCESS_EXTERNAL_DTD = XMLConstants.ACCESS_EXTERNAL_DTD; 106 107 /** Property identifier: access to external schema */ 108 public static final String ACCESS_EXTERNAL_SCHEMA = XMLConstants.ACCESS_EXTERNAL_SCHEMA; 109 110 111 private final DOMParser domParser; 112 private final Schema grammar; 113 114 private final XMLComponent fSchemaValidator; 115 private final XMLComponentManager fSchemaValidatorComponentManager; 116 private final ValidationManager fSchemaValidationManager; 117 private final UnparsedEntityHandler fUnparsedEntityHandler; 118 119 /** Initial ErrorHandler */ 120 private final ErrorHandler fInitErrorHandler; 121 122 /** Initial EntityResolver */ 123 private final EntityResolver fInitEntityResolver; 124 125 private XMLSecurityManager fSecurityManager; 126 private XMLSecurityPropertyManager fSecurityPropertyMgr; 127 DocumentBuilderImpl(DocumentBuilderFactoryImpl dbf, Map<String, Object> dbfAttrs, Map<String, Boolean> features)128 DocumentBuilderImpl(DocumentBuilderFactoryImpl dbf, Map<String, Object> dbfAttrs, 129 Map<String, Boolean> features) 130 throws SAXNotRecognizedException, SAXNotSupportedException { 131 this(dbf, dbfAttrs, features, false); 132 } 133 DocumentBuilderImpl(DocumentBuilderFactoryImpl dbf, Map<String, Object> dbfAttrs, Map<String, Boolean> features, boolean secureProcessing)134 DocumentBuilderImpl(DocumentBuilderFactoryImpl dbf, Map<String, Object> dbfAttrs, 135 Map<String, Boolean> 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(domParser.getXMLParserConfiguration().getLocale()); 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 fSecurityManager = new XMLSecurityManager(secureProcessing); 177 domParser.setProperty(SECURITY_MANAGER, fSecurityManager); 178 179 if (secureProcessing) { 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 Boolean temp = features.get(XMLConstants.FEATURE_SECURE_PROCESSING); 187 if (temp != null && temp) { 188 fSecurityPropertyMgr.setValue(Property.ACCESS_EXTERNAL_DTD, 189 State.FSP, Constants.EXTERNAL_ACCESS_DEFAULT_FSP); 190 fSecurityPropertyMgr.setValue(Property.ACCESS_EXTERNAL_SCHEMA, 191 State.FSP, Constants.EXTERNAL_ACCESS_DEFAULT_FSP); 192 } 193 } 194 } 195 196 this.grammar = dbf.getSchema(); 197 if (grammar != null) { 198 XMLParserConfiguration config = domParser.getXMLParserConfiguration(); 199 XMLComponent validatorComponent = null; 200 /** For Xerces grammars, use built-in schema validator. **/ 201 if (grammar instanceof XSGrammarPoolContainer) { 202 validatorComponent = new XMLSchemaValidator(); 203 fSchemaValidationManager = new ValidationManager(); 204 fUnparsedEntityHandler = new UnparsedEntityHandler(fSchemaValidationManager); 205 config.setDTDHandler(fUnparsedEntityHandler); 206 fUnparsedEntityHandler.setDTDHandler(domParser); 207 domParser.setDTDSource(fUnparsedEntityHandler); 208 fSchemaValidatorComponentManager = new SchemaValidatorConfiguration(config, 209 (XSGrammarPoolContainer) grammar, fSchemaValidationManager); 210 } 211 /** For third party grammars, use the JAXP validator component. **/ 212 else { 213 validatorComponent = new JAXPValidatorComponent(grammar.newValidatorHandler()); 214 fSchemaValidationManager = null; 215 fUnparsedEntityHandler = null; 216 fSchemaValidatorComponentManager = config; 217 } 218 config.addRecognizedFeatures(validatorComponent.getRecognizedFeatures()); 219 config.addRecognizedProperties(validatorComponent.getRecognizedProperties()); 220 setFeatures(features); // Must set before calling setDocumentHandler() 221 config.setDocumentHandler((XMLDocumentHandler) validatorComponent); 222 ((XMLDocumentSource)validatorComponent).setDocumentHandler(domParser); 223 domParser.setDocumentSource((XMLDocumentSource) validatorComponent); 224 fSchemaValidator = validatorComponent; 225 } 226 else { 227 fSchemaValidationManager = null; 228 fUnparsedEntityHandler = null; 229 fSchemaValidatorComponentManager = null; 230 fSchemaValidator = null; 231 setFeatures(features); 232 } 233 234 //setAttribute override those that may be set by other means 235 setDocumentBuilderFactoryAttributes(dbfAttrs); 236 237 // Initial EntityResolver 238 fInitEntityResolver = domParser.getEntityResolver(); 239 } 240 setFeatures( Map<String, Boolean> features)241 private void setFeatures( Map<String, Boolean> features) 242 throws SAXNotSupportedException, SAXNotRecognizedException { 243 if (features != null) { 244 for (Map.Entry<String, Boolean> entry : features.entrySet()) { 245 domParser.setFeature(entry.getKey(), entry.getValue()); 246 } 247 } 248 } 249 250 /** 251 * Set any DocumentBuilderFactory attributes of our underlying DOMParser 252 * 253 * Note: code does not handle possible conflicts between DOMParser 254 * attribute names and JAXP specific attribute names, 255 * eg. DocumentBuilderFactory.setValidating() 256 */ setDocumentBuilderFactoryAttributes( Map<String, Object> dbfAttrs)257 private void setDocumentBuilderFactoryAttributes( Map<String, Object> dbfAttrs) 258 throws SAXNotSupportedException, SAXNotRecognizedException 259 { 260 if (dbfAttrs == null) { 261 // Nothing to do 262 return; 263 } 264 265 for (Map.Entry<String, Object> entry : dbfAttrs.entrySet()) { 266 String name = entry.getKey(); 267 Object val = entry.getValue(); 268 if (val instanceof Boolean) { 269 // Assume feature 270 domParser.setFeature(name, (Boolean)val); 271 } else { 272 // Assume property 273 if (JAXP_SCHEMA_LANGUAGE.equals(name)) { 274 // JAXP 1.2 support 275 //None of the properties will take effect till the setValidating(true) has been called 276 if ( W3C_XML_SCHEMA.equals(val) ) { 277 if( isValidating() ) { 278 domParser.setFeature(XMLSCHEMA_VALIDATION_FEATURE, true); 279 // this should allow us not to emit DTD errors, as expected by the 280 // spec when schema validation is enabled 281 domParser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA); 282 } 283 } 284 } else if(JAXP_SCHEMA_SOURCE.equals(name)){ 285 if( isValidating() ) { 286 String value=(String)dbfAttrs.get(JAXP_SCHEMA_LANGUAGE); 287 if(value !=null && W3C_XML_SCHEMA.equals(value)){ 288 domParser.setProperty(name, val); 289 }else{ 290 throw new IllegalArgumentException( 291 DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, 292 "jaxp-order-not-supported", 293 new Object[] {JAXP_SCHEMA_LANGUAGE, JAXP_SCHEMA_SOURCE})); 294 } 295 } 296 } else { 297 //check if the property is managed by security manager 298 if (fSecurityManager == null || 299 !fSecurityManager.setLimit(name, XMLSecurityManager.State.APIPROPERTY, val)) { 300 //check if the property is managed by security property manager 301 if (fSecurityPropertyMgr == null || 302 !fSecurityPropertyMgr.setValue(name, XMLSecurityPropertyManager.State.APIPROPERTY, val)) { 303 //fall back to the existing property manager 304 domParser.setProperty(name, val); 305 } 306 } 307 308 } 309 } 310 } 311 } 312 313 /** 314 * Non-preferred: use the getDOMImplementation() method instead of this 315 * one to get a DOM Level 2 DOMImplementation object and then use DOM 316 * Level 2 methods to create a DOM Document object. 317 */ newDocument()318 public Document newDocument() { 319 return new com.sun.org.apache.xerces.internal.dom.DocumentImpl(); 320 } 321 getDOMImplementation()322 public DOMImplementation getDOMImplementation() { 323 return DOMImplementationImpl.getDOMImplementation(); 324 } 325 parse(InputSource is)326 public Document parse(InputSource is) throws SAXException, IOException { 327 if (is == null) { 328 throw new IllegalArgumentException( 329 DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, 330 "jaxp-null-input-source", null)); 331 } 332 if (fSchemaValidator != null) { 333 if (fSchemaValidationManager != null) { 334 fSchemaValidationManager.reset(); 335 fUnparsedEntityHandler.reset(); 336 } 337 resetSchemaValidator(); 338 } 339 domParser.parse(is); 340 Document doc = domParser.getDocument(); 341 domParser.dropDocumentReferences(); 342 return doc; 343 } 344 isNamespaceAware()345 public boolean isNamespaceAware() { 346 try { 347 return domParser.getFeature(NAMESPACES_FEATURE); 348 } 349 catch (SAXException x) { 350 throw new IllegalStateException(x.getMessage()); 351 } 352 } 353 isValidating()354 public boolean isValidating() { 355 try { 356 return domParser.getFeature(VALIDATION_FEATURE); 357 } 358 catch (SAXException x) { 359 throw new IllegalStateException(x.getMessage()); 360 } 361 } 362 363 /** 364 * Gets the XInclude processing mode for this parser 365 * @return the state of XInclude processing mode 366 */ isXIncludeAware()367 public boolean isXIncludeAware() { 368 try { 369 return domParser.getFeature(XINCLUDE_FEATURE); 370 } 371 catch (SAXException exc) { 372 return false; 373 } 374 } 375 setEntityResolver(EntityResolver er)376 public void setEntityResolver(EntityResolver er) { 377 domParser.setEntityResolver(er); 378 } 379 setErrorHandler(ErrorHandler eh)380 public void setErrorHandler(ErrorHandler eh) { 381 domParser.setErrorHandler(eh); 382 } 383 getSchema()384 public Schema getSchema() { 385 return grammar; 386 } 387 reset()388 public void reset() { 389 /** Restore the initial error handler. **/ 390 if (domParser.getErrorHandler() != fInitErrorHandler) { 391 domParser.setErrorHandler(fInitErrorHandler); 392 } 393 /** Restore the initial entity resolver. **/ 394 if (domParser.getEntityResolver() != fInitEntityResolver) { 395 domParser.setEntityResolver(fInitEntityResolver); 396 } 397 } 398 399 // package private getDOMParser()400 DOMParser getDOMParser() { 401 return domParser; 402 } 403 resetSchemaValidator()404 private void resetSchemaValidator() throws SAXException { 405 try { 406 fSchemaValidator.reset(fSchemaValidatorComponentManager); 407 } 408 // This should never be thrown from the schema validator. 409 catch (XMLConfigurationException e) { 410 throw new SAXException(e); 411 } 412 } 413 } 414