HHH-7981 - Load (now) locally defined orm.xsd while processing orm.xml files
This commit is contained in:
parent
06ab065272
commit
a1afa0ce35
|
@ -23,19 +23,9 @@
|
|||
*/
|
||||
package org.hibernate.internal.util.xml;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.io.StringReader;
|
||||
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.Element;
|
||||
import org.dom4j.dom.DOMDocumentFactory;
|
||||
import org.dom4j.io.SAXReader;
|
||||
import org.xml.sax.EntityResolver;
|
||||
import org.xml.sax.InputSource;
|
||||
|
@ -44,9 +34,7 @@ import org.xml.sax.SAXException;
|
|||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.InvalidMappingException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.ConfigHelper;
|
||||
|
||||
/**
|
||||
* Handles reading mapping documents, both {@code hbm} and {@code orm} varieties.
|
||||
|
@ -54,14 +42,11 @@ import org.hibernate.internal.util.ConfigHelper;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class MappingReader {
|
||||
|
||||
private static final CoreMessageLogger log = Logger.getMessageLogger(
|
||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
|
||||
CoreMessageLogger.class,
|
||||
MappingReader.class.getName()
|
||||
);
|
||||
|
||||
public static final String ASSUMED_ORM_XSD_VERSION = "2.1";
|
||||
|
||||
public static final MappingReader INSTANCE = new MappingReader();
|
||||
|
||||
/**
|
||||
|
@ -74,204 +59,88 @@ public class MappingReader {
|
|||
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.hasErrors() ) {
|
||||
// throw errorHandler.getErrors().get( 0 );
|
||||
// }
|
||||
// return new XmlDocumentImpl( document, origin.getType(), origin.getName() );
|
||||
// }
|
||||
// catch ( Exception orm2Problem ) {
|
||||
// if ( LOG.isDebugEnabled() ) {
|
||||
// LOG.debugf( "Problem parsing XML using orm 2 xsd : %s", 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.hasErrors() ) {
|
||||
// errorHandler.logErrors();
|
||||
// throw errorHandler.getErrors().get( 0 );
|
||||
// }
|
||||
// return new XmlDocumentImpl( document, origin.getType(), origin.getName() );
|
||||
// }
|
||||
// catch ( Exception orm1Problem ) {
|
||||
// if ( LOG.isDebugEnabled() ) {
|
||||
// LOG.debugf( "Problem parsing XML using orm 1 xsd : %s", 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) {
|
||||
// IMPL NOTE : this is the legacy logic as pulled from the old AnnotationConfiguration code
|
||||
|
||||
Exception failure;
|
||||
|
||||
ErrorLogger errorHandler = new ErrorLogger();
|
||||
|
||||
SAXReader saxReader = new SAXReader( new DOMDocumentFactory() );
|
||||
SAXReader saxReader = new SAXReader();
|
||||
saxReader.setEntityResolver( entityResolver );
|
||||
saxReader.setErrorHandler( errorHandler );
|
||||
saxReader.setMergeAdjacentText( true );
|
||||
|
||||
Document documentTree;
|
||||
|
||||
// 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 );
|
||||
|
||||
Document document = null;
|
||||
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, origin );
|
||||
final Schema schema = xsdVersion.getSchema();
|
||||
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 {
|
||||
// first try with orm 2.1 xsd validation
|
||||
setValidationFor( saxReader, "orm_2_1.xsd" );
|
||||
document = saxReader.read( source );
|
||||
if ( errorHandler.hasErrors() ) {
|
||||
errorHandler.logErrors();
|
||||
errorHandler.reset();
|
||||
throw new InvalidMappingException(
|
||||
"Error validating hibernate-mapping against DTD; see logs for details",
|
||||
origin.getType(),
|
||||
origin.getName()
|
||||
);
|
||||
throw errorHandler.getErrors().get( 0 );
|
||||
}
|
||||
return new XmlDocumentImpl( document, origin.getType(), origin.getName() );
|
||||
}
|
||||
|
||||
return new XmlDocumentImpl( documentTree, origin );
|
||||
}
|
||||
|
||||
public static enum SupportedOrmXsdVersion {
|
||||
ORM_1_0( "org/hibernate/jpa/orm_1_0.xsd" ),
|
||||
ORM_2_0( "org/hibernate/jpa/orm_2_0.xsd"),
|
||||
ORM_2_1( "org/hibernate/jpa/orm_2_1.xsd");
|
||||
|
||||
private final String schemaResourceName;
|
||||
private Schema schema;
|
||||
|
||||
private SupportedOrmXsdVersion(String schemaResourceName) {
|
||||
this.schemaResourceName = schemaResourceName;
|
||||
}
|
||||
|
||||
public static SupportedOrmXsdVersion parse(String name, Origin origin) {
|
||||
if ( "1.0".equals( name ) ) {
|
||||
return ORM_1_0;
|
||||
catch ( Exception e ) {
|
||||
if ( LOG.isDebugEnabled() ) {
|
||||
LOG.debugf( "Problem parsing XML using orm 2.1 xsd, trying 2.0 xsd : %s", e.getMessage() );
|
||||
}
|
||||
else if ( "2.0".equals( name ) ) {
|
||||
return ORM_2_0;
|
||||
}
|
||||
else if ( "2.1".equals( name ) ) {
|
||||
return ORM_2_1;
|
||||
}
|
||||
throw new UnsupportedOrmXsdVersionException( name, origin );
|
||||
}
|
||||
failure = e;
|
||||
errorHandler.reset();
|
||||
|
||||
public Schema getSchema() {
|
||||
if ( schema == null ) {
|
||||
schema = resolveLocalSchema( schemaResourceName );
|
||||
}
|
||||
return schema;
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
if ( document != null ) {
|
||||
// next try with orm 2.0 xsd validation
|
||||
try {
|
||||
schemaStream.close();
|
||||
setValidationFor( saxReader, "orm_2_0.xsd" );
|
||||
document = saxReader.read( new StringReader( document.asXML() ) );
|
||||
if ( errorHandler.hasErrors() ) {
|
||||
errorHandler.logErrors();
|
||||
throw errorHandler.getErrors().get( 0 );
|
||||
}
|
||||
return new XmlDocumentImpl( document, origin.getType(), origin.getName() );
|
||||
}
|
||||
catch ( IOException e ) {
|
||||
log.debugf( "Problem closing schema stream - %s", e.toString() );
|
||||
catch ( Exception e2 ) {
|
||||
if ( LOG.isDebugEnabled() ) {
|
||||
LOG.debugf( "Problem parsing XML using orm 2.0 xsd, trying 1.0 xsd : %s", e2.getMessage() );
|
||||
}
|
||||
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.hasErrors() ) {
|
||||
errorHandler.logErrors();
|
||||
throw errorHandler.getErrors().get( 0 );
|
||||
}
|
||||
return new XmlDocumentImpl( document, origin.getType(), origin.getName() );
|
||||
}
|
||||
catch ( Exception e3 ) {
|
||||
if ( LOG.isDebugEnabled() ) {
|
||||
LOG.debugf( "Problem parsing XML using orm 1.0 xsd : %s", e3.getMessage() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( IOException e ) {
|
||||
throw new MappingException( "Stream error handling schema url [" + url.toExternalForm() + "]" );
|
||||
}
|
||||
|
||||
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 );
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, 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.internal.util.xml;
|
||||
|
||||
import org.hibernate.InvalidMappingException;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class UnsupportedOrmXsdVersionException extends InvalidMappingException {
|
||||
public UnsupportedOrmXsdVersionException(String version, Origin origin) {
|
||||
super( "Encountered unsupported orm.xml xsd version [" + version + "]", origin.getType(), origin.getName() );
|
||||
}
|
||||
}
|
|
@ -25,8 +25,8 @@ package org.hibernate.test.annotations.xml.ejb3;
|
|||
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.hibernate.InvalidMappingException;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.internal.util.xml.UnsupportedOrmXsdVersionException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -47,7 +47,7 @@ public class NonExistentOrmVersionTest extends BaseCoreFunctionalTestCase {
|
|||
config.buildMappings();
|
||||
fail( "Expecting failure due to unsupported xsd version" );
|
||||
}
|
||||
catch ( UnsupportedOrmXsdVersionException expected ) {
|
||||
catch ( InvalidMappingException expected ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue