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 }