org.hibernate.util.xml.MappingReader.java Source code

Java tutorial

Introduction

Here is the source code for org.hibernate.util.xml.MappingReader.java

Source

/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * Copyright (c) 2010, Red Hat Inc. or third-party contributors as
 * indicated by the @author tags or express copyright attribution
 * statements applied by the authors.  All third-party contributions are
 * distributed under license by Red Hat Inc.
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package org.hibernate.util.xml;

import java.io.StringReader;

import org.dom4j.Document;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import org.hibernate.InvalidMappingException;

/**
 * Handles reading mapping documents, both {@code hbm} and {@code orm} varieties.
 *
 * @author Steve Ebersole
 */
public class MappingReader {
    private static final Logger log = LoggerFactory.getLogger(MappingReader.class);

    public static final String ASSUMED_ORM_XSD_VERSION = "2.0";
    public static final MappingReader INSTANCE = new MappingReader();

    /**
     * Disallow direct instantiation.
     * <p/>
     * Eventually we perhaps need to have this configurable by the "configuration" and simply reference it
     * from there (registry).  This would allow, for example, injection of the entity resolver to use as
     * instance state.
     */
    private MappingReader() {
    }

    public XmlDocument readMappingDocument(EntityResolver entityResolver, InputSource source, Origin origin) {
        // IMPL NOTE : this is the legacy logic as pulled from the old AnnotationConfiguration code

        Exception failure;
        ErrorLogger errorHandler = new ErrorLogger();

        SAXReader saxReader = new SAXReader();
        saxReader.setEntityResolver(entityResolver);
        saxReader.setErrorHandler(errorHandler);
        saxReader.setMergeAdjacentText(true);
        saxReader.setValidation(true);

        Document document = null;
        try {
            // first try with orm 2.0 xsd validation
            setValidationFor(saxReader, "orm_2_0.xsd");
            document = saxReader.read(source);
            if (errorHandler.getError() != null) {
                throw errorHandler.getError();
            }
            return new XmlDocumentImpl(document, origin.getType(), origin.getName());
        } catch (Exception orm2Problem) {
            log.debug("Problem parsing XML using orm 2 xsd : {}", orm2Problem.getMessage());
            failure = orm2Problem;
            errorHandler.reset();

            if (document != null) {
                // next try with orm 1.0 xsd validation
                try {
                    setValidationFor(saxReader, "orm_1_0.xsd");
                    document = saxReader.read(new StringReader(document.asXML()));
                    if (errorHandler.getError() != null) {
                        throw errorHandler.getError();
                    }
                    return new XmlDocumentImpl(document, origin.getType(), origin.getName());
                } catch (Exception orm1Problem) {
                    log.debug("Problem parsing XML using orm 1 xsd : {}", orm1Problem.getMessage());
                }
            }
        }
        throw new InvalidMappingException("Unable to read XML", origin.getType(), origin.getName(), failure);
    }

    private void setValidationFor(SAXReader saxReader, String xsd) {
        try {
            saxReader.setFeature("http://apache.org/xml/features/validation/schema", true);
            //saxReader.setFeature( "http://apache.org/xml/features/validation/dynamic", true );
            //set the default schema locators
            saxReader.setProperty("http://apache.org/xml/properties/schema/external-schemaLocation",
                    "http://java.sun.com/xml/ns/persistence/orm " + xsd);
        } catch (SAXException e) {
            saxReader.setValidation(false);
        }
    }

    // this is the version of the code I'd like to use, but it unfortunately works very differently between
    // JDK 1.5 ad JDK 1.6.  On 1.5 the vaildation "passes" even with invalid content.
    //
    // Options:
    //       1) continue using the code above
    //      2) Document the issue on 1.5 and how to fix (specifying alternate SchemaFactory instance)
    //      3) Use a specific JAXP library (Xerces2, Saxon, Jing, MSV) and its SchemaFactory instance directly

    //   public XmlDocument readMappingDocument(EntityResolver entityResolver, InputSource source, Origin origin) {
    //      ErrorLogger errorHandler = new ErrorLogger();
    //
    //      SAXReader saxReader = new SAXReader( new DOMDocumentFactory() );
    //      saxReader.setEntityResolver( entityResolver );
    //      saxReader.setErrorHandler( errorHandler );
    //      saxReader.setMergeAdjacentText( true );
    //
    //      Document documentTree = null;
    //
    //      // IMPL NOTE : here we enable DTD validation in case the mapping is a HBM file.  This will validate
    //      // the document as it is parsed.  This is needed because the DTD defines default values that have to be
    //      // applied as the document is parsed, so thats something we need to account for as we (if we) transition
    //      // to XSD.
    //      saxReader.setValidation( true );
    //      try {
    //         documentTree = saxReader.read( source );
    //      }
    //      catch ( DocumentException e ) {
    //         // we had issues reading the input, most likely malformed document or validation error against DTD
    //         throw new InvalidMappingException( "Unable to read XML", origin.getType(), origin.getName(), e );
    //      }
    //
    //      Element rootElement = documentTree.getRootElement();
    //      if ( rootElement ==  null ) {
    //         throw new InvalidMappingException( "No root element", origin.getType(), origin.getName() );
    //      }
    //
    //      if ( "entity-mappings".equals( rootElement.getName() ) ) {
    //         final String explicitVersion = rootElement.attributeValue( "version" );
    //         final String xsdVersionString = explicitVersion == null ? ASSUMED_ORM_XSD_VERSION : explicitVersion;
    //         final SupportedOrmXsdVersion xsdVersion = SupportedOrmXsdVersion.parse( xsdVersionString );
    //         final Schema schema = xsdVersion == SupportedOrmXsdVersion.ORM_1_0 ? orm1Schema() : orm2Schema();
    //         try {
    //            schema.newValidator().validate( new DOMSource( (org.w3c.dom.Document) documentTree ) );
    //         }
    //         catch ( SAXException e ) {
    //            throw new InvalidMappingException( "Validation problem", origin.getType(), origin.getName(), e );
    //         }
    //         catch ( IOException e ) {
    //            throw new InvalidMappingException( "Validation problem", origin.getType(), origin.getName(), e );
    //         }
    //      }
    //      else {
    //         if ( errorHandler.getError() != null ) {
    //            throw new InvalidMappingException(
    //                  "Error validating hibernate-mapping against DTD",
    //                  origin.getType(),
    //                  origin.getName(),
    //                  errorHandler.getError()
    //            );
    //         }
    //      }
    //
    //      return new XmlDocumentImpl( documentTree, origin );
    //   }
    //
    //   public static enum SupportedOrmXsdVersion {
    //      ORM_1_0,
    //      ORM_2_0;
    //
    //      public static SupportedOrmXsdVersion parse(String name) {
    //         if ( "1.0".equals( name ) ) {
    //            return ORM_1_0;
    //         }
    //         else if ( "2.0".equals( name ) ) {
    //            return ORM_2_0;
    //         }
    //         throw new IllegalArgumentException( "Unsupported orm.xml XSD version encountered [" + name + "]" );
    //      }
    //   }
    //
    //
    //   public static final String ORM_1_SCHEMA_NAME = "org/hibernate/ejb/orm_1_0.xsd";
    //   public static final String ORM_2_SCHEMA_NAME = "org/hibernate/ejb/orm_2_0.xsd";
    //
    //   private static Schema orm1Schema;
    //
    //   private static Schema orm1Schema() {
    //      if ( orm1Schema == null ) {
    //         orm1Schema = resolveLocalSchema( ORM_1_SCHEMA_NAME );
    //      }
    //      return orm1Schema;
    //   }
    //
    //   private static Schema orm2Schema;
    //
    //   private static Schema orm2Schema() {
    //      if ( orm2Schema == null ) {
    //         orm2Schema = resolveLocalSchema( ORM_2_SCHEMA_NAME );
    //      }
    //      return orm2Schema;
    //   }
    //
    //   private static Schema resolveLocalSchema(String schemaName) {
    //      return resolveLocalSchema( schemaName, XMLConstants.W3C_XML_SCHEMA_NS_URI );
    //   }
    //
    //   private static Schema resolveLocalSchema(String schemaName, String schemaLanguage) {
    //        URL url = ConfigHelper.findAsResource( schemaName );
    //      if ( url == null ) {
    //         throw new MappingException( "Unable to locate schema [" + schemaName + "] via classpath" );
    //      }
    //      try {
    //         InputStream schemaStream = url.openStream();
    //         try {
    //            StreamSource source = new StreamSource(url.openStream());
    //            SchemaFactory schemaFactory = SchemaFactory.newInstance( schemaLanguage );
    //            return schemaFactory.newSchema(source);
    //         }
    //         catch ( SAXException e ) {
    //            throw new MappingException( "Unable to load schema [" + schemaName + "]", e );
    //         }
    //         catch ( IOException e ) {
    //            throw new MappingException( "Unable to load schema [" + schemaName + "]", e );
    //         }
    //         finally {
    //            try {
    //               schemaStream.close();
    //            }
    //            catch ( IOException e ) {
    //               log.warn( "Problem closing schema stream [{}]", e.toString() );
    //            }
    //         }
    //      }
    //      catch ( IOException e ) {
    //         throw new MappingException( "Stream error handling schema url [" + url.toExternalForm() + "]" );
    //      }
    //
    //   }
}