/*
* Copyright (c) 2009, Red Hat Middleware LLC 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 Middleware LLC.
*
* 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.ejb.metamodel;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.persistence.metamodel.EmbeddableType;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.ManagedType;
import javax.persistence.metamodel.Metamodel;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.mapping.MappedSuperclass;
import org.hibernate.mapping.PersistentClass;
/**
* Hibernate implementation of the JPA {@link Metamodel} contract.
*
* @author Steve Ebersole
* @author Emmanuel Bernard
*/
public class MetamodelImpl implements Metamodel, Serializable {
private final Map<Class<?>,EntityTypeImpl<?>> entities;
private final Map<Class<?>, EmbeddableTypeImpl<?>> embeddables;
/**
* Build the metamodel using the information from the collection of Hibernate
* {@link PersistentClass} models as well as the Hibernate {@link org.hibernate.SessionFactory}.
*
* @param persistentClasses Iterator over the Hibernate (config-time) metamodel
* @param sessionFactory The Hibernate session factry.
* @return The built metamodel
*/
public static MetamodelImpl buildMetamodel(
Iterator<PersistentClass> persistentClasses,
SessionFactoryImplementor sessionFactory) {
MetadataContext context = new MetadataContext( sessionFactory );
while ( persistentClasses.hasNext() ) {
PersistentClass pc = persistentClasses.next();
if ( pc.getMappedClass() != null ) {
locateOrBuildEntityType( pc, context );
}
}
context.wrapUp();
return new MetamodelImpl( context.getEntityTypeMap(), context.getEmbeddableTypeMap() );
}
private static EntityTypeImpl<?> locateOrBuildEntityType(PersistentClass persistentClass, MetadataContext context) {
EntityTypeImpl<?> entityType = context.locateEntityType( persistentClass );
if ( entityType == null ) {
entityType = buildEntityType( persistentClass, context );
}
return entityType;
}
//TODO remove / reduce @SW scope
@SuppressWarnings( "unchecked" )
private static EntityTypeImpl<?> buildEntityType(PersistentClass persistentClass, MetadataContext context) {
final Class javaType = persistentClass.getMappedClass();
context.pushEntityWorkedOn(persistentClass);
final MappedSuperclass superMappedSuperclass = persistentClass.getSuperMappedSuperclass();
AbstractIdentifiableType<?> superType = superMappedSuperclass == null
? null
: locateOrBuildMappedsuperclassType( superMappedSuperclass, context );
//no mappedSuperclass, check for a super entity
if (superType == null) {
final PersistentClass superPersistentClass = persistentClass.getSuperclass();
superType = superPersistentClass == null
? null
: locateOrBuildEntityType( superPersistentClass, context );
}
EntityTypeImpl entityType = new EntityTypeImpl(
javaType,
superType,
persistentClass.getJpaEntityName(),
persistentClass.hasIdentifierProperty(),
persistentClass.isVersioned()
);
context.registerEntityType( persistentClass, entityType );
context.popEntityWorkedOn(persistentClass);
return entityType;
}
private static MappedSuperclassTypeImpl<?> locateOrBuildMappedsuperclassType(
MappedSuperclass mappedSuperclass, MetadataContext context) {
MappedSuperclassTypeImpl<?> mappedSuperclassType = context.locateMappedSuperclassType( mappedSuperclass );
if ( mappedSuperclassType == null ) {
mappedSuperclassType = buildMappedSuperclassType(mappedSuperclass, context);
}
return mappedSuperclassType;
}
//TODO remove / reduce @SW scope
@SuppressWarnings( "unchecked" )
private static MappedSuperclassTypeImpl<?> buildMappedSuperclassType(MappedSuperclass mappedSuperclass,
MetadataContext context) {
final MappedSuperclass superMappedSuperclass = mappedSuperclass.getSuperMappedSuperclass();
AbstractIdentifiableType<?> superType = superMappedSuperclass == null
? null
: locateOrBuildMappedsuperclassType( superMappedSuperclass, context );
//no mappedSuperclass, check for a super entity
if (superType == null) {
final PersistentClass superPersistentClass = mappedSuperclass.getSuperPersistentClass();
superType = superPersistentClass == null
? null
: locateOrBuildEntityType( superPersistentClass, context );
}
final Class javaType = mappedSuperclass.getMappedClass();
MappedSuperclassTypeImpl mappedSuperclassType = new MappedSuperclassTypeImpl(
javaType,
superType,
mappedSuperclass.hasIdentifierProperty(),
mappedSuperclass.isVersioned()
);
context.registerMappedSuperclassType( mappedSuperclass, mappedSuperclassType );
return mappedSuperclassType;
}
/**
* Instantiate the metamodel.
*
* @param entities The entity mappings.
* @param embeddables The embeddable (component) mappings.
*/
private MetamodelImpl(
Map<Class<?>, EntityTypeImpl<?>> entities,
Map<Class<?>, EmbeddableTypeImpl<?>> embeddables) {
this.entities = entities;
this.embeddables = embeddables;
}
/**
* {@inheritDoc}
*/
@SuppressWarnings({ "unchecked" })
public <X> EntityType<X> entity(Class<X> cls) {
final EntityType<?> entityType = entities.get( cls );
if ( entityType == null ) throw new IllegalArgumentException( "Not an entity: " + cls );
//unsafe casting is our map inserts guarantee them
return (EntityType<X>) entityType;
}
/**
* {@inheritDoc}
*/
@SuppressWarnings({ "unchecked" })
public <X> ManagedType<X> managedType(Class<X> cls) {
ManagedType<?> type = entities.get( cls );
if ( type == null ) throw new IllegalArgumentException( "Not an managed type: " + cls );
//unsafe casting is our map inserts guarantee them
return (ManagedType<X>) type;
}
/**
* {@inheritDoc}
*/
@SuppressWarnings({ "unchecked" })
public <X> EmbeddableType<X> embeddable(Class<X> cls) {
final EmbeddableType<?> embeddableType = embeddables.get( cls );
if ( embeddableType == null ) throw new IllegalArgumentException( "Not an entity: " + cls );
//unsafe casting is our map inserts guarantee them
return (EmbeddableType<X>) embeddableType;
}
/**
* {@inheritDoc}
*/
public Set<ManagedType<?>> getManagedTypes() {
final Set<ManagedType<?>> managedTypes = new HashSet<ManagedType<?>>( entities.size() + embeddables.size() );
managedTypes.addAll( entities.values() );
managedTypes.addAll( embeddables.values() );
return managedTypes;
}
/**
* {@inheritDoc}
*/
public Set<EntityType<?>> getEntities() {
return new HashSet<EntityType<?>>(entities.values());
}
/**
* {@inheritDoc}
*/
public Set<EmbeddableType<?>> getEmbeddables() {
return new HashSet<EmbeddableType<?>>(embeddables.values());
}
}