001: /*
002: * Copyright 2002-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.beans.factory.xml;
018:
019: import javax.xml.parsers.DocumentBuilder;
020: import javax.xml.parsers.DocumentBuilderFactory;
021: import javax.xml.parsers.ParserConfigurationException;
022:
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025: import org.w3c.dom.Document;
026: import org.xml.sax.EntityResolver;
027: import org.xml.sax.ErrorHandler;
028: import org.xml.sax.InputSource;
029:
030: /**
031: * The default {@link DocumentLoader} implementation.
032: *
033: * <p>Simply loads {@link Document documents} using the standard JAXP-configured
034: * XML parser. If you want to change the {@link DocumentBuilder} that is used to
035: * load documents then one strategy is to use a Java define when starting your
036: * application. For example, to use the Oracle {@link DocumentBuilder}, one might
037: * start one's application like so:
038: *
039: * <pre code="class">java -Djavax.xml.parsers.DocumentBuilderFactory=oracle.xml.jaxp.JXDocumentBuilderFactory MyMainClass</pre>
040: *
041: * @author Rob Harrop
042: * @author Juergen Hoeller
043: * @since 2.0
044: */
045: public class DefaultDocumentLoader implements DocumentLoader {
046:
047: /**
048: * JAXP attribute used to configure the schema language for validation.
049: */
050: private static final String SCHEMA_LANGUAGE_ATTRIBUTE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
051:
052: /**
053: * JAXP attribute value indicating the XSD schema language.
054: */
055: private static final String XSD_SCHEMA_LANGUAGE = "http://www.w3.org/2001/XMLSchema";
056:
057: private static final Log logger = LogFactory
058: .getLog(DefaultDocumentLoader.class);
059:
060: /**
061: * Load the {@link Document} at the supplied {@link InputSource} using the standard JAXP-configured
062: * XML parser.
063: */
064: public Document loadDocument(InputSource inputSource,
065: EntityResolver entityResolver, ErrorHandler errorHandler,
066: int validationMode, boolean namespaceAware)
067: throws Exception {
068:
069: DocumentBuilderFactory factory = createDocumentBuilderFactory(
070: validationMode, namespaceAware);
071: if (logger.isDebugEnabled()) {
072: logger.debug("Using JAXP provider ["
073: + factory.getClass().getName() + "]");
074: }
075: DocumentBuilder builder = createDocumentBuilder(factory,
076: entityResolver, errorHandler);
077: return builder.parse(inputSource);
078: }
079:
080: /**
081: * Create the {@link DocumentBuilderFactory} instance.
082: * @param validationMode the type of validation ({@link XmlBeanDefinitionReader#VALIDATION_NONE none}, {@link XmlBeanDefinitionReader#VALIDATION_DTD DTD}, or {@link XmlBeanDefinitionReader#VALIDATION_XSD XSD})
083: * @param namespaceAware <code>true</code> if the returned factory is to provide support for XML namespaces
084: * @throws ParserConfigurationException if we failed to build a proper DocumentBuilderFactory
085: */
086: protected DocumentBuilderFactory createDocumentBuilderFactory(
087: int validationMode, boolean namespaceAware)
088: throws ParserConfigurationException {
089:
090: DocumentBuilderFactory factory = DocumentBuilderFactory
091: .newInstance();
092: factory.setNamespaceAware(namespaceAware);
093:
094: if (validationMode != XmlBeanDefinitionReader.VALIDATION_NONE) {
095: factory.setValidating(true);
096:
097: if (validationMode == XmlBeanDefinitionReader.VALIDATION_XSD) {
098: // enforce namespace aware for XSD
099: factory.setNamespaceAware(true);
100: try {
101: factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE,
102: XSD_SCHEMA_LANGUAGE);
103: } catch (IllegalArgumentException ex) {
104: throw new ParserConfigurationException(
105: "Unable to validate using XSD: Your JAXP provider ["
106: + factory
107: + "] does not support XML Schema. Are you running on Java 1.4 or below with "
108: + "Apache Crimson? Upgrade to Apache Xerces (or Java 1.5) for full XSD support.");
109: }
110: }
111: }
112:
113: return factory;
114: }
115:
116: /**
117: * Create a JAXP DocumentBuilder that this bean definition reader
118: * will use for parsing XML documents. Can be overridden in subclasses,
119: * adding further initialization of the builder.
120: * @param factory the JAXP DocumentBuilderFactory that the DocumentBuilder
121: * should be created with
122: * @return the JAXP DocumentBuilder
123: * @throws ParserConfigurationException if thrown by JAXP methods
124: */
125: protected DocumentBuilder createDocumentBuilder(
126: DocumentBuilderFactory factory,
127: EntityResolver entityResolver, ErrorHandler errorHandler)
128: throws ParserConfigurationException {
129:
130: DocumentBuilder docBuilder = factory.newDocumentBuilder();
131: if (entityResolver != null) {
132: docBuilder.setEntityResolver(entityResolver);
133: }
134: if (errorHandler != null) {
135: docBuilder.setErrorHandler(errorHandler);
136: }
137: return docBuilder;
138: }
139:
140: }
|