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