From 775e02233107525055538c61f0b4c1a668145821 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Wed, 13 Apr 2011 14:47:18 -0500 Subject: [PATCH] HHH-6118 - Make Metadata more user-friendly API --- .../org/hibernate/HibernateException.java | 10 +- .../metamodel/source/MappingException.java | 50 +++ .../source/MappingNotFoundException.java | 46 +++ .../hibernate/metamodel/source/Metadata.java | 266 ++++++------- .../source/{util/xml => }/Origin.java | 23 +- .../xml/JaxbRoot.java => SourceType.java} | 29 +- .../metamodel/source/XsdException.java | 50 +++ .../source/annotations/AnnotationBinder.java | 6 +- .../source/annotations/EntityBinder.java | 4 +- .../source/annotations/OrmXmlParser.java | 6 +- .../source/hbm/AbstractEntityBinder.java | 4 +- .../source/hbm/HibernateXmlBinder.java | 29 +- .../source/{ => internal}/ExtendsQueue.java | 51 +-- .../metamodel/source/internal/JaxbHelper.java | 213 ++++++++++ .../JaxbRoot.java} | 19 +- .../source/internal/MetadataImpl.java | 371 ++++++++++++++++++ .../{ => internal}/MetadataSourceQueue.java | 6 +- .../MetadataImplementor.java} | 34 +- .../metamodel/source/util/xml/XmlHelper.java | 6 +- .../binding/BasicAnnotationBindingTests.java | 7 +- .../binding/BasicHbmBindingTests.java | 6 +- .../source/annotations/OrmXmlParserTests.java | 6 +- 22 files changed, 990 insertions(+), 252 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/source/MappingException.java create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/source/MappingNotFoundException.java rename hibernate-core/src/main/java/org/hibernate/metamodel/source/{util/xml => }/Origin.java (78%) rename hibernate-core/src/main/java/org/hibernate/metamodel/source/{util/xml/JaxbRoot.java => SourceType.java} (75%) create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/source/XsdException.java rename hibernate-core/src/main/java/org/hibernate/metamodel/source/{ => internal}/ExtendsQueue.java (69%) create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/JaxbHelper.java rename hibernate-core/src/main/java/org/hibernate/metamodel/source/{util/xml/JaxbRootImpl.java => internal/JaxbRoot.java} (76%) create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java rename hibernate-core/src/main/java/org/hibernate/metamodel/source/{ => internal}/MetadataSourceQueue.java (97%) rename hibernate-core/src/main/java/org/hibernate/metamodel/source/{util/xml/OriginImpl.java => spi/MetadataImplementor.java} (70%) diff --git a/hibernate-core/src/main/java/org/hibernate/HibernateException.java b/hibernate-core/src/main/java/org/hibernate/HibernateException.java index 722099fa4c..52be3448b4 100644 --- a/hibernate-core/src/main/java/org/hibernate/HibernateException.java +++ b/hibernate-core/src/main/java/org/hibernate/HibernateException.java @@ -35,16 +35,16 @@ package org.hibernate; * @author Gavin King */ public class HibernateException extends RuntimeException { - public HibernateException(String s) { - super(s); + public HibernateException(String message) { + super( message ); } public HibernateException(Throwable root) { - super(root); + super( root ); } - public HibernateException(String string, Throwable root) { - super(string, root); + public HibernateException(String message, Throwable root) { + super( message, root ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/MappingException.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/MappingException.java new file mode 100644 index 0000000000..279879e41f --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/MappingException.java @@ -0,0 +1,50 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.metamodel.source; + +import org.hibernate.HibernateException; + +/** + * Indicates a problem parsing a mapping document. + * + * @author Steve Ebersole + */ +public class MappingException extends HibernateException { + private final Origin origin; + + public MappingException(String message, Origin origin) { + super( message ); + this.origin = origin; + } + + public MappingException(String message, Throwable root, Origin origin) { + super( message, root ); + this.origin = origin; + } + + public Origin getOrigin() { + return origin; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/MappingNotFoundException.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/MappingNotFoundException.java new file mode 100644 index 0000000000..3e56633c35 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/MappingNotFoundException.java @@ -0,0 +1,46 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.metamodel.source; + +/** + * @author Steve Ebersole + */ +public class MappingNotFoundException extends MappingException { + public MappingNotFoundException(String message, Origin origin) { + super( message, origin ); + } + + public MappingNotFoundException(Origin origin) { + super( String.format( "Mapping (%s) not found : %s", origin.getType(), origin.getName() ), origin ); + } + + public MappingNotFoundException(String message, Throwable root, Origin origin) { + super( message, root, origin ); + } + + public MappingNotFoundException(Throwable root, Origin origin) { + super( String.format( "Mapping (%s) not found : %s", origin.getType(), origin.getName() ), root, origin ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/Metadata.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/Metadata.java index e19d7def70..2ef0eb9e97 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/Metadata.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/Metadata.java @@ -1,7 +1,7 @@ /* * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright (c) 2010, Red Hat Inc. or third-party contributors as + * Copyright (c) 2011, 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. @@ -21,156 +21,160 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ + package org.hibernate.metamodel.source; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; +import java.io.File; +import java.io.InputStream; +import java.net.URL; -import org.jboss.logging.Logger; - -import org.hibernate.DuplicateMappingException; -import org.hibernate.cfg.EJB3NamingStrategy; -import org.hibernate.cfg.NamingStrategy; -import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.mapping.FetchProfile; -import org.hibernate.mapping.MetadataSource; -import org.hibernate.metamodel.binding.EntityBinding; -import org.hibernate.metamodel.binding.PluralAttributeBinding; -import org.hibernate.metamodel.relational.Database; -import org.hibernate.metamodel.source.annotations.AnnotationBinder; -import org.hibernate.metamodel.source.hbm.HibernateXmlBinder; -import org.hibernate.service.BasicServiceRegistry; +import org.w3c.dom.Document; /** - * Container for configuration data while building and binding the metamodel - * * @author Steve Ebersole */ -public class Metadata implements Serializable { - private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, Metadata.class.getName() ); +public interface Metadata { + /** + * Read metadata from the annotations attached to the given class. + * + * @param annotatedClass The class containing annotations + * + * @return this (for method chaining) + */ + public Metadata addAnnotatedClass(Class annotatedClass); - private final BasicServiceRegistry serviceRegistry; + /** + * Read package-level metadata. + * + * @param packageName java package name + * + * @return this (for method chaining) + */ + public Metadata addPackage(String packageName); - private final AnnotationBinder annotationBinder; - private final HibernateXmlBinder hibernateXmlBinder; + /** + * Read mappings as a application resourceName (i.e. classpath lookup). + * + * @param name The resource name + * + * @return this (for method chaining purposes) + */ + public Metadata addResource(String name); - private final Database database = new Database(); + /** + * Read a mapping as an application resource using the convention that a class named {@code foo.bar.Foo} is + * mapped by a file named {@code foo/bar/Foo.hbm.xml} which can be resolved as a classpath resource. + * + * @param entityClass The mapped class + * + * @return this (for method chaining purposes) + */ + public Metadata addClass(Class entityClass); - private final ExtendsQueue extendsQueue; - private final MetadataSourceQueue metadataSourceQueue; + /** + * Read mappings from a particular XML file + * + * @param path The path to a file. Expected to be resolvable by {@link File#File(String)} + * + * @return this (for method chaining purposes) + * + * @see #addFile(java.io.File) + */ + public Metadata addFile(String path); - private NamingStrategy namingStrategy = EJB3NamingStrategy.INSTANCE; - private Map entityBindingMap = new HashMap(); - private Map collectionBindingMap = new HashMap(); - private Map fetchProfiles = new HashMap(); - private Map imports; + /** + * Read mappings from a particular XML file + * + * @param file The reference to the XML file + * + * @return this (for method chaining purposes) + */ + public Metadata addFile(File file); - public Metadata(BasicServiceRegistry serviceRegistry) { - this.serviceRegistry = serviceRegistry; - this.annotationBinder = new AnnotationBinder( this ); - this.hibernateXmlBinder = new HibernateXmlBinder( this ); - this.extendsQueue = new ExtendsQueue( this ); - this.metadataSourceQueue = new MetadataSourceQueue( this ); - } + /** + * See {@link #addCacheableFile(java.io.File)} for description + * + * @param path The path to a file. Expected to be resolvable by {@link File#File(String)} + * + * @return this (for method chaining purposes) + * + * @see #addCacheableFile(java.io.File) + */ + public Metadata addCacheableFile(String path); - public BasicServiceRegistry getServiceRegistry() { - return serviceRegistry; - } + /** + * Add a cached mapping file. A cached file is a serialized representation of the DOM structure of a + * particular mapping. It is saved from a previous call as a file with the name {@code {xmlFile}.bin} + * where {@code {xmlFile}} is the name of the original mapping file. + *

+ * If a cached {@code {xmlFile}.bin} exists and is newer than {@code {xmlFile}}, the {@code {xmlFile}.bin} + * file will be read directly. Otherwise {@code {xmlFile}} is read and then serialized to {@code {xmlFile}.bin} for + * use the next time. + * + * @param file The cacheable mapping file to be added, {@code {xmlFile}} in above discussion. + * + * @return this (for method chaining purposes) + */ + public Metadata addCacheableFile(File file); - public HibernateXmlBinder getHibernateXmlBinder() { - return hibernateXmlBinder; - } + /** + * Read metadata from an {@link InputStream}. + * + * @param xmlInputStream The input stream containing a DOM. + * + * @return this (for method chaining purposes) + */ + public Metadata addInputStream(InputStream xmlInputStream); - public AnnotationBinder getAnnotationBinder() { - return annotationBinder; - } - public ExtendsQueue getExtendsQueue() { - return extendsQueue; - } + /** + * Read mappings from a {@link URL} + * + * @param url The url for the mapping document to be read. + * + * @return this (for method chaining purposes) + */ + public Metadata addURL(URL url); - public MetadataSourceQueue getMetadataSourceQueue() { - return metadataSourceQueue; - } + /** + * Read mappings from a string representation of the XML + * + * @param xml an XML string + * + * @return this (for method chaining purposes) + */ + public Metadata addXML(String xml); - public Database getDatabase() { - return database; - } + /** + * Read mappings from a DOM {@link Document} + * + * @param doc The DOM document + * + * @return this (for method chaining purposes) + */ + public Metadata addDocument(Document doc); - public NamingStrategy getNamingStrategy() { - return namingStrategy; - } - public void setNamingStrategy(NamingStrategy namingStrategy) { - this.namingStrategy = namingStrategy; - } + /** + * Read all mappings from a jar file. + *

+ * Assumes that any file named *.hbm.xml is a mapping document. + * + * @param jar a jar file + * + * @return this (for method chaining purposes) + */ + public Metadata addJar(File jar); - public EntityBinding getEntityBinding(String entityName) { - return entityBindingMap.get( entityName ); - } - - public Iterable getEntityBindings() { - return entityBindingMap.values(); - } - - public void addEntity(EntityBinding entityBinding) { - final String entityName = entityBinding.getEntity().getName(); - if ( entityBindingMap.containsKey( entityName ) ) { - throw new DuplicateMappingException( DuplicateMappingException.Type.ENTITY, entityName ); - } - entityBindingMap.put( entityName, entityBinding ); - } - - public PluralAttributeBinding getCollection(String collectionRole) { - return collectionBindingMap.get( collectionRole ); - } - - public Iterable getCollections() { - return collectionBindingMap.values(); - } - - public void addCollection(PluralAttributeBinding pluralAttributeBinding) { - final String owningEntityName = pluralAttributeBinding.getEntityBinding().getEntity().getName(); - final String attributeName = pluralAttributeBinding.getAttribute().getName(); - final String collectionRole = owningEntityName + '.' + attributeName; - if ( collectionBindingMap.containsKey( collectionRole ) ) { - throw new DuplicateMappingException( DuplicateMappingException.Type.ENTITY, collectionRole ); - } - collectionBindingMap.put( collectionRole, pluralAttributeBinding ); - } - - public void addImport(String importName, String entityName) { - if ( imports == null ) { - imports = new HashMap(); - } - LOG.trace( "Import: " + importName + " -> " + entityName ); - String old = imports.put( importName, entityName ); - if ( old != null ) { - LOG.debug( "import name [" + importName + "] overrode previous [{" + old + "}]" ); - } - } - - public Iterable getFetchProfiles() { - return fetchProfiles.values(); - } - - public FetchProfile findOrCreateFetchProfile(String profileName, MetadataSource source) { - FetchProfile profile = fetchProfiles.get( profileName ); - if ( profile == null ) { - profile = new FetchProfile( profileName, source ); - fetchProfiles.put( profileName, profile ); - } - return profile; - } - - private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { - ois.defaultReadObject(); - } - - private void writeObject(java.io.ObjectOutputStream out) throws IOException { - out.defaultWriteObject(); - } + /** + * Read all mapping documents from a directory tree. + *

+ * Assumes that any file named *.hbm.xml is a mapping document. + * + * @param dir The directory + * @return this (for method chaining purposes) + * @throws org.hibernate.MappingException Indicates problems reading the jar file or + * processing the contained mapping documents. + */ + public Metadata addDirectory(File dir); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/util/xml/Origin.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/Origin.java similarity index 78% rename from hibernate-core/src/main/java/org/hibernate/metamodel/source/util/xml/Origin.java rename to hibernate-core/src/main/java/org/hibernate/metamodel/source/Origin.java index 950fa3f1d4..824d433bd8 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/util/xml/Origin.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/Origin.java @@ -21,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.metamodel.source.util.xml; +package org.hibernate.metamodel.source; import java.io.Serializable; @@ -30,14 +30,23 @@ import java.io.Serializable; * * @author Steve Ebersole */ -public interface Origin extends Serializable { +public class Origin implements Serializable { + private final SourceType type; + private final String name; + + public Origin(SourceType type, String name) { + this.type = type; + this.name = name; + } + /** - * Retrieve the type of origin. This is not a discrete set, but might be somethign like - * {@code file} for file protocol URLs, or {@code resource} for classpath resource lookups. + * Retrieve the type of origin. * * @return The origin type. */ - public String getType(); + public SourceType getType() { + return type; + } /** * The name of the document origin. Interpretation is relative to the type, but might be the @@ -45,5 +54,7 @@ public interface Origin extends Serializable { * * @return The name. */ - public String getName(); + public String getName() { + return name; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/util/xml/JaxbRoot.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/SourceType.java similarity index 75% rename from hibernate-core/src/main/java/org/hibernate/metamodel/source/util/xml/JaxbRoot.java rename to hibernate-core/src/main/java/org/hibernate/metamodel/source/SourceType.java index 8fd807e438..e7a158f64f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/util/xml/JaxbRoot.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/SourceType.java @@ -21,25 +21,20 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.metamodel.source.util.xml; + +package org.hibernate.metamodel.source; /** - * Describes a parsed xml document. + * From where did the metadata come from? * - * @author Hardy Ferentschik + * @author Steve Ebersole */ -public interface JaxbRoot { - /** - * Retrieve the jaxb root - * - * @return the jaxb root object - */ - public T getRoot(); - - /** - * Retrieve the document's origin. - * - * @return The origin - */ - public Origin getOrigin(); +public enum SourceType { + RESOURCE, + FILE, + INPUT_STREAM, + URL, + STRING, + DOM, + JAR } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/XsdException.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/XsdException.java new file mode 100644 index 0000000000..fac0104bf9 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/XsdException.java @@ -0,0 +1,50 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.metamodel.source; + +import org.hibernate.HibernateException; + +/** + * Indicates an issue finding or loading an XSD schema. + * + * @author Steve Ebersole + */ +public class XsdException extends HibernateException { + private final String xsdName; + + public XsdException(String message, String xsdName) { + super( message ); + this.xsdName = xsdName; + } + + public XsdException(String message, Throwable root, String xsdName) { + super( message, root ); + this.xsdName = xsdName; + } + + public String getXsdName() { + return xsdName; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/AnnotationBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/AnnotationBinder.java index 61353de2a1..9539bdc97a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/AnnotationBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/AnnotationBinder.java @@ -32,7 +32,7 @@ import org.jboss.jandex.Index; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.hibernate.metamodel.source.Metadata; +import org.hibernate.metamodel.source.internal.MetadataImpl; /** * Main class responsible to creating and binding the Hibernate meta-model from annotations. @@ -45,9 +45,9 @@ import org.hibernate.metamodel.source.Metadata; */ public class AnnotationBinder { private static final Logger log = LoggerFactory.getLogger( AnnotationBinder.class ); - private final Metadata metadata; + private final MetadataImpl metadata; - public AnnotationBinder(Metadata metadata) { + public AnnotationBinder(MetadataImpl metadata) { this.metadata = metadata; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/EntityBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/EntityBinder.java index 42fa1a3841..c6127626bf 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/EntityBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/EntityBinder.java @@ -30,7 +30,7 @@ import org.hibernate.AssertionFailure; import org.hibernate.internal.util.StringHelper; import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.metamodel.domain.Entity; -import org.hibernate.metamodel.source.Metadata; +import org.hibernate.metamodel.source.internal.MetadataImpl; /** * @author Hardy Ferentschik @@ -38,7 +38,7 @@ import org.hibernate.metamodel.source.Metadata; public class EntityBinder { private final ClassInfo classToBind; - public EntityBinder(Metadata metadata, ClassInfo classInfo, AnnotationInstance jpaEntityAnnotation, AnnotationInstance hibernateEntityAnnotation) { + public EntityBinder(MetadataImpl metadata, ClassInfo classInfo, AnnotationInstance jpaEntityAnnotation, AnnotationInstance hibernateEntityAnnotation) { this.classToBind = classInfo; EntityBinding entityBinding = new EntityBinding(); bindJpaAnnotation( jpaEntityAnnotation, entityBinding ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/OrmXmlParser.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/OrmXmlParser.java index d07dd8f529..e424313f48 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/OrmXmlParser.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/OrmXmlParser.java @@ -8,7 +8,7 @@ import javax.xml.bind.JAXBException; import org.jboss.jandex.Index; import org.hibernate.AnnotationException; -import org.hibernate.metamodel.source.Metadata; +import org.hibernate.metamodel.source.internal.MetadataImpl; import org.hibernate.metamodel.source.annotation.xml.EntityMappings; import org.hibernate.metamodel.source.util.xml.XmlHelper; import org.hibernate.service.classloading.spi.ClassLoaderService; @@ -21,9 +21,9 @@ public class OrmXmlParser { private static final String ORM1_MAPPING_XSD = "org/hibernate/ejb/orm_1_0.xsd"; private static final String ORM2_MAPPING_XSD = "org/hibernate/ejb/orm_2_0.xsd"; - private final Metadata meta; + private final MetadataImpl meta; - public OrmXmlParser(Metadata meta) { + public OrmXmlParser(MetadataImpl meta) { this.meta = meta; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/AbstractEntityBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/AbstractEntityBinder.java index 56f585af6b..5ab8ecefa9 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/AbstractEntityBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/AbstractEntityBinder.java @@ -44,7 +44,7 @@ import org.hibernate.metamodel.relational.Schema; import org.hibernate.metamodel.relational.Table; import org.hibernate.metamodel.relational.TableSpecification; import org.hibernate.metamodel.relational.UniqueKey; -import org.hibernate.metamodel.source.Metadata; +import org.hibernate.metamodel.source.internal.MetadataImpl; import org.hibernate.metamodel.source.hbm.state.domain.HbmPluralAttributeDomainState; import org.hibernate.metamodel.source.hbm.state.domain.HbmSimpleAttributeDomainState; import org.hibernate.metamodel.source.hbm.state.relational.HbmSimpleValueRelationalStateContainer; @@ -82,7 +82,7 @@ abstract class AbstractEntityBinder { return hibernateMappingBinder.getHibernateXmlBinder(); } - protected Metadata getMetadata() { + protected MetadataImpl getMetadata() { return hibernateMappingBinder.getHibernateXmlBinder().getMetadata(); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/HibernateXmlBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/HibernateXmlBinder.java index 4b94e5a5be..5ad022fc13 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/HibernateXmlBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/HibernateXmlBinder.java @@ -40,7 +40,7 @@ import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.JoinedIterator; import org.hibernate.internal.util.xml.XmlDocument; import org.hibernate.mapping.MetaAttribute; -import org.hibernate.metamodel.source.Metadata; +import org.hibernate.metamodel.source.internal.MetadataImpl; import org.hibernate.metamodel.source.hbm.xml.mapping.HibernateMapping; /** @@ -51,14 +51,14 @@ import org.hibernate.metamodel.source.hbm.xml.mapping.HibernateMapping; public class HibernateXmlBinder { private static final Logger log = LoggerFactory.getLogger( HibernateXmlBinder.class ); - private final Metadata metadata; + private final MetadataImpl metadata; private final Map globalMetas; - public HibernateXmlBinder(Metadata metadata) { + public HibernateXmlBinder(MetadataImpl metadata) { this( metadata, Collections.emptyMap() ); } - public HibernateXmlBinder(Metadata metadata, Map globalMetas) { + public HibernateXmlBinder(MetadataImpl metadata, Map globalMetas) { this.metadata = metadata; this.globalMetas = globalMetas; } @@ -75,20 +75,21 @@ public class HibernateXmlBinder { public void bindRoot(XmlDocument metadataXml, Set entityNames) { final HibernateMappingBinder mappingBinder = new HibernateMappingBinder( this, metadataXml ); - List names = locateEntityNamesAwaitingExtends( metadataXml, mappingBinder ); - if ( !names.isEmpty() ) { - // classes mentioned in extends not available - so put it in queue - for ( String name : names ) { - metadata.getExtendsQueue() - .add( new ExtendsQueueEntry( name, mappingBinder.getPackageName(), metadataXml, entityNames ) ); - } - return; - } +// this is irrelevant due to HHH-6118 and the fact that now all sources should be +// List names = locateEntityNamesAwaitingExtends( metadataXml, mappingBinder ); +// if ( !names.isEmpty() ) { +// // classes mentioned in extends not available - so put it in queue +// for ( String name : names ) { +// metadata.getExtendsQueue() +// .add( new ExtendsQueueEntry( name, mappingBinder.getPackageName(), metadataXml, entityNames ) ); +// } +// return; +// } mappingBinder.processElement(); } - Metadata getMetadata() { + MetadataImpl getMetadata() { return metadata; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/ExtendsQueue.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/ExtendsQueue.java similarity index 69% rename from hibernate-core/src/main/java/org/hibernate/metamodel/source/ExtendsQueue.java rename to hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/ExtendsQueue.java index 3b3c719147..33ab5fdeba 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/ExtendsQueue.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/ExtendsQueue.java @@ -21,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.metamodel.source; +package org.hibernate.metamodel.source.internal; import java.io.Serializable; import java.util.HashSet; @@ -32,6 +32,7 @@ import org.hibernate.internal.CoreMessageLogger; import org.hibernate.MappingException; import org.hibernate.cfg.ExtendsQueueEntry; import org.hibernate.metamodel.source.hbm.HbmHelper; + import org.jboss.logging.Logger; /** @@ -43,10 +44,10 @@ public class ExtendsQueue implements Serializable { private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, ExtendsQueue.class.getName()); - private final Metadata metadata; + private final MetadataImpl metadata; private Set extendsQueue = new HashSet(); - public ExtendsQueue(Metadata metadata) { + public ExtendsQueue(MetadataImpl metadata) { this.metadata = metadata; } @@ -57,28 +58,28 @@ public class ExtendsQueue implements Serializable { public int processExtendsQueue() { LOG.debug( "processing extends queue" ); int added = 0; - ExtendsQueueEntry extendsQueueEntry = findPossibleExtends(); - while ( extendsQueueEntry != null ) { - metadata.getMetadataSourceQueue().processHbmXml( extendsQueueEntry.getMetadataXml(), extendsQueueEntry.getEntityNames() ); - extendsQueueEntry = findPossibleExtends(); - } - - if ( extendsQueue.size() > 0 ) { - Iterator iterator = extendsQueue.iterator(); - StringBuffer buf = new StringBuffer( "Following super classes referenced in extends not found: " ); - while ( iterator.hasNext() ) { - final ExtendsQueueEntry entry = ( ExtendsQueueEntry ) iterator.next(); - buf.append( entry.getExplicitName() ); - if ( entry.getMappingPackage() != null ) { - buf.append( "[" ).append( entry.getMappingPackage() ).append( "]" ); - } - if ( iterator.hasNext() ) { - buf.append( "," ); - } - } - throw new MappingException( buf.toString() ); - } - +// ExtendsQueueEntry extendsQueueEntry = findPossibleExtends(); +// while ( extendsQueueEntry != null ) { +// metadata.getMetadataSourceQueue().processHbmXml( extendsQueueEntry.getMetadataXml(), extendsQueueEntry.getEntityNames() ); +// extendsQueueEntry = findPossibleExtends(); +// } +// +// if ( extendsQueue.size() > 0 ) { +// Iterator iterator = extendsQueue.iterator(); +// StringBuffer buf = new StringBuffer( "Following super classes referenced in extends not found: " ); +// while ( iterator.hasNext() ) { +// final ExtendsQueueEntry entry = ( ExtendsQueueEntry ) iterator.next(); +// buf.append( entry.getExplicitName() ); +// if ( entry.getMappingPackage() != null ) { +// buf.append( "[" ).append( entry.getMappingPackage() ).append( "]" ); +// } +// if ( iterator.hasNext() ) { +// buf.append( "," ); +// } +// } +// throw new MappingException( buf.toString() ); +// } +// return added; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/JaxbHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/JaxbHelper.java new file mode 100644 index 0000000000..72059c018c --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/JaxbHelper.java @@ -0,0 +1,213 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.metamodel.source.internal; + +import javax.xml.XMLConstants; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +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 org.jboss.logging.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import org.hibernate.HibernateException; +import org.hibernate.cfg.EJB3DTDEntityResolver; +import org.hibernate.internal.util.xml.ErrorLogger; +import org.hibernate.metamodel.source.MappingException; +import org.hibernate.metamodel.source.Origin; +import org.hibernate.metamodel.source.SourceType; +import org.hibernate.metamodel.source.XsdException; +import org.hibernate.metamodel.source.annotation.xml.EntityMappings; +import org.hibernate.metamodel.source.hbm.xml.mapping.HibernateMapping; +import org.hibernate.service.classloading.spi.ClassLoaderService; + +/** + * @author Steve Ebersole + */ +class JaxbHelper { + private static final Logger log = Logger.getLogger( JaxbHelper.class ); + + public static final String ASSUMED_ORM_XSD_VERSION = "2.0"; + + private final MetadataImpl metadata; + + JaxbHelper(MetadataImpl metadata) { + this.metadata = metadata; + } + + public JaxbRoot unmarshal(InputSource source, Origin origin) { + ErrorLogger errorHandler = new ErrorLogger(); + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setValidating( false ); // we will validate separately + try { + DocumentBuilder builder = factory.newDocumentBuilder(); + builder.setEntityResolver( metadata.getEntityResolver() ); + builder.setErrorHandler( errorHandler ); + return unmarshal( builder.parse( source ), origin ); + } + catch ( HibernateException e ) { + throw e; + } + catch (Exception e) { + throw new MappingException( "Unable to read DOM via JAXP", e, origin ); + } + } + + @SuppressWarnings( {"unchecked"}) + public JaxbRoot unmarshal(Document document, Origin origin) { + Element rootElement = document.getDocumentElement(); + if ( rootElement == null ) { + throw new MappingException( "No root element found", origin ); + } + + final Schema validationSchema; + final Class jaxbTarget; + + if ( "entity-mappings".equals( rootElement.getLocalName() ) ) { + final String explicitVersion = rootElement.getAttribute( "version" ); + validationSchema = resolveSupportedOrmXsd( explicitVersion ); + jaxbTarget = EntityMappings.class; + } + else { + validationSchema = hbmSchema(); + jaxbTarget = HibernateMapping.class; + } + + try { + validationSchema.newValidator().validate( new DOMSource( rootElement.getOwnerDocument() ) ); + } + catch ( SAXException e ) { + throw new MappingException( "Validation problem", e, origin ); + } + catch ( IOException e ) { + throw new MappingException( "Validation problem", e, origin ); + } + + final Object target; + try { + JAXBContext jaxbContext = JAXBContext.newInstance( jaxbTarget ); + Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + target = unmarshaller.unmarshal( document ); + } + catch (JAXBException e) { + throw new MappingException( "Unable to perform unmarshalling", e, origin ); + } + + return new JaxbRoot( target, origin ); + } + + private Schema resolveSupportedOrmXsd(String explicitVersion) { + final String xsdVersionString = explicitVersion == null ? ASSUMED_ORM_XSD_VERSION : explicitVersion; + if ( "1.0".equals( xsdVersionString ) ) { + return orm1Schema(); + } + else if ( "2.0".equals( xsdVersionString ) ) { + return orm1Schema(); + } + throw new IllegalArgumentException( "Unsupported orm.xml XSD version encountered [" + xsdVersionString + "]" ); + } + + public static final String HBM_SCHEMA_NAME = "/org/hibernate/hibernate-mapping-4.0.xsd"; + 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 Schema hbmSchema; + + private Schema hbmSchema() { + if ( hbmSchema == null ) { + hbmSchema = resolveLocalSchema( HBM_SCHEMA_NAME ); + } + return hbmSchema; + } + + private Schema orm1Schema; + + private Schema orm1Schema() { + if ( orm1Schema == null ) { + orm1Schema = resolveLocalSchema( ORM_1_SCHEMA_NAME ); + } + return orm1Schema; + } + + private Schema orm2Schema; + + private Schema orm2Schema() { + if ( orm2Schema == null ) { + orm2Schema = resolveLocalSchema( ORM_2_SCHEMA_NAME ); + } + return orm2Schema; + } + + private Schema resolveLocalSchema(String schemaName) { + return resolveLocalSchema( schemaName, XMLConstants.W3C_XML_SCHEMA_NS_URI ); + } + + private Schema resolveLocalSchema(String schemaName, String schemaLanguage) { + URL url = metadata.getServiceRegistry().getService( ClassLoaderService.class ).locateResource( schemaName ); + if ( url == null ) { + throw new XsdException( "Unable to locate schema [" + schemaName + "] via classpath", schemaName ); + } + 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 XsdException( "Unable to load schema [" + schemaName + "]", e, schemaName ); + } + catch ( IOException e ) { + throw new XsdException( "Unable to load schema [" + schemaName + "]", e, schemaName ); + } + finally { + try { + schemaStream.close(); + } + catch ( IOException e ) { + log.debugf( "Problem closing schema stream [%s]", e.toString() ); + } + } + } + catch ( IOException e ) { + throw new XsdException( "Stream error handling schema url [" + url.toExternalForm() + "]", schemaName ); + } + } + + +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/util/xml/JaxbRootImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/JaxbRoot.java similarity index 76% rename from hibernate-core/src/main/java/org/hibernate/metamodel/source/util/xml/JaxbRootImpl.java rename to hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/JaxbRoot.java index 6eb740184b..888b05aecb 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/util/xml/JaxbRootImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/JaxbRoot.java @@ -21,31 +21,38 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.metamodel.source.util.xml; +package org.hibernate.metamodel.source.internal; + +import org.hibernate.metamodel.source.Origin; /** - * Basic implementation of {@link JaxbRoot}. + * Holds information about a JAXB-unmarshalled XML document. * * @author Hardy Ferentschik + * @author Steve Ebersole */ -public class JaxbRootImpl implements JaxbRoot { +public class JaxbRoot { private final T root; private final Origin origin; - public JaxbRootImpl(T root, Origin origin) { + public JaxbRoot(T root, Origin origin) { this.root = root; this.origin = origin; } /** - * {@inheritDoc} + * Obtain the root JAXB bound object + * + * @return The JAXB root object */ public T getRoot() { return root; } /** - * {@inheritDoc} + * Obtain the metadata about the document's origin + * + * @return The origin */ public Origin getOrigin() { return origin; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java new file mode 100644 index 0000000000..300540f09c --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java @@ -0,0 +1,371 @@ +/* + * 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.metamodel.source.internal; + +import javax.xml.transform.dom.DOMSource; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.io.StringReader; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.jar.JarFile; +import java.util.zip.ZipEntry; + +import org.jboss.logging.Logger; +import org.w3c.dom.Document; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; + +import org.hibernate.DuplicateMappingException; +import org.hibernate.cfg.EJB3DTDEntityResolver; +import org.hibernate.cfg.EJB3NamingStrategy; +import org.hibernate.cfg.NamingStrategy; +import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.util.xml.XmlDocumentImpl; +import org.hibernate.mapping.FetchProfile; +import org.hibernate.mapping.MetadataSource; +import org.hibernate.metamodel.binding.EntityBinding; +import org.hibernate.metamodel.binding.PluralAttributeBinding; +import org.hibernate.metamodel.relational.Database; +import org.hibernate.metamodel.source.MappingException; +import org.hibernate.metamodel.source.MappingNotFoundException; +import org.hibernate.metamodel.source.Metadata; +import org.hibernate.metamodel.source.Origin; +import org.hibernate.metamodel.source.SourceType; +import org.hibernate.metamodel.source.annotations.AnnotationBinder; +import org.hibernate.metamodel.source.hbm.HibernateXmlBinder; +import org.hibernate.metamodel.source.spi.MetadataImplementor; +import org.hibernate.service.BasicServiceRegistry; +import org.hibernate.service.classloading.spi.ClassLoaderService; + +/** + * Container for configuration data while building and binding the metamodel + * + * @author Steve Ebersole + */ +public class MetadataImpl implements Metadata, MetadataImplementor, Serializable { + private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, MetadataImpl.class.getName() ); + + private final BasicServiceRegistry serviceRegistry; + + private final Database database = new Database(); + +// private final MetadataSourceQueue metadataSourceQueue; + + private final JaxbHelper jaxbHelper; + private final AnnotationBinder annotationBinder; + private final HibernateXmlBinder hibernateXmlBinder; + + private final EntityResolver entityResolver; + private final NamingStrategy namingStrategy; + private Map entityBindingMap = new HashMap(); + private Map collectionBindingMap = new HashMap(); + private Map fetchProfiles = new HashMap(); + private Map imports; + + public MetadataImpl(BasicServiceRegistry serviceRegistry) { + this( serviceRegistry, EJB3NamingStrategy.INSTANCE, EJB3DTDEntityResolver.INSTANCE ); + } + + public MetadataImpl(BasicServiceRegistry serviceRegistry, NamingStrategy namingStrategy, EntityResolver entityResolver) { + this.serviceRegistry = serviceRegistry; + this.namingStrategy = namingStrategy; + this.entityResolver = entityResolver; + this.jaxbHelper = new JaxbHelper( this ); + this.annotationBinder = new AnnotationBinder( this ); + this.hibernateXmlBinder = new HibernateXmlBinder( this ); +// this.metadataSourceQueue = new MetadataSourceQueue( this ); + } + + public BasicServiceRegistry getServiceRegistry() { + return serviceRegistry; + } + + public EntityResolver getEntityResolver() { + return entityResolver; + } + + public HibernateXmlBinder getHibernateXmlBinder() { + return hibernateXmlBinder; + } + + public AnnotationBinder getAnnotationBinder() { + return annotationBinder; + } + +// public MetadataSourceQueue getMetadataSourceQueue() { +// return metadataSourceQueue; +// } + + public Database getDatabase() { + return database; + } + + public NamingStrategy getNamingStrategy() { + return namingStrategy; + } + + public EntityBinding getEntityBinding(String entityName) { + return entityBindingMap.get( entityName ); + } + + public Iterable getEntityBindings() { + return entityBindingMap.values(); + } + + public void addEntity(EntityBinding entityBinding) { + final String entityName = entityBinding.getEntity().getName(); + if ( entityBindingMap.containsKey( entityName ) ) { + throw new DuplicateMappingException( DuplicateMappingException.Type.ENTITY, entityName ); + } + entityBindingMap.put( entityName, entityBinding ); + } + + public PluralAttributeBinding getCollection(String collectionRole) { + return collectionBindingMap.get( collectionRole ); + } + + public Iterable getCollections() { + return collectionBindingMap.values(); + } + + public void addCollection(PluralAttributeBinding pluralAttributeBinding) { + final String owningEntityName = pluralAttributeBinding.getEntityBinding().getEntity().getName(); + final String attributeName = pluralAttributeBinding.getAttribute().getName(); + final String collectionRole = owningEntityName + '.' + attributeName; + if ( collectionBindingMap.containsKey( collectionRole ) ) { + throw new DuplicateMappingException( DuplicateMappingException.Type.ENTITY, collectionRole ); + } + collectionBindingMap.put( collectionRole, pluralAttributeBinding ); + } + + public void addImport(String importName, String entityName) { + if ( imports == null ) { + imports = new HashMap(); + } + LOG.trace( "Import: " + importName + " -> " + entityName ); + String old = imports.put( importName, entityName ); + if ( old != null ) { + LOG.debug( "import name [" + importName + "] overrode previous [{" + old + "}]" ); + } + } + + public Iterable getFetchProfiles() { + return fetchProfiles.values(); + } + + public FetchProfile findOrCreateFetchProfile(String profileName, MetadataSource source) { + FetchProfile profile = fetchProfiles.get( profileName ); + if ( profile == null ) { + profile = new FetchProfile( profileName, source ); + fetchProfiles.put( profileName, profile ); + } + return profile; + } + + // Metadata contract ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + private List jaxbRootList = new ArrayList(); + + @Override + public Metadata addAnnotatedClass(Class annotatedClass) { + return null; // todo : implement method body + } + + @Override + public Metadata addPackage(String packageName) { + return null; // todo : implement method body + } + + @Override + public Metadata addResource(String name) { + LOG.tracef( "reading mappings from resource : %s", name ); + + final Origin origin = new Origin( SourceType.RESOURCE, name ); + InputStream resourceInputStream = classLoaderService().locateResourceStream( name ); + if ( resourceInputStream == null ) { + throw new MappingNotFoundException( origin ); + } + add( resourceInputStream, origin ); + + return this; + } + + private ClassLoaderService classLoaderService() { + return serviceRegistry.getService( ClassLoaderService.class ); + } + + private JaxbRoot add(InputStream inputStream, Origin origin) { + final InputSource inputSource = new InputSource( inputStream ); + try { + return add( inputSource, origin ); + } + finally { + try { + inputStream.close(); + } + catch ( IOException ignore ) { + LOG.trace( "Was unable to close input stream" ); + } + } + } + + private JaxbRoot add(InputSource inputSource, Origin origin) { + JaxbRoot jaxbRoot = jaxbHelper.unmarshal( inputSource, origin ); + jaxbRootList.add( jaxbRoot ); + return jaxbRoot; + } + + @Override + public Metadata addClass(Class entityClass) { + LOG.debugf( "adding resource mappings from class convention : %s", entityClass.getName() ); + final String mappingResourceName = entityClass.getName().replace( '.', '/' ) + ".hbm.xml"; + addResource( mappingResourceName ); + return this; + } + + @Override + public Metadata addFile(String path) { + return addFile( new File( path ) ); + } + + @Override + public Metadata addFile(File file) { + final String name = file.getAbsolutePath(); + LOG.tracef( "reading mappings from file : %s", name ); + final Origin origin = new Origin( SourceType.FILE, name ); + final InputSource inputSource; + try { + inputSource = new InputSource( new FileInputStream( file ) ); + } + catch ( FileNotFoundException e ) { + throw new MappingNotFoundException( e, origin ); + } + add( inputSource, origin ); + return this; + } + + @Override + public Metadata addCacheableFile(String path) { + return null; // todo : implement method body + } + + @Override + public Metadata addCacheableFile(File file) { + return null; // todo : implement method body + } + + @Override + public Metadata addInputStream(InputStream xmlInputStream) { + add( xmlInputStream, new Origin( SourceType.INPUT_STREAM, "" ) ); + return this; + } + + @Override + public Metadata addURL(URL url) { + final String urlExternalForm = url.toExternalForm(); + LOG.debugf("Reading mapping document from URL : %s", urlExternalForm); + + final Origin origin = new Origin( SourceType.URL, urlExternalForm ); + try { + add( url.openStream(), origin ); + } + catch ( IOException e ) { + throw new MappingNotFoundException( "Unable to open url stream [" + urlExternalForm + "]", e, origin ); + } + return this; + } + + @Override + public Metadata addXML(String xml) { + final InputSource inputSource = new InputSource( new StringReader( xml ) ); + add( inputSource, new Origin( SourceType.STRING, "" ) ); + return this; + } + + @Override + public Metadata addDocument(Document document) { + final Origin origin = new Origin( SourceType.DOM, "" ); + JaxbRoot jaxbRoot = jaxbHelper.unmarshal( document, origin ); + jaxbRootList.add( jaxbRoot ); + return this; + } + + @Override + public Metadata addJar(File jar) { + LOG.debugf( "Seeking mapping documents in jar file : %s", jar.getName() ); + final Origin origin = new Origin( SourceType.JAR, jar.getAbsolutePath() ); + try { + JarFile jarFile = new JarFile( jar ); + try { + Enumeration jarEntries = jarFile.entries(); + while ( jarEntries.hasMoreElements() ) { + final ZipEntry zipEntry = (ZipEntry) jarEntries.nextElement(); + if ( zipEntry.getName().endsWith( ".hbm.xml" ) ) { + LOG.tracef( "found mapping document : %s", zipEntry.getName() ); + try { + add( jarFile.getInputStream( zipEntry ), origin ); + } + catch (Exception e) { + throw new MappingException( "could not read mapping documents", e, origin ); + } + } + } + } + finally { + try { + jarFile.close(); + } + catch (Exception ignore) { + } + } + } + catch (IOException e) { + throw new MappingNotFoundException( e, origin ); + } + return this; + } + + @Override + public Metadata addDirectory(File dir) { + File[] files = dir.listFiles(); + for ( File file : files ) { + if ( file.isDirectory() ) { + addDirectory( file ); + } + else if ( file.getName().endsWith( ".hbm.xml" ) ) { + addFile( file ); + } + } + return this; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/MetadataSourceQueue.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataSourceQueue.java similarity index 97% rename from hibernate-core/src/main/java/org/hibernate/metamodel/source/MetadataSourceQueue.java rename to hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataSourceQueue.java index cf67136adf..018b93e388 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/MetadataSourceQueue.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataSourceQueue.java @@ -21,7 +21,7 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.metamodel.source; +package org.hibernate.metamodel.source.internal; import java.io.IOException; import java.io.ObjectInputStream; @@ -56,14 +56,14 @@ public class MetadataSourceQueue implements Serializable { private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, MetadataSourceQueue.class.getName() ); - private final Metadata metadata; + private final MetadataImpl metadata; private LinkedHashMap> hbmMetadataToEntityNamesMap = new LinkedHashMap>(); private Map hbmMetadataByEntityNameXRef = new HashMap(); private transient List annotatedClasses = new ArrayList(); - public MetadataSourceQueue(Metadata metadata) { + public MetadataSourceQueue(MetadataImpl metadata) { this.metadata = metadata; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/util/xml/OriginImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/MetadataImplementor.java similarity index 70% rename from hibernate-core/src/main/java/org/hibernate/metamodel/source/util/xml/OriginImpl.java rename to hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/MetadataImplementor.java index aa4aaa89ee..cc4b3194f2 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/util/xml/OriginImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/MetadataImplementor.java @@ -21,33 +21,19 @@ * 51 Franklin Street, Fifth Floor * Boston, MA 02110-1301 USA */ -package org.hibernate.metamodel.source.util.xml; +package org.hibernate.metamodel.source.spi; + +import org.hibernate.metamodel.binding.EntityBinding; +import org.hibernate.metamodel.relational.Database; +import org.hibernate.service.BasicServiceRegistry; /** - * Basic implementation of {@link org.hibernate.internal.util.xml.Origin} - * * @author Steve Ebersole */ -public class OriginImpl implements Origin { - private final String type; - private final String name; +public interface MetadataImplementor { + public BasicServiceRegistry getServiceRegistry(); + public Database getDatabase(); - public OriginImpl(String type, String name) { - this.type = type; - this.name = name; - } - - /** - * {@inheritDoc} - */ - public String getType() { - return type; - } - - /** - * {@inheritDoc} - */ - public String getName() { - return name; - } + public Iterable getEntityBindings(); + public EntityBinding getEntityBinding(String entityName); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/util/xml/XmlHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/util/xml/XmlHelper.java index 0cfb7ba67f..e714f03ab0 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/util/xml/XmlHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/util/xml/XmlHelper.java @@ -37,6 +37,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.SAXException; +import org.hibernate.metamodel.source.Origin; +import org.hibernate.metamodel.source.internal.JaxbRoot; import org.hibernate.service.classloading.spi.ClassLoaderService; /** @@ -57,8 +59,8 @@ public class XmlHelper { unmarshaller.setSchema( schema ); StreamSource stream = new StreamSource( in ); JAXBElement elem = unmarshaller.unmarshal( stream, clazz ); - Origin origin = new OriginImpl( "", fileName ); - return new JaxbRootImpl( elem.getValue(), origin ); + Origin origin = new Origin( null, fileName ); + return new JaxbRoot( elem.getValue(), origin ); } private static Schema getMappingSchema(String schemaVersion, ClassLoaderService classLoaderService) { diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/binding/BasicAnnotationBindingTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/binding/BasicAnnotationBindingTests.java index 5e83142c4a..872004ae9d 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/binding/BasicAnnotationBindingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/binding/BasicAnnotationBindingTests.java @@ -30,7 +30,8 @@ import org.jboss.jandex.Index; import org.jboss.jandex.Indexer; import org.junit.Test; -import org.hibernate.metamodel.source.Metadata; +import org.hibernate.metamodel.source.internal.MetadataImpl; + import org.hibernate.testing.FailureExpected; import static org.junit.Assert.fail; @@ -56,7 +57,7 @@ public class BasicAnnotationBindingTests extends AbstractBasicBindingTests { public EntityBinding buildSimpleEntityBinding() { Index index = indexForClass( SimpleEntity.class ); - Metadata metadata = new Metadata( basicServiceRegistry() ); + MetadataImpl metadata = new MetadataImpl( basicServiceRegistry() ); metadata.getAnnotationBinder().bindMappedClasses( index ); return metadata.getEntityBinding( SimpleEntity.class.getSimpleName() ); @@ -64,7 +65,7 @@ public class BasicAnnotationBindingTests extends AbstractBasicBindingTests { public EntityBinding buildSimpleVersionedEntityBinding() { Index index = indexForClass( SimpleEntity.class ); - Metadata metadata = new Metadata( basicServiceRegistry() ); + MetadataImpl metadata = new MetadataImpl( basicServiceRegistry() ); metadata.getAnnotationBinder().bindMappedClasses( index ); return metadata.getEntityBinding( SimpleVersionedEntity.class.getSimpleName() ); diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/binding/BasicHbmBindingTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/binding/BasicHbmBindingTests.java index a2b236f511..1f7f798ff9 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/binding/BasicHbmBindingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/binding/BasicHbmBindingTests.java @@ -33,7 +33,7 @@ import org.hibernate.internal.util.xml.MappingReader; import org.hibernate.internal.util.xml.Origin; import org.hibernate.internal.util.xml.XMLHelper; import org.hibernate.internal.util.xml.XmlDocument; -import org.hibernate.metamodel.source.Metadata; +import org.hibernate.metamodel.source.internal.MetadataImpl; import org.hibernate.metamodel.source.hbm.xml.mapping.HibernateMapping; import org.hibernate.metamodel.source.util.xml.XmlHelper; import org.hibernate.service.classloading.spi.ClassLoaderService; @@ -49,7 +49,7 @@ public class BasicHbmBindingTests extends AbstractBasicBindingTests { private static final Logger log = Logger.getLogger( BasicHbmBindingTests.class.getName() ); public EntityBinding buildSimpleEntityBinding() { - Metadata metadata = new Metadata( basicServiceRegistry() ); + MetadataImpl metadata = new MetadataImpl( basicServiceRegistry() ); XmlDocument xmlDocument = readResource( "/org/hibernate/metamodel/binding/SimpleEntity.hbm.xml" ); metadata.getHibernateXmlBinder().bindRoot( xmlDocument ); @@ -57,7 +57,7 @@ public class BasicHbmBindingTests extends AbstractBasicBindingTests { } public EntityBinding buildSimpleVersionedEntityBinding() { - Metadata metadata = new Metadata( basicServiceRegistry() ); + MetadataImpl metadata = new MetadataImpl( basicServiceRegistry() ); String fileName = "/org/hibernate/metamodel/binding/SimpleVersionedEntity.hbm.xml"; XmlDocument xmlDocument = readResource( fileName ); diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/OrmXmlParserTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/OrmXmlParserTests.java index cfad6c17e6..97585e5c38 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/OrmXmlParserTests.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/OrmXmlParserTests.java @@ -6,7 +6,7 @@ import java.util.Set; import org.junit.Test; -import org.hibernate.metamodel.source.Metadata; +import org.hibernate.metamodel.source.internal.MetadataImpl; import org.hibernate.service.internal.BasicServiceRegistryImpl; import org.hibernate.testing.junit4.BaseUnitTestCase; @@ -16,7 +16,7 @@ import org.hibernate.testing.junit4.BaseUnitTestCase; public class OrmXmlParserTests extends BaseUnitTestCase { @Test public void testSingleOrmXml() { - OrmXmlParser parser = new OrmXmlParser( new Metadata( new BasicServiceRegistryImpl( Collections.emptyMap() ) ) ); + OrmXmlParser parser = new OrmXmlParser( new MetadataImpl( new BasicServiceRegistryImpl( Collections.emptyMap() ) ) ); Set xmlFiles = new HashSet(); xmlFiles.add( "org/hibernate/metamodel/source/annotations/orm.xml" ); parser.parseAndUpdateIndex( xmlFiles, null ); @@ -24,7 +24,7 @@ public class OrmXmlParserTests extends BaseUnitTestCase { @Test public void testOrmXmlWithOldSchema() { - OrmXmlParser parser = new OrmXmlParser( new Metadata( new BasicServiceRegistryImpl( Collections.emptyMap() ) ) ); + OrmXmlParser parser = new OrmXmlParser( new MetadataImpl( new BasicServiceRegistryImpl( Collections.emptyMap() ) ) ); Set xmlFiles = new HashSet(); xmlFiles.add( "org/hibernate/metamodel/source/annotations/orm2.xml" ); parser.parseAndUpdateIndex( xmlFiles, null );