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: import org.springframework.util.xml.XmlValidationModeDetector;
031:
032: /**
033: * The default {@link DocumentLoader} implementation.
034: *
035: * <p>Simply loads {@link Document documents} using the standard JAXP-configured
036: * XML parser. If you want to change the {@link DocumentBuilder} that is used to
037: * load documents then one strategy is to use a Java define when starting your
038: * application. For example, to use the Oracle {@link DocumentBuilder}, one might
039: * start one's application like so:
040: *
041: * <pre code="class">java -Djavax.xml.parsers.DocumentBuilderFactory=oracle.xml.jaxp.JXDocumentBuilderFactory MyMainClass</pre>
042: *
043: * @author Rob Harrop
044: * @author Juergen Hoeller
045: * @since 2.0
046: */
047: public class DefaultDocumentLoader implements DocumentLoader {
048:
049: /**
050: * JAXP attribute used to configure the schema language for validation.
051: */
052: private static final String SCHEMA_LANGUAGE_ATTRIBUTE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
053:
054: /**
055: * JAXP attribute value indicating the XSD schema language.
056: */
057: private static final String XSD_SCHEMA_LANGUAGE = "http://www.w3.org/2001/XMLSchema";
058:
059: private static final Log logger = LogFactory
060: .getLog(DefaultDocumentLoader.class);
061:
062: /**
063: * Load the {@link Document} at the supplied {@link InputSource} using the standard JAXP-configured
064: * XML parser.
065: */
066: public Document loadDocument(InputSource inputSource,
067: EntityResolver entityResolver, ErrorHandler errorHandler,
068: int validationMode, boolean namespaceAware)
069: throws Exception {
070:
071: DocumentBuilderFactory factory = createDocumentBuilderFactory(
072: validationMode, namespaceAware);
073: if (logger.isDebugEnabled()) {
074: logger.debug("Using JAXP provider ["
075: + factory.getClass().getName() + "]");
076: }
077: DocumentBuilder builder = createDocumentBuilder(factory,
078: entityResolver, errorHandler);
079: return builder.parse(inputSource);
080: }
081:
082: /**
083: * Create the {@link DocumentBuilderFactory} instance.
084: * @param validationMode the type of validation {@link XmlValidationModeDetector#VALIDATION_DTD DTD}
085: * or {@link XmlValidationModeDetector#VALIDATION_XSD XSD})
086: * @param namespaceAware <code>true</code> if the returned factory is to provide support for XML namespaces
087: * @return the JAXP DocumentBuilderFactory
088: * @throws ParserConfigurationException if we failed to build a proper DocumentBuilderFactory
089: */
090: protected DocumentBuilderFactory createDocumentBuilderFactory(
091: int validationMode, boolean namespaceAware)
092: throws ParserConfigurationException {
093:
094: DocumentBuilderFactory factory = DocumentBuilderFactory
095: .newInstance();
096: factory.setNamespaceAware(namespaceAware);
097:
098: if (validationMode != XmlValidationModeDetector.VALIDATION_NONE) {
099: factory.setValidating(true);
100:
101: if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) {
102: // enforce namespace aware for XSD
103: factory.setNamespaceAware(true);
104: try {
105: factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE,
106: XSD_SCHEMA_LANGUAGE);
107: } catch (IllegalArgumentException ex) {
108: throw new ParserConfigurationException(
109: "Unable to validate using XSD: Your JAXP provider ["
110: + factory
111: + "] does not support XML Schema. Are you running on Java 1.4 or below with "
112: + "Apache Crimson? Upgrade to Apache Xerces (or Java 1.5) for full XSD support.");
113: }
114: }
115: }
116:
117: return factory;
118: }
119:
120: /**
121: * Create a JAXP DocumentBuilder that this bean definition reader
122: * will use for parsing XML documents. Can be overridden in subclasses,
123: * adding further initialization of the builder.
124: * @param factory the JAXP DocumentBuilderFactory that the DocumentBuilder
125: * should be created with
126: * @param entityResolver the SAX EntityResolver to use
127: * @param errorHandler the SAX ErrorHandler to use
128: * @return the JAXP DocumentBuilder
129: * @throws ParserConfigurationException if thrown by JAXP methods
130: */
131: protected DocumentBuilder createDocumentBuilder(
132: DocumentBuilderFactory factory,
133: EntityResolver entityResolver, ErrorHandler errorHandler)
134: throws ParserConfigurationException {
135:
136: DocumentBuilder docBuilder = factory.newDocumentBuilder();
137: if (entityResolver != null) {
138: docBuilder.setEntityResolver(entityResolver);
139: }
140: if (errorHandler != null) {
141: docBuilder.setErrorHandler(errorHandler);
142: }
143: return docBuilder;
144: }
145:
146: }
|