/* * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.sun.org.apache.xerces.internal.jaxp; import java.io.IOException; import java.util.Iterator; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.validation.Schema; import javax.xml.XMLConstants; import com.sun.org.apache.xerces.internal.dom.DOMImplementationImpl; import com.sun.org.apache.xerces.internal.dom.DOMMessageFormatter; import com.sun.org.apache.xerces.internal.impl.Constants; import com.sun.org.apache.xerces.internal.impl.validation.ValidationManager; import com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator; import com.sun.org.apache.xerces.internal.jaxp.validation.XSGrammarPoolContainer; import com.sun.org.apache.xerces.internal.parsers.DOMParser; import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager; import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager; import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager.Property; import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager.State; import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler; import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent; import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager; import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException; import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource; import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration; import org.w3c.dom.DOMImplementation; import org.w3c.dom.Document; import org.xml.sax.EntityResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; /** * @author Rajiv Mordani * @author Edwin Goei */ public class DocumentBuilderImpl extends DocumentBuilder implements JAXPConstants { /** Feature identifier: namespaces. */ private static final String NAMESPACES_FEATURE = Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; /** Feature identifier: include ignorable white space. */ private static final String INCLUDE_IGNORABLE_WHITESPACE = Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_IGNORABLE_WHITESPACE; /** Feature identifier: create entiry ref nodes feature. */ private static final String CREATE_ENTITY_REF_NODES_FEATURE = Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_ENTITY_REF_NODES_FEATURE; /** Feature identifier: include comments feature. */ private static final String INCLUDE_COMMENTS_FEATURE = Constants.XERCES_FEATURE_PREFIX + Constants.INCLUDE_COMMENTS_FEATURE; /** Feature identifier: create cdata nodes feature. */ private static final String CREATE_CDATA_NODES_FEATURE = Constants.XERCES_FEATURE_PREFIX + Constants.CREATE_CDATA_NODES_FEATURE; /** Feature identifier: XInclude processing */ private static final String XINCLUDE_FEATURE = Constants.XERCES_FEATURE_PREFIX + Constants.XINCLUDE_FEATURE; /** feature identifier: XML Schema validation */ private static final String XMLSCHEMA_VALIDATION_FEATURE = Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE; /** Feature identifier: validation */ private static final String VALIDATION_FEATURE = Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; /** Property identifier: security manager. */ private static final String SECURITY_MANAGER = Constants.XERCES_PROPERTY_PREFIX + Constants.SECURITY_MANAGER_PROPERTY; /** Property identifier: Security property manager. */ private static final String XML_SECURITY_PROPERTY_MANAGER = Constants.XML_SECURITY_PROPERTY_MANAGER; /** property identifier: access external dtd. */ public static final String ACCESS_EXTERNAL_DTD = XMLConstants.ACCESS_EXTERNAL_DTD; /** Property identifier: access to external schema */ public static final String ACCESS_EXTERNAL_SCHEMA = XMLConstants.ACCESS_EXTERNAL_SCHEMA; private final DOMParser domParser; private final Schema grammar; private final XMLComponent fSchemaValidator; private final XMLComponentManager fSchemaValidatorComponentManager; private final ValidationManager fSchemaValidationManager; private final UnparsedEntityHandler fUnparsedEntityHandler; /** Initial ErrorHandler */ private final ErrorHandler fInitErrorHandler; /** Initial EntityResolver */ private final EntityResolver fInitEntityResolver; private XMLSecurityManager fSecurityManager; private XMLSecurityPropertyManager fSecurityPropertyMgr; DocumentBuilderImpl(DocumentBuilderFactoryImpl dbf, Map<String, Object> dbfAttrs, Map<String, Boolean> features) throws SAXNotRecognizedException, SAXNotSupportedException { this(dbf, dbfAttrs, features, false); } DocumentBuilderImpl(DocumentBuilderFactoryImpl dbf, Map<String, Object> dbfAttrs, Map<String, Boolean> features, boolean secureProcessing) throws SAXNotRecognizedException, SAXNotSupportedException { domParser = new DOMParser(); // If validating, provide a default ErrorHandler that prints // validation errors with a warning telling the user to set an // ErrorHandler if (dbf.isValidating()) { fInitErrorHandler = new DefaultValidationErrorHandler(domParser.getXMLParserConfiguration().getLocale()); setErrorHandler(fInitErrorHandler); } else { fInitErrorHandler = domParser.getErrorHandler(); } domParser.setFeature(VALIDATION_FEATURE, dbf.isValidating()); // "namespaceAware" == SAX Namespaces feature domParser.setFeature(NAMESPACES_FEATURE, dbf.isNamespaceAware()); // Set various parameters obtained from DocumentBuilderFactory domParser.setFeature(INCLUDE_IGNORABLE_WHITESPACE, !dbf.isIgnoringElementContentWhitespace()); domParser.setFeature(CREATE_ENTITY_REF_NODES_FEATURE, !dbf.isExpandEntityReferences()); domParser.setFeature(INCLUDE_COMMENTS_FEATURE, !dbf.isIgnoringComments()); domParser.setFeature(CREATE_CDATA_NODES_FEATURE, !dbf.isCoalescing()); // Avoid setting the XInclude processing feature if the value is false. // This will keep the configuration from throwing an exception if it // does not support XInclude. if (dbf.isXIncludeAware()) { domParser.setFeature(XINCLUDE_FEATURE, true); } fSecurityPropertyMgr = new XMLSecurityPropertyManager(); domParser.setProperty(XML_SECURITY_PROPERTY_MANAGER, fSecurityPropertyMgr); fSecurityManager = new XMLSecurityManager(secureProcessing); domParser.setProperty(SECURITY_MANAGER, fSecurityManager); if (secureProcessing) { /** * If secure processing is explicitly set on the factory, the * access properties will be set unless the corresponding * System Properties or jaxp.properties are set */ if (features != null) { Boolean temp = features.get(XMLConstants.FEATURE_SECURE_PROCESSING); if (temp != null && temp) { fSecurityPropertyMgr.setValue(Property.ACCESS_EXTERNAL_DTD, State.FSP, Constants.EXTERNAL_ACCESS_DEFAULT_FSP); fSecurityPropertyMgr.setValue(Property.ACCESS_EXTERNAL_SCHEMA, State.FSP, Constants.EXTERNAL_ACCESS_DEFAULT_FSP); } } } this.grammar = dbf.getSchema(); if (grammar != null) { XMLParserConfiguration config = domParser.getXMLParserConfiguration(); XMLComponent validatorComponent = null; /** For Xerces grammars, use built-in schema validator. **/ if (grammar instanceof XSGrammarPoolContainer) { validatorComponent = new XMLSchemaValidator(); fSchemaValidationManager = new ValidationManager(); fUnparsedEntityHandler = new UnparsedEntityHandler(fSchemaValidationManager); config.setDTDHandler(fUnparsedEntityHandler); fUnparsedEntityHandler.setDTDHandler(domParser); domParser.setDTDSource(fUnparsedEntityHandler); fSchemaValidatorComponentManager = new SchemaValidatorConfiguration(config, (XSGrammarPoolContainer) grammar, fSchemaValidationManager); } /** For third party grammars, use the JAXP validator component. **/ else { validatorComponent = new JAXPValidatorComponent(grammar.newValidatorHandler()); fSchemaValidationManager = null; fUnparsedEntityHandler = null; fSchemaValidatorComponentManager = config; } config.addRecognizedFeatures(validatorComponent.getRecognizedFeatures()); config.addRecognizedProperties(validatorComponent.getRecognizedProperties()); setFeatures(features); // Must set before calling setDocumentHandler() config.setDocumentHandler((XMLDocumentHandler) validatorComponent); ((XMLDocumentSource)validatorComponent).setDocumentHandler(domParser); domParser.setDocumentSource((XMLDocumentSource) validatorComponent); fSchemaValidator = validatorComponent; } else { fSchemaValidationManager = null; fUnparsedEntityHandler = null; fSchemaValidatorComponentManager = null; fSchemaValidator = null; setFeatures(features); } //setAttribute override those that may be set by other means setDocumentBuilderFactoryAttributes(dbfAttrs); // Initial EntityResolver fInitEntityResolver = domParser.getEntityResolver(); } private void setFeatures( Map<String, Boolean> features) throws SAXNotSupportedException, SAXNotRecognizedException { if (features != null) { for (Map.Entry<String, Boolean> entry : features.entrySet()) { domParser.setFeature(entry.getKey(), entry.getValue()); } } } /** * Set any DocumentBuilderFactory attributes of our underlying DOMParser * * Note: code does not handle possible conflicts between DOMParser * attribute names and JAXP specific attribute names, * eg. DocumentBuilderFactory.setValidating() */ private void setDocumentBuilderFactoryAttributes( Map<String, Object> dbfAttrs) throws SAXNotSupportedException, SAXNotRecognizedException { if (dbfAttrs == null) { // Nothing to do return; } for (Map.Entry<String, Object> entry : dbfAttrs.entrySet()) { String name = entry.getKey(); Object val = entry.getValue(); if (val instanceof Boolean) { // Assume feature domParser.setFeature(name, (Boolean)val); } else { // Assume property if (JAXP_SCHEMA_LANGUAGE.equals(name)) { // JAXP 1.2 support //None of the properties will take effect till the setValidating(true) has been called if ( W3C_XML_SCHEMA.equals(val) ) { if( isValidating() ) { domParser.setFeature(XMLSCHEMA_VALIDATION_FEATURE, true); // this should allow us not to emit DTD errors, as expected by the // spec when schema validation is enabled domParser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA); } } } else if(JAXP_SCHEMA_SOURCE.equals(name)){ if( isValidating() ) { String value=(String)dbfAttrs.get(JAXP_SCHEMA_LANGUAGE); if(value !=null && W3C_XML_SCHEMA.equals(value)){ domParser.setProperty(name, val); }else{ throw new IllegalArgumentException( DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "jaxp-order-not-supported", new Object[] {JAXP_SCHEMA_LANGUAGE, JAXP_SCHEMA_SOURCE})); } } } else { //check if the property is managed by security manager if (fSecurityManager == null || !fSecurityManager.setLimit(name, XMLSecurityManager.State.APIPROPERTY, val)) { //check if the property is managed by security property manager if (fSecurityPropertyMgr == null || !fSecurityPropertyMgr.setValue(name, XMLSecurityPropertyManager.State.APIPROPERTY, val)) { //fall back to the existing property manager domParser.setProperty(name, val); } } } } } } /** * Non-preferred: use the getDOMImplementation() method instead of this * one to get a DOM Level 2 DOMImplementation object and then use DOM * Level 2 methods to create a DOM Document object. */ public Document newDocument() { return new com.sun.org.apache.xerces.internal.dom.DocumentImpl(); } public DOMImplementation getDOMImplementation() { return DOMImplementationImpl.getDOMImplementation(); } public Document parse(InputSource is) throws SAXException, IOException { if (is == null) { throw new IllegalArgumentException( DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "jaxp-null-input-source", null)); } if (fSchemaValidator != null) { if (fSchemaValidationManager != null) { fSchemaValidationManager.reset(); fUnparsedEntityHandler.reset(); } resetSchemaValidator(); } domParser.parse(is); Document doc = domParser.getDocument(); domParser.dropDocumentReferences(); return doc; } public boolean isNamespaceAware() { try { return domParser.getFeature(NAMESPACES_FEATURE); } catch (SAXException x) { throw new IllegalStateException(x.getMessage()); } } public boolean isValidating() { try { return domParser.getFeature(VALIDATION_FEATURE); } catch (SAXException x) { throw new IllegalStateException(x.getMessage()); } } /** * Gets the XInclude processing mode for this parser * @return the state of XInclude processing mode */ public boolean isXIncludeAware() { try { return domParser.getFeature(XINCLUDE_FEATURE); } catch (SAXException exc) { return false; } } public void setEntityResolver(EntityResolver er) { domParser.setEntityResolver(er); } public void setErrorHandler(ErrorHandler eh) { domParser.setErrorHandler(eh); } public Schema getSchema() { return grammar; } public void reset() { /** Restore the initial error handler. **/ if (domParser.getErrorHandler() != fInitErrorHandler) { domParser.setErrorHandler(fInitErrorHandler); } /** Restore the initial entity resolver. **/ if (domParser.getEntityResolver() != fInitEntityResolver) { domParser.setEntityResolver(fInitEntityResolver); } } // package private DOMParser getDOMParser() { return domParser; } private void resetSchemaValidator() throws SAXException { try { fSchemaValidator.reset(fSchemaValidatorComponentManager); } // This should never be thrown from the schema validator. catch (XMLConfigurationException e) { throw new SAXException(e); } } }