/* * Hibernate, Relational Persistence for Idiomatic Java * * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ package org.hibernate.orm.type.spi; import java.util.Collection; import java.util.Map; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import org.hibernate.Incubating; import org.hibernate.MappingException; import org.hibernate.SessionFactoryObserver; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.orm.persister.collection.spi.CollectionPersister; import org.hibernate.orm.persister.embeddable.spi.EmbeddableMapper; import org.hibernate.orm.persister.entity.spi.EntityPersister; import org.hibernate.orm.type.descriptor.java.spi.JavaTypeDescriptorRegistry; import org.hibernate.orm.type.descriptor.sql.spi.SqlTypeDescriptorRegistry; import org.hibernate.usertype.ParameterizedType; import static org.hibernate.internal.CoreLogging.messageLogger; /** * Defines a set of available Type instances as isolated from other configurations. The * isolation is defined by each instance of a TypeConfiguration. * <p/> * Note that each Type is inherently "scoped" to a TypeConfiguration. We only ever access * a Type through a TypeConfiguration - specifically the TypeConfiguration in effect for * the current persistence unit. * <p/> * Even though each Type instance is scoped to a TypeConfiguration, Types do not inherently * have access to that TypeConfiguration (mainly because Type is an extension contract - meaning * that Hibernate does not manage the full set of Types available in ever TypeConfiguration). * However Types will often want access to the TypeConfiguration, which can be achieved by the * Type simply implementing the {@link TypeConfigurationAware} interface. * * @author Steve Ebersole * * @since 6.0 */ @Incubating public class TypeConfiguration implements SessionFactoryObserver { private static final CoreMessageLogger log = messageLogger( TypeConfiguration.class ); // !!! NOTE !!! // This is an extremely scaled-back version of the upstream TypeConfiguration. // Here we do not worry about "scoping", we just deal with the exposed // APIs as that is what is needed for consumption in SQM // private final Scope scope; private final JavaTypeDescriptorRegistry javaTypeDescriptorRegistry; private final SqlTypeDescriptorRegistry sqlTypeDescriptorRegistry; private final BasicTypeRegistry basicTypeRegistry; private boolean initialized = false; private final Map<String,EntityPersister> entityPersisterMap = new ConcurrentHashMap<>(); private final Map<String,CollectionPersister> collectionPersisterMap = new ConcurrentHashMap<>(); private final Map<String,EmbeddableMapper> embeddableMapperMap = new ConcurrentHashMap<>(); public TypeConfiguration() { // this( new EolScopeMapping() ); // } // // public TypeConfiguration(Mapping mapping) { // this.scope = new Scope( mapping ); this.javaTypeDescriptorRegistry = new JavaTypeDescriptorRegistry( this ); this.sqlTypeDescriptorRegistry = new SqlTypeDescriptorRegistry( this ); this.basicTypeRegistry = new BasicTypeRegistry( this ); this.initialized = true; } public JavaTypeDescriptorRegistry getJavaTypeDescriptorRegistry() { if ( !initialized ) { throw new IllegalStateException( "TypeConfiguration initialization incomplete; not yet ready for access" ); } return javaTypeDescriptorRegistry; } public SqlTypeDescriptorRegistry getSqlTypeDescriptorRegistry() { if ( !initialized ) { throw new IllegalStateException( "TypeConfiguration initialization incomplete; not yet ready for access" ); } return sqlTypeDescriptorRegistry; } // /** // * Get access to the generic Mapping contract. This is implemented for both the // * boot-time model (Metamodel) and the run-time model (SessionFactory). // * // * @return The mapping object. Should almost never return {@code null}. There is a minor // * chance this method would get a {@code null}, but that would be an unsupported use-case. // */ // public Mapping getMapping() { // return scope.getMapping(); // } // /** // * Attempt to resolve the {@link #getMapping()} reference as a SessionFactory (the runtime model). // * This will throw an exception if the SessionFactory is not yet bound here. // * // * @return The SessionFactory // * // * @throws IllegalStateException if the Mapping reference is not a SessionFactory or the SessionFactory // * cannot be resolved; generally either of these cases would mean that the SessionFactory was not yet // * bound to this scope object // */ // public SessionFactoryImplementor getSessionFactory() { // return scope.getSessionFactory(); // } // public MetadataBuildingContext getMetadataBuildingContext() { // return scope.getMetadataBuildingContext(); // } public BasicTypeRegistry getBasicTypeRegistry() { return basicTypeRegistry; } // public void scope(MetadataBuildingContext metadataBuildingContext) { // log.debugf( "Scoping TypeConfiguration [%s] to MetadataBuildingContext [%s]", this, metadataBuildingContext ); // scope.setMetadataBuildingContext( metadataBuildingContext ); // } // public void scope(SessionFactoryImplementor factory) { // log.debugf( "Scoping TypeConfiguration [%s] to SessionFactory [%s]", this, factory ); // scope.setSessionFactory( factory ); // factory.addObserver( this ); // } // @Override // public void sessionFactoryClosed(SessionFactory factory) { // log.debugf( "Un-scoping TypeConfiguration [%s] to SessionFactory [%s]", this, factory ); // scope.unsetSessionFactory( factory ); // } // public BasicType resolveCastTargetType(String name) { // throw new NotYetImplementedException( ); // } // public EntityType manyToOne(Class clazz) { // assert clazz != null; // return manyToOne( clazz.getName() ); // } // // public EntityType manyToOne(String entityName) { // throw new NotYetImplementedException( ); // } // // public EntityType manyToOne(Class clazz, boolean lazy) { // assert clazz != null; // return manyToOne( clazz.getName(), lazy ); // } // // public EntityType manyToOne(String entityName, boolean lazy) { // return manyToOne( entityName, true, null, lazy, true, false, false ); // } // // public EntityType manyToOne( // String persistentClass, // boolean referenceToPrimaryKey, // String uniqueKeyPropertyName, // boolean lazy, // boolean unwrapProxy, // boolean ignoreNotFound, // boolean isLogicalOneToOne) { // return new ManyToOneType( // this, // persistentClass, // referenceToPrimaryKey, // uniqueKeyPropertyName, // lazy, // unwrapProxy, // ignoreNotFound, // isLogicalOneToOne // ); // } // // // one-to-one type builders ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // public EntityType oneToOne( // String persistentClass, // ForeignKeyDirection foreignKeyType, // boolean referenceToPrimaryKey, // String uniqueKeyPropertyName, // boolean lazy, // boolean unwrapProxy, // String entityName, // String propertyName) { // return new OneToOneType( // this, persistentClass, foreignKeyType, referenceToPrimaryKey, // uniqueKeyPropertyName, lazy, unwrapProxy, entityName, propertyName // ); // } // // public EntityType specialOneToOne( // String persistentClass, // ForeignKeyDirection foreignKeyType, // boolean referenceToPrimaryKey, // String uniqueKeyPropertyName, // boolean lazy, // boolean unwrapProxy, // String entityName, // String propertyName) { // return new SpecialOneToOneType( // this, persistentClass, foreignKeyType, referenceToPrimaryKey, // uniqueKeyPropertyName, lazy, unwrapProxy, entityName, propertyName // ); // } // // public Type heuristicType(String typename) { // throw new NotYetImplementedException( ); // } // // // collection type builders ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // public CollectionType array(String role, String propertyRef, Class elementClass) { // return new ArrayType( this, role, propertyRef, elementClass ); // } // // public CollectionType list(String role, String propertyRef) { // return new ListType( this, role, propertyRef ); // } // // public CollectionType bag(String role, String propertyRef) { // return new BagType( this, role, propertyRef ); // } // // public CollectionType idbag(String role, String propertyRef) { // return new IdentifierBagType( this, role, propertyRef ); // } // // public CollectionType map(String role, String propertyRef) { // return new MapType( this, role, propertyRef ); // } // // public CollectionType orderedMap(String role, String propertyRef) { // return new OrderedMapType( this, role, propertyRef ); // } // // public CollectionType sortedMap(String role, String propertyRef, Comparator comparator) { // return new SortedMapType( this, role, propertyRef, comparator ); // } // // public CollectionType set(String role, String propertyRef) { // return new SetType( this, role, propertyRef ); // } // // public CollectionType orderedSet(String role, String propertyRef) { // return new OrderedSetType( this, role, propertyRef ); // } // // public CollectionType sortedSet(String role, String propertyRef, Comparator comparator) { // return new SortedSetType( this, role, propertyRef, comparator ); // } // // // component type builders ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // public EmbeddedComponentType embeddedComponent(ComponentMetamodel metamodel) { // return new EmbeddedComponentType( this, metamodel ); // } // // public ComponentType component(ComponentMetamodel metamodel) { // return new ComponentType( this, metamodel ); // } // // // public CollectionType customCollection( // String typeName, // Properties typeParameters, // String role, // String propertyRef) { // Class typeClass; // try { // typeClass = ReflectHelper.classForName( typeName ); // } // catch (ClassNotFoundException cnfe) { // throw new MappingException( "user collection type class not found: " + typeName, cnfe ); // } // CustomCollectionType result = new CustomCollectionType( this, typeClass, role, propertyRef ); // if ( typeParameters != null ) { // injectParameters( result.getUserType(), typeParameters ); // } // return result; // } private final static Properties EMPTY_PROPERTIES = new Properties(); public static void injectParameters(Object type, Properties parameters) { if ( ParameterizedType.class.isInstance( type ) ) { if ( parameters == null ) { ( (ParameterizedType) type ).setParameterValues( EMPTY_PROPERTIES ); } else { ( (ParameterizedType) type ).setParameterValues( parameters ); } } else if ( parameters != null && !parameters.isEmpty() ) { throw new MappingException( "type is not parameterized: " + type.getClass().getName() ); } } // /** // * Encapsulation of lifecycle concerns for a TypeConfiguration, mainly in regards to // * eventually being associated with a SessionFactory. Goes through the following stages:<ol> // * <li> // * TypeConfiguration initialization - during this phase {@link #getMapping()} will // * return a non-null, no-op impl. Calls to {@link #getMetadataBuildingContext()} will // * simply return {@code null}, while calls to {@link #getSessionFactory()} will throw // * an exception. // * </li> // * <li> // * Metadata building - during this phase {@link #getMetadataBuildingContext()} will // * return a non-null value and the {@link #getMapping()} return will be the // * {@link MetadataBuildingContext#getMetadataCollector()} reference. Calls to // * {@link #getSessionFactory()} will throw an exception. // * </li> // * <li> // * live SessionFactory - this is the only phase where calls to {@link #getSessionFactory()} // * are allowed and {@link #getMapping()} returns the SessionFactory itself (since it // * implements that Mapping contract (for now) too. Calls to {@link #getMetadataBuildingContext()} // * will simply return {@code null}. // * </li> // * </ol> // */ // private static class Scope { // private transient Mapping mapping; // // private transient MetadataBuildingContext metadataBuildingContext; // // private String sessionFactoryName; // private String sessionFactoryUuid; // // Scope(Mapping mapping) { // this.mapping = mapping; // } // // public Mapping getMapping() { // return mapping; // } // // public MetadataBuildingContext getMetadataBuildingContext() { // if ( metadataBuildingContext == null ) { // throw new HibernateException( "TypeConfiguration is not currently scoped to MetadataBuildingContext" ); // } // return metadataBuildingContext; // } // // public void setMetadataBuildingContext(MetadataBuildingContext metadataBuildingContext) { // this.metadataBuildingContext = metadataBuildingContext; // this.mapping = metadataBuildingContext.getMetadataCollector(); // } // // public SessionFactoryImplementor getSessionFactory() { // if ( mapping == null ) { // if ( sessionFactoryName == null && sessionFactoryUuid == null ) { // throw new HibernateException( "TypeConfiguration was not yet scoped to SessionFactory" ); // } // mapping = (SessionFactoryImplementor) SessionFactoryRegistry.INSTANCE.findSessionFactory( // sessionFactoryUuid, // sessionFactoryName // ); // if ( mapping == null ) { // throw new HibernateException( // "Could not find a SessionFactory [uuid=" + sessionFactoryUuid + ",name=" + sessionFactoryName + "]" // ); // } // } // // if ( !SessionFactoryImplementor.class.isInstance( mapping ) ) { // throw new HibernateException( "TypeConfiguration was not yet scoped to SessionFactory" ); // } // // return (SessionFactoryImplementor) mapping; // } // // /** // * Used by TypeFactory scoping. // * // * @param factory The SessionFactory that the TypeFactory is being bound to // */ // void setSessionFactory(SessionFactoryImplementor factory) { // if ( this.mapping != null && mapping instanceof SessionFactoryImplementor ) { // log.scopingTypesToSessionFactoryAfterAlreadyScoped( (SessionFactoryImplementor) mapping, factory ); // } // else { // metadataBuildingContext = null; // // sessionFactoryUuid = factory.getUuid(); // String sfName = factory.getSessionFactoryOptions().getSessionFactoryName(); // if ( sfName == null ) { // final CfgXmlAccessService cfgXmlAccessService = factory.getServiceRegistry() // .getService( CfgXmlAccessService.class ); // if ( cfgXmlAccessService.getAggregatedConfig() != null ) { // sfName = cfgXmlAccessService.getAggregatedConfig().getSessionFactoryName(); // } // } // sessionFactoryName = sfName; // } // this.mapping = factory; // } // // public void unsetSessionFactory(SessionFactory factory) { // this.mapping = EolScopeMapping.INSTANCE; // } // } // private static class EolScopeMapping implements Mapping { // /** // * Singleton access // */ // public static final EolScopeMapping INSTANCE = new EolScopeMapping(); // // @Override // public IdentifierGeneratorFactory getIdentifierGeneratorFactory() { // throw invalidAccess(); // } // // private RuntimeException invalidAccess() { // return new IllegalStateException( "Access to this TypeConfiguration is no longer valid" ); // } // // @Override // public Type getIdentifierType(String className) { // throw invalidAccess(); // } // // @Override // public String getIdentifierPropertyName(String className) { // throw invalidAccess(); // } // // @Override // public Type getReferencedPropertyType(String className, String propertyName) { // throw invalidAccess(); // } // } @SuppressWarnings("unchecked") public <T> EntityPersister<T> findEntityPersister(String entityName) { return entityPersisterMap.get( entityName ); } public void register(EntityPersister entityPersister) { entityPersisterMap.put( entityPersister.getEntityName(), entityPersister ); } @SuppressWarnings("unchecked") public <O,C,E> CollectionPersister<O,C,E> findCollectionPersister(String roleName) { return collectionPersisterMap.get( roleName ); } public void register(CollectionPersister collectionPersister) { collectionPersisterMap.put( collectionPersister.getRoleName(), collectionPersister ); } @SuppressWarnings("unchecked") public <T> EmbeddableMapper<T> findEmbeddableMapper(String roleName) { return embeddableMapperMap.get( roleName ); } public void register(EmbeddableMapper mapper) { embeddableMapperMap.put( mapper.getRoleName(), mapper ); } public Collection<EmbeddableMapper> getEmbeddablePersisters() { return embeddableMapperMap.values(); } public Collection<EntityPersister> getEntityPersisters() { return entityPersisterMap.values(); } }