Open Source Repository

Home /spring/spring-beans-3.0.5 | Repository Home



org/springframework/beans/factory/xml/DefaultDocumentLoader.java
/*
 * Copyright 2002-2007 the original author or authors.
 *
 * Licensed 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 org.springframework.beans.factory.xml;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;

import org.springframework.util.xml.XmlValidationModeDetector;

/**
 * Spring's default {@link DocumentLoader} implementation.
 *
 <p>Simply loads {@link Document documents} using the standard JAXP-configured
 * XML parser. If you want to change the {@link DocumentBuilder} that is used to
 * load documents, then one strategy is to define a corresponding Java system property
 * when starting your JVM. For example, to use the Oracle {@link DocumentBuilder},
 * you might start your application like as follows:
 *
 <pre code="class">java -Djavax.xml.parsers.DocumentBuilderFactory=oracle.xml.jaxp.JXDocumentBuilderFactory MyMainClass</pre>
 *
 @author Rob Harrop
 @author Juergen Hoeller
 @since 2.0
 */
public class DefaultDocumentLoader implements DocumentLoader {

  /**
   * JAXP attribute used to configure the schema language for validation.
   */
  private static final String SCHEMA_LANGUAGE_ATTRIBUTE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";

  /**
   * JAXP attribute value indicating the XSD schema language.
   */
  private static final String XSD_SCHEMA_LANGUAGE = "http://www.w3.org/2001/XMLSchema";


  private static final Log logger = LogFactory.getLog(DefaultDocumentLoader.class);


  /**
   * Load the {@link Document} at the supplied {@link InputSource} using the standard JAXP-configured
   * XML parser.
   */
  public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
      ErrorHandler errorHandler, int validationMode, boolean namespaceAwarethrows Exception {

    DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
    if (logger.isDebugEnabled()) {
      logger.debug("Using JAXP provider [" + factory.getClass().getName() "]");
    }
    DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
    return builder.parse(inputSource);
  }

  /**
   * Create the {@link DocumentBuilderFactory} instance.
   @param validationMode the type of validation: {@link XmlValidationModeDetector#VALIDATION_DTD DTD}
   * or {@link XmlValidationModeDetector#VALIDATION_XSD XSD})
   @param namespaceAware whether the returned factory is to provide support for XML namespaces
   @return the JAXP DocumentBuilderFactory
   @throws ParserConfigurationException if we failed to build a proper DocumentBuilderFactory
   */
  protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware)
      throws ParserConfigurationException {

    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    factory.setNamespaceAware(namespaceAware);

    if (validationMode != XmlValidationModeDetector.VALIDATION_NONE) {
      factory.setValidating(true);

      if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) {
        // Enforce namespace aware for XSD...
        factory.setNamespaceAware(true);
        try {
          factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE);
        }
        catch (IllegalArgumentException ex) {
          ParserConfigurationException pcex = new ParserConfigurationException(
              "Unable to validate using XSD: Your JAXP provider [" + factory +
              "] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? " +
              "Upgrade to Apache Xerces (or Java 1.5) for full XSD support.");
          pcex.initCause(ex);
          throw pcex;
        }
      }
    }

    return factory;
  }

  /**
   * Create a JAXP DocumentBuilder that this bean definition reader
   * will use for parsing XML documents. Can be overridden in subclasses,
   * adding further initialization of the builder.
   @param factory the JAXP DocumentBuilderFactory that the DocumentBuilder
   * should be created with
   @param entityResolver the SAX EntityResolver to use
   @param errorHandler the SAX ErrorHandler to use
   @return the JAXP DocumentBuilder
   @throws ParserConfigurationException if thrown by JAXP methods
   */
  protected DocumentBuilder createDocumentBuilder(
      DocumentBuilderFactory factory, EntityResolver entityResolver, ErrorHandler errorHandler)
      throws ParserConfigurationException {

    DocumentBuilder docBuilder = factory.newDocumentBuilder();
    if (entityResolver != null) {
      docBuilder.setEntityResolver(entityResolver);
    }
    if (errorHandler != null) {
      docBuilder.setErrorHandler(errorHandler);
    }
    return docBuilder;
  }

}