All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.internal.SessionFactoryImpl Maven / Gradle / Ivy

There is a newer version: 7.0.0.Alpha1
Show newest version
/*
 * 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.internal;

import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.naming.Reference;
import javax.naming.StringRefAddr;

import org.hibernate.AssertionFailure;
import org.hibernate.Cache;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.CustomEntityDirtinessStrategy;
import org.hibernate.EmptyInterceptor;
import org.hibernate.EntityNameResolver;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.MappingException;
import org.hibernate.MultiTenancyStrategy;
import org.hibernate.ObjectNotFoundException;
import org.hibernate.Session;
import org.hibernate.SessionBuilder;
import org.hibernate.SessionEventListener;
import org.hibernate.SessionFactory;
import org.hibernate.SessionFactoryObserver;
import org.hibernate.StatelessSession;
import org.hibernate.StatelessSessionBuilder;
import org.hibernate.TypeHelper;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.cache.internal.CacheDataDescriptionImpl;
import org.hibernate.cache.spi.CollectionRegion;
import org.hibernate.cache.spi.EntityRegion;
import org.hibernate.cache.spi.NaturalIdRegion;
import org.hibernate.cache.spi.QueryCache;
import org.hibernate.cache.spi.Region;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.UpdateTimestampsCache;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cache.spi.access.CollectionRegionAccessStrategy;
import org.hibernate.cache.spi.access.EntityRegionAccessStrategy;
import org.hibernate.cache.spi.access.NaturalIdRegionAccessStrategy;
import org.hibernate.cache.spi.access.RegionAccessStrategy;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.cfg.Settings;
import org.hibernate.cfg.SettingsFactory;
import org.hibernate.cfg.annotations.NamedProcedureCallDefinition;
import org.hibernate.context.internal.JTASessionContext;
import org.hibernate.context.internal.ManagedSessionContext;
import org.hibernate.context.internal.ThreadLocalSessionContext;
import org.hibernate.context.spi.CurrentSessionContext;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.function.SQLFunction;
import org.hibernate.dialect.function.SQLFunctionRegistry;
import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.hibernate.engine.jdbc.spi.JdbcConnectionAccess;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.jndi.spi.JndiService;
import org.hibernate.engine.profile.Association;
import org.hibernate.engine.profile.Fetch;
import org.hibernate.engine.profile.FetchProfile;
import org.hibernate.engine.query.spi.QueryPlanCache;
import org.hibernate.engine.query.spi.ReturnMetadata;
import org.hibernate.engine.spi.ActionQueue;
import org.hibernate.engine.spi.CacheImplementor;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.NamedQueryDefinition;
import org.hibernate.engine.spi.NamedSQLQueryDefinition;
import org.hibernate.engine.spi.SessionBuilderImplementor;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionOwner;
import org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
import org.hibernate.engine.transaction.spi.TransactionEnvironment;
import org.hibernate.engine.transaction.spi.TransactionFactory;
import org.hibernate.exception.spi.SQLExceptionConverter;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.UUIDGenerator;
import org.hibernate.id.factory.IdentifierGeneratorFactory;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.integrator.spi.IntegratorService;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.RootClass;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.metadata.CollectionMetadata;
import org.hibernate.metamodel.binding.EntityBinding;
import org.hibernate.metamodel.binding.PluralAttributeBinding;
import org.hibernate.metamodel.source.MetadataImplementor;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.persister.spi.PersisterFactory;
import org.hibernate.procedure.ProcedureCallMemento;
import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
import org.hibernate.service.spi.SessionFactoryServiceRegistryFactory;
import org.hibernate.stat.Statistics;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.tool.hbm2ddl.ImportSqlCommandExtractor;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.hbm2ddl.SchemaUpdate;
import org.hibernate.tool.hbm2ddl.SchemaValidator;
import org.hibernate.tuple.entity.EntityTuplizer;
import org.hibernate.type.AssociationType;
import org.hibernate.type.Type;
import org.hibernate.type.TypeResolver;
import org.jboss.logging.Logger;


/**
 * Concrete implementation of the SessionFactory interface. Has the following
 * responsibilities
 * 
    *
  • caches configuration settings (immutably) *
  • caches "compiled" mappings ie. EntityPersisters and * CollectionPersisters (immutable) *
  • caches "compiled" queries (memory sensitive cache) *
  • manages PreparedStatements *
  • delegates JDBC Connection management to the ConnectionProvider *
  • factory for instances of SessionImpl *
* This class must appear immutable to clients, even if it does all kinds of caching * and pooling under the covers. It is crucial that the class is not only thread * safe, but also highly concurrent. Synchronization must be used extremely sparingly. * * @see org.hibernate.engine.jdbc.connections.spi.ConnectionProvider * @see org.hibernate.Session * @see org.hibernate.hql.spi.QueryTranslator * @see org.hibernate.persister.entity.EntityPersister * @see org.hibernate.persister.collection.CollectionPersister * @author Gavin King */ public final class SessionFactoryImpl implements SessionFactoryImplementor { private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, SessionFactoryImpl.class.getName()); private static final IdentifierGenerator UUID_GENERATOR = UUIDGenerator.buildSessionFactoryUniqueIdentifierGenerator(); private final String name; private final String uuid; private final transient Map entityPersisters; private final transient Map classMetadata; private final transient Map collectionPersisters; private final transient Map collectionMetadata; private final transient Map> collectionRolesByEntityParticipant; private final transient Map identifierGenerators; private final transient NamedQueryRepository namedQueryRepository; private final transient Map filters; private final transient Map fetchProfiles; private final transient Map imports; private final transient SessionFactoryServiceRegistry serviceRegistry; private final transient JdbcServices jdbcServices; private final transient Dialect dialect; private final transient Settings settings; private final transient Properties properties; private transient SchemaExport schemaExport; private final transient CurrentSessionContext currentSessionContext; private final transient SQLFunctionRegistry sqlFunctionRegistry; private final transient SessionFactoryObserverChain observer = new SessionFactoryObserverChain(); private final transient ConcurrentHashMap entityNameResolvers = new ConcurrentHashMap(); private final transient QueryPlanCache queryPlanCache; private final transient CacheImplementor cacheAccess; private transient boolean isClosed; private final transient TypeResolver typeResolver; private final transient TypeHelper typeHelper; private final transient TransactionEnvironment transactionEnvironment; private final transient SessionFactoryOptions sessionFactoryOptions; private final transient CustomEntityDirtinessStrategy customEntityDirtinessStrategy; private final transient CurrentTenantIdentifierResolver currentTenantIdentifierResolver; @SuppressWarnings( {"unchecked", "ThrowableResultOfMethodCallIgnored"}) public SessionFactoryImpl( final Configuration cfg, Mapping mapping, final ServiceRegistry serviceRegistry, Settings settings, SessionFactoryObserver observer) throws HibernateException { LOG.debug( "Building session factory" ); sessionFactoryOptions = new SessionFactoryOptions() { private EntityNotFoundDelegate entityNotFoundDelegate; @Override public StandardServiceRegistry getServiceRegistry() { return (StandardServiceRegistry) serviceRegistry; } @Override public Interceptor getInterceptor() { return cfg.getInterceptor(); } @Override public EntityNotFoundDelegate getEntityNotFoundDelegate() { if ( entityNotFoundDelegate == null ) { if ( cfg.getEntityNotFoundDelegate() != null ) { entityNotFoundDelegate = cfg.getEntityNotFoundDelegate(); } else { entityNotFoundDelegate = new EntityNotFoundDelegate() { public void handleEntityNotFound(String entityName, Serializable id) { throw new ObjectNotFoundException( id, entityName ); } }; } } return entityNotFoundDelegate; } }; this.settings = settings; this.properties = new Properties(); this.properties.putAll( cfg.getProperties() ); this.serviceRegistry = serviceRegistry.getService( SessionFactoryServiceRegistryFactory.class ).buildServiceRegistry( this, cfg ); this.jdbcServices = this.serviceRegistry.getService( JdbcServices.class ); this.dialect = this.jdbcServices.getDialect(); this.cacheAccess = this.serviceRegistry.getService( CacheImplementor.class ); this.sqlFunctionRegistry = new SQLFunctionRegistry( getDialect(), cfg.getSqlFunctions() ); if ( observer != null ) { this.observer.addObserver( observer ); } this.typeResolver = cfg.getTypeResolver().scope( this ); this.typeHelper = new TypeLocatorImpl( typeResolver ); this.filters = new HashMap(); this.filters.putAll( cfg.getFilterDefinitions() ); LOG.debugf( "Session factory constructed with filter configurations : %s", filters ); LOG.debugf( "Instantiating session factory with properties: %s", properties ); this.queryPlanCache = new QueryPlanCache( this ); // todo : everything above here consider implementing as standard SF service. specifically: stats, caches, types, function-reg class IntegratorObserver implements SessionFactoryObserver { private ArrayList integrators = new ArrayList(); @Override public void sessionFactoryCreated(SessionFactory factory) { } @Override public void sessionFactoryClosed(SessionFactory factory) { for ( Integrator integrator : integrators ) { integrator.disintegrate( SessionFactoryImpl.this, SessionFactoryImpl.this.serviceRegistry ); } integrators.clear(); } } final IntegratorObserver integratorObserver = new IntegratorObserver(); this.observer.addObserver( integratorObserver ); for ( Integrator integrator : serviceRegistry.getService( IntegratorService.class ).getIntegrators() ) { integrator.integrate( cfg, this, this.serviceRegistry ); integratorObserver.integrators.add( integrator ); } //Generators: identifierGenerators = new HashMap(); Iterator classes = cfg.getClassMappings(); while ( classes.hasNext() ) { PersistentClass model = (PersistentClass) classes.next(); if ( !model.isInherited() ) { IdentifierGenerator generator = model.getIdentifier().createIdentifierGenerator( cfg.getIdentifierGeneratorFactory(), getDialect(), settings.getDefaultCatalogName(), settings.getDefaultSchemaName(), (RootClass) model ); identifierGenerators.put( model.getEntityName(), generator ); } } imports = new HashMap( cfg.getImports() ); /////////////////////////////////////////////////////////////////////// // Prepare persisters and link them up with their cache // region/access-strategy final RegionFactory regionFactory = cacheAccess.getRegionFactory(); final String cacheRegionPrefix = settings.getCacheRegionPrefix() == null ? "" : settings.getCacheRegionPrefix() + "."; final PersisterFactory persisterFactory = serviceRegistry.getService( PersisterFactory.class ); // todo : consider removing this silliness and just have EntityPersister directly implement ClassMetadata // EntityPersister.getClassMetadata() for the internal impls simply "return this"; // collapsing those would allow us to remove this "extra" Map // // todo : similar for CollectionPersister/CollectionMetadata entityPersisters = new HashMap(); Map entityAccessStrategies = new HashMap(); Map classMeta = new HashMap(); classes = cfg.getClassMappings(); while ( classes.hasNext() ) { final PersistentClass model = (PersistentClass) classes.next(); model.prepareTemporaryTables( mapping, getDialect() ); final String cacheRegionName = cacheRegionPrefix + model.getRootClass().getCacheRegionName(); // cache region is defined by the root-class in the hierarchy... EntityRegionAccessStrategy accessStrategy = ( EntityRegionAccessStrategy ) entityAccessStrategies.get( cacheRegionName ); if ( accessStrategy == null && settings.isSecondLevelCacheEnabled() ) { final AccessType accessType = AccessType.fromExternalName( model.getCacheConcurrencyStrategy() ); if ( accessType != null ) { LOG.tracef( "Building shared cache region for entity data [%s]", model.getEntityName() ); EntityRegion entityRegion = regionFactory.buildEntityRegion( cacheRegionName, properties, CacheDataDescriptionImpl.decode( model ) ); accessStrategy = entityRegion.buildAccessStrategy( accessType ); entityAccessStrategies.put( cacheRegionName, accessStrategy ); cacheAccess.addCacheRegion( cacheRegionName, entityRegion ); } } NaturalIdRegionAccessStrategy naturalIdAccessStrategy = null; if ( model.hasNaturalId() && model.getNaturalIdCacheRegionName() != null ) { final String naturalIdCacheRegionName = cacheRegionPrefix + model.getNaturalIdCacheRegionName(); naturalIdAccessStrategy = ( NaturalIdRegionAccessStrategy ) entityAccessStrategies.get( naturalIdCacheRegionName ); if ( naturalIdAccessStrategy == null && settings.isSecondLevelCacheEnabled() ) { final CacheDataDescriptionImpl cacheDataDescription = CacheDataDescriptionImpl.decode( model ); NaturalIdRegion naturalIdRegion = null; try { naturalIdRegion = regionFactory.buildNaturalIdRegion( naturalIdCacheRegionName, properties, cacheDataDescription ); } catch ( UnsupportedOperationException e ) { LOG.warnf( "Shared cache region factory [%s] does not support natural id caching; " + "shared NaturalId caching will be disabled for not be enabled for %s", regionFactory.getClass().getName(), model.getEntityName() ); } if (naturalIdRegion != null) { naturalIdAccessStrategy = naturalIdRegion.buildAccessStrategy( regionFactory.getDefaultAccessType() ); entityAccessStrategies.put( naturalIdCacheRegionName, naturalIdAccessStrategy ); cacheAccess.addCacheRegion( naturalIdCacheRegionName, naturalIdRegion ); } } } EntityPersister cp = persisterFactory.createEntityPersister( model, accessStrategy, naturalIdAccessStrategy, this, mapping ); entityPersisters.put( model.getEntityName(), cp ); classMeta.put( model.getEntityName(), cp.getClassMetadata() ); } this.classMetadata = Collections.unmodifiableMap(classMeta); Map> tmpEntityToCollectionRoleMap = new HashMap>(); collectionPersisters = new HashMap(); Map tmpCollectionMetadata = new HashMap(); Iterator collections = cfg.getCollectionMappings(); while ( collections.hasNext() ) { Collection model = (Collection) collections.next(); final String cacheRegionName = cacheRegionPrefix + model.getCacheRegionName(); final AccessType accessType = AccessType.fromExternalName( model.getCacheConcurrencyStrategy() ); CollectionRegionAccessStrategy accessStrategy = null; if ( accessType != null && settings.isSecondLevelCacheEnabled() ) { LOG.tracev( "Building shared cache region for collection data [{0}]", model.getRole() ); CollectionRegion collectionRegion = regionFactory.buildCollectionRegion( cacheRegionName, properties, CacheDataDescriptionImpl .decode( model ) ); accessStrategy = collectionRegion.buildAccessStrategy( accessType ); entityAccessStrategies.put( cacheRegionName, accessStrategy ); cacheAccess.addCacheRegion( cacheRegionName, collectionRegion ); } CollectionPersister persister = persisterFactory.createCollectionPersister( cfg, model, accessStrategy, this ) ; collectionPersisters.put( model.getRole(), persister ); tmpCollectionMetadata.put( model.getRole(), persister.getCollectionMetadata() ); Type indexType = persister.getIndexType(); if ( indexType != null && indexType.isAssociationType() && !indexType.isAnyType() ) { String entityName = ( ( AssociationType ) indexType ).getAssociatedEntityName( this ); Set roles = tmpEntityToCollectionRoleMap.get( entityName ); if ( roles == null ) { roles = new HashSet(); tmpEntityToCollectionRoleMap.put( entityName, roles ); } roles.add( persister.getRole() ); } Type elementType = persister.getElementType(); if ( elementType.isAssociationType() && !elementType.isAnyType() ) { String entityName = ( ( AssociationType ) elementType ).getAssociatedEntityName( this ); Set roles = tmpEntityToCollectionRoleMap.get( entityName ); if ( roles == null ) { roles = new HashSet(); tmpEntityToCollectionRoleMap.put( entityName, roles ); } roles.add( persister.getRole() ); } } collectionMetadata = Collections.unmodifiableMap( tmpCollectionMetadata ); Iterator itr = tmpEntityToCollectionRoleMap.entrySet().iterator(); while ( itr.hasNext() ) { final Map.Entry entry = ( Map.Entry ) itr.next(); entry.setValue( Collections.unmodifiableSet( ( Set ) entry.getValue() ) ); } collectionRolesByEntityParticipant = Collections.unmodifiableMap( tmpEntityToCollectionRoleMap ); //Named Queries: this.namedQueryRepository = new NamedQueryRepository( cfg.getNamedQueries().values(), cfg.getNamedSQLQueries().values(), cfg.getSqlResultSetMappings().values(), toProcedureCallMementos( cfg.getNamedProcedureCallMap(), cfg.getSqlResultSetMappings() ) ); // after *all* persisters and named queries are registered for ( EntityPersister persister : entityPersisters.values() ) { persister.generateEntityDefinition(); } for ( EntityPersister persister : entityPersisters.values() ) { persister.postInstantiate(); registerEntityNameResolvers( persister ); } for ( CollectionPersister persister : collectionPersisters.values() ) { persister.postInstantiate(); } //JNDI + Serialization: name = settings.getSessionFactoryName(); try { uuid = (String) UUID_GENERATOR.generate(null, null); } catch (Exception e) { throw new AssertionFailure("Could not generate UUID"); } SessionFactoryRegistry.INSTANCE.addSessionFactory( uuid, name, settings.isSessionFactoryNameAlsoJndiName(), this, serviceRegistry.getService( JndiService.class ) ); LOG.debug( "Instantiated session factory" ); settings.getMultiTableBulkIdStrategy().prepare( jdbcServices, buildLocalConnectionAccess(), cfg.createMappings(), cfg.buildMapping(), properties ); if ( settings.isAutoCreateSchema() ) { new SchemaExport( serviceRegistry, cfg ) .setImportSqlCommandExtractor( serviceRegistry.getService( ImportSqlCommandExtractor.class ) ) .create( false, true ); } if ( settings.isAutoUpdateSchema() ) { new SchemaUpdate( serviceRegistry, cfg ).execute( false, true ); } if ( settings.isAutoValidateSchema() ) { new SchemaValidator( serviceRegistry, cfg ).validate(); } if ( settings.isAutoDropSchema() ) { schemaExport = new SchemaExport( serviceRegistry, cfg ) .setImportSqlCommandExtractor( serviceRegistry.getService( ImportSqlCommandExtractor.class ) ); } currentSessionContext = buildCurrentSessionContext(); //checking for named queries if ( settings.isNamedQueryStartupCheckingEnabled() ) { final Map errors = checkNamedQueries(); if ( ! errors.isEmpty() ) { StringBuilder failingQueries = new StringBuilder( "Errors in named queries: " ); String sep = ""; for ( Map.Entry entry : errors.entrySet() ) { LOG.namedQueryError( entry.getKey(), entry.getValue() ); failingQueries.append( sep ).append( entry.getKey() ); sep = ", "; } throw new HibernateException( failingQueries.toString() ); } } // this needs to happen after persisters are all ready to go... this.fetchProfiles = new HashMap(); itr = cfg.iterateFetchProfiles(); while ( itr.hasNext() ) { final org.hibernate.mapping.FetchProfile mappingProfile = ( org.hibernate.mapping.FetchProfile ) itr.next(); final FetchProfile fetchProfile = new FetchProfile( mappingProfile.getName() ); for ( org.hibernate.mapping.FetchProfile.Fetch mappingFetch : mappingProfile.getFetches() ) { // resolve the persister owning the fetch final String entityName = getImportedClassName( mappingFetch.getEntity() ); final EntityPersister owner = entityName == null ? null : entityPersisters.get( entityName ); if ( owner == null ) { throw new HibernateException( "Unable to resolve entity reference [" + mappingFetch.getEntity() + "] in fetch profile [" + fetchProfile.getName() + "]" ); } // validate the specified association fetch Type associationType = owner.getPropertyType( mappingFetch.getAssociation() ); if ( associationType == null || !associationType.isAssociationType() ) { throw new HibernateException( "Fetch profile [" + fetchProfile.getName() + "] specified an invalid association" ); } // resolve the style final Fetch.Style fetchStyle = Fetch.Style.parse( mappingFetch.getStyle() ); // then construct the fetch instance... fetchProfile.addFetch( new Association( owner, mappingFetch.getAssociation() ), fetchStyle ); ((Loadable) owner).registerAffectingFetchProfile( fetchProfile.getName() ); } fetchProfiles.put( fetchProfile.getName(), fetchProfile ); } this.customEntityDirtinessStrategy = determineCustomEntityDirtinessStrategy(); this.currentTenantIdentifierResolver = determineCurrentTenantIdentifierResolver( cfg.getCurrentTenantIdentifierResolver() ); this.transactionEnvironment = new TransactionEnvironmentImpl( this ); this.observer.sessionFactoryCreated( this ); } private Map toProcedureCallMementos( Map definitions, Map resultSetMappingMap) { final Map rtn = new HashMap(); if ( definitions != null ) { for (String name : definitions.keySet()){ rtn.put( name, definitions.get( name ).toMemento( this, resultSetMappingMap )); } } return rtn; } private JdbcConnectionAccess buildLocalConnectionAccess() { return new JdbcConnectionAccess() { @Override public Connection obtainConnection() throws SQLException { return settings.getMultiTenancyStrategy() == MultiTenancyStrategy.NONE ? serviceRegistry.getService( ConnectionProvider.class ).getConnection() : serviceRegistry.getService( MultiTenantConnectionProvider.class ).getAnyConnection(); } @Override public void releaseConnection(Connection connection) throws SQLException { if ( settings.getMultiTenancyStrategy() == MultiTenancyStrategy.NONE ) { serviceRegistry.getService( ConnectionProvider.class ).closeConnection( connection ); } else { serviceRegistry.getService( MultiTenantConnectionProvider.class ).releaseAnyConnection( connection ); } } @Override public boolean supportsAggressiveRelease() { return false; } }; } @SuppressWarnings({ "unchecked" }) private CustomEntityDirtinessStrategy determineCustomEntityDirtinessStrategy() { CustomEntityDirtinessStrategy defaultValue = new CustomEntityDirtinessStrategy() { @Override public boolean canDirtyCheck(Object entity, EntityPersister persister, Session session) { return false; } @Override public boolean isDirty(Object entity, EntityPersister persister, Session session) { return false; } @Override public void resetDirty(Object entity, EntityPersister persister, Session session) { } @Override public void findDirty( Object entity, EntityPersister persister, Session session, DirtyCheckContext dirtyCheckContext) { // todo : implement proper method body } }; return serviceRegistry.getService( ConfigurationService.class ).getSetting( AvailableSettings.CUSTOM_ENTITY_DIRTINESS_STRATEGY, CustomEntityDirtinessStrategy.class, defaultValue ); } @SuppressWarnings({ "unchecked" }) private CurrentTenantIdentifierResolver determineCurrentTenantIdentifierResolver( CurrentTenantIdentifierResolver explicitResolver) { if ( explicitResolver != null ) { return explicitResolver; } return serviceRegistry.getService( ConfigurationService.class ) .getSetting( AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER, CurrentTenantIdentifierResolver.class, null ); } @SuppressWarnings( {"ThrowableResultOfMethodCallIgnored"}) public SessionFactoryImpl( MetadataImplementor metadata, SessionFactoryOptions sessionFactoryOptions, SessionFactoryObserver observer) throws HibernateException { final boolean traceEnabled = LOG.isTraceEnabled(); final boolean debugEnabled = traceEnabled || LOG.isDebugEnabled(); if ( debugEnabled ) { LOG.debug( "Building session factory" ); } this.sessionFactoryOptions = sessionFactoryOptions; this.properties = createPropertiesFromMap( metadata.getServiceRegistry().getService( ConfigurationService.class ).getSettings() ); // TODO: these should be moved into SessionFactoryOptions this.settings = new SettingsFactory().buildSettings( properties, metadata.getServiceRegistry() ); this.serviceRegistry = sessionFactoryOptions.getServiceRegistry() .getService( SessionFactoryServiceRegistryFactory.class ) .buildServiceRegistry( this, metadata ); this.jdbcServices = this.serviceRegistry.getService( JdbcServices.class ); this.dialect = this.jdbcServices.getDialect(); this.cacheAccess = this.serviceRegistry.getService( CacheImplementor.class ); // TODO: get SQL functions from JdbcServices (HHH-6559) //this.sqlFunctionRegistry = new SQLFunctionRegistry( this.jdbcServices.getSqlFunctions() ); this.sqlFunctionRegistry = new SQLFunctionRegistry( this.dialect, new HashMap() ); // TODO: get SQL functions from a new service // this.sqlFunctionRegistry = new SQLFunctionRegistry( getDialect(), cfg.getSqlFunctions() ); if ( observer != null ) { this.observer.addObserver( observer ); } this.typeResolver = metadata.getTypeResolver().scope( this ); this.typeHelper = new TypeLocatorImpl( typeResolver ); this.filters = new HashMap(); for ( FilterDefinition filterDefinition : metadata.getFilterDefinitions() ) { filters.put( filterDefinition.getFilterName(), filterDefinition ); } if ( debugEnabled ) { LOG.debugf( "Session factory constructed with filter configurations : %s", filters ); LOG.debugf( "Instantiating session factory with properties: %s", properties ); } this.queryPlanCache = new QueryPlanCache( this ); class IntegratorObserver implements SessionFactoryObserver { private ArrayList integrators = new ArrayList(); @Override public void sessionFactoryCreated(SessionFactory factory) { } @Override public void sessionFactoryClosed(SessionFactory factory) { for ( Integrator integrator : integrators ) { integrator.disintegrate( SessionFactoryImpl.this, SessionFactoryImpl.this.serviceRegistry ); } integrators.clear(); } } final IntegratorObserver integratorObserver = new IntegratorObserver(); this.observer.addObserver(integratorObserver); for (Integrator integrator : serviceRegistry.getService(IntegratorService.class).getIntegrators()) { integrator.integrate(metadata, this, this.serviceRegistry); integratorObserver.integrators.add(integrator); } //Generators: identifierGenerators = new HashMap(); for ( EntityBinding entityBinding : metadata.getEntityBindings() ) { if ( entityBinding.isRoot() ) { identifierGenerators.put( entityBinding.getEntity().getName(), entityBinding.getHierarchyDetails().getEntityIdentifier().getIdentifierGenerator() ); } } /////////////////////////////////////////////////////////////////////// // Prepare persisters and link them up with their cache // region/access-strategy StringBuilder stringBuilder = new StringBuilder(); if ( settings.getCacheRegionPrefix() != null) { stringBuilder .append( settings.getCacheRegionPrefix() ) .append( '.' ); } final String cacheRegionPrefix = stringBuilder.toString(); entityPersisters = new HashMap(); Map entityAccessStrategies = new HashMap(); Map classMeta = new HashMap(); for ( EntityBinding model : metadata.getEntityBindings() ) { // TODO: should temp table prep happen when metadata is being built? //model.prepareTemporaryTables( metadata, getDialect() ); // cache region is defined by the root-class in the hierarchy... EntityBinding rootEntityBinding = metadata.getRootEntityBinding( model.getEntity().getName() ); EntityRegionAccessStrategy accessStrategy = null; if ( settings.isSecondLevelCacheEnabled() && rootEntityBinding.getHierarchyDetails().getCaching() != null && model.getHierarchyDetails().getCaching() != null && model.getHierarchyDetails().getCaching().getAccessType() != null ) { final String cacheRegionName = cacheRegionPrefix + rootEntityBinding.getHierarchyDetails().getCaching().getRegion(); accessStrategy = EntityRegionAccessStrategy.class.cast( entityAccessStrategies.get( cacheRegionName ) ); if ( accessStrategy == null ) { final AccessType accessType = model.getHierarchyDetails().getCaching().getAccessType(); if ( traceEnabled ) { LOG.tracev( "Building cache for entity data [{0}]", model.getEntity().getName() ); } EntityRegion entityRegion = settings.getRegionFactory().buildEntityRegion( cacheRegionName, properties, CacheDataDescriptionImpl.decode( model ) ); accessStrategy = entityRegion.buildAccessStrategy( accessType ); entityAccessStrategies.put( cacheRegionName, accessStrategy ); cacheAccess.addCacheRegion( cacheRegionName, entityRegion ); } } EntityPersister cp = serviceRegistry.getService( PersisterFactory.class ).createEntityPersister( model, accessStrategy, this, metadata ); entityPersisters.put( model.getEntity().getName(), cp ); classMeta.put( model.getEntity().getName(), cp.getClassMetadata() ); } this.classMetadata = Collections.unmodifiableMap(classMeta); Map> tmpEntityToCollectionRoleMap = new HashMap>(); collectionPersisters = new HashMap(); Map tmpCollectionMetadata = new HashMap(); for ( PluralAttributeBinding model : metadata.getCollectionBindings() ) { if ( model.getAttribute() == null ) { throw new IllegalStateException( "No attribute defined for a AbstractPluralAttributeBinding: " + model ); } if ( model.getAttribute().isSingular() ) { throw new IllegalStateException( "AbstractPluralAttributeBinding has a Singular attribute defined: " + model.getAttribute().getName() ); } final String cacheRegionName = cacheRegionPrefix + model.getCaching().getRegion(); final AccessType accessType = model.getCaching().getAccessType(); CollectionRegionAccessStrategy accessStrategy = null; if ( accessType != null && settings.isSecondLevelCacheEnabled() ) { if ( traceEnabled ) { LOG.tracev( "Building cache for collection data [{0}]", model.getAttribute().getRole() ); } CollectionRegion collectionRegion = settings.getRegionFactory().buildCollectionRegion( cacheRegionName, properties, CacheDataDescriptionImpl.decode( model ) ); accessStrategy = collectionRegion.buildAccessStrategy( accessType ); entityAccessStrategies.put( cacheRegionName, accessStrategy ); cacheAccess.addCacheRegion( cacheRegionName, collectionRegion ); } CollectionPersister persister = serviceRegistry .getService( PersisterFactory.class ) .createCollectionPersister( metadata, model, accessStrategy, this ); collectionPersisters.put( model.getAttribute().getRole(), persister ); tmpCollectionMetadata.put( model.getAttribute().getRole(), persister.getCollectionMetadata() ); Type indexType = persister.getIndexType(); if ( indexType != null && indexType.isAssociationType() && !indexType.isAnyType() ) { String entityName = ( ( AssociationType ) indexType ).getAssociatedEntityName( this ); Set roles = tmpEntityToCollectionRoleMap.get( entityName ); if ( roles == null ) { roles = new HashSet(); tmpEntityToCollectionRoleMap.put( entityName, roles ); } roles.add( persister.getRole() ); } Type elementType = persister.getElementType(); if ( elementType.isAssociationType() && !elementType.isAnyType() ) { String entityName = ( ( AssociationType ) elementType ).getAssociatedEntityName( this ); Set roles = tmpEntityToCollectionRoleMap.get( entityName ); if ( roles == null ) { roles = new HashSet(); tmpEntityToCollectionRoleMap.put( entityName, roles ); } roles.add( persister.getRole() ); } } collectionMetadata = Collections.unmodifiableMap( tmpCollectionMetadata ); for ( Map.Entry> entry : tmpEntityToCollectionRoleMap.entrySet() ) { entry.setValue( Collections.unmodifiableSet( entry.getValue() ) ); } collectionRolesByEntityParticipant = Collections.unmodifiableMap( tmpEntityToCollectionRoleMap ); //Named Queries: namedQueryRepository = new NamedQueryRepository( metadata.getNamedQueryDefinitions(), metadata.getNamedNativeQueryDefinitions(), metadata.getResultSetMappingDefinitions(), new HashMap( ) ); imports = new HashMap(); for ( Map.Entry importEntry : metadata.getImports() ) { imports.put( importEntry.getKey(), importEntry.getValue() ); } // after *all* persisters and named queries are registered Iterator iter = entityPersisters.values().iterator(); while ( iter.hasNext() ) { final EntityPersister persister = ( ( EntityPersister ) iter.next() ); persister.postInstantiate(); registerEntityNameResolvers( persister ); } iter = collectionPersisters.values().iterator(); while ( iter.hasNext() ) { final CollectionPersister persister = ( ( CollectionPersister ) iter.next() ); persister.postInstantiate(); } //JNDI + Serialization: name = settings.getSessionFactoryName(); try { uuid = (String) UUID_GENERATOR.generate(null, null); } catch (Exception e) { throw new AssertionFailure("Could not generate UUID"); } SessionFactoryRegistry.INSTANCE.addSessionFactory( uuid, name, settings.isSessionFactoryNameAlsoJndiName(), this, serviceRegistry.getService( JndiService.class ) ); if ( debugEnabled ) { LOG.debug("Instantiated session factory"); } if ( settings.isAutoCreateSchema() ) { new SchemaExport( metadata ) .setImportSqlCommandExtractor( serviceRegistry.getService( ImportSqlCommandExtractor.class ) ) .create( false, true ); } if ( settings.isAutoDropSchema() ) { schemaExport = new SchemaExport( metadata ) .setImportSqlCommandExtractor( serviceRegistry.getService( ImportSqlCommandExtractor.class ) ); } currentSessionContext = buildCurrentSessionContext(); //checking for named queries if ( settings.isNamedQueryStartupCheckingEnabled() ) { final Map errors = checkNamedQueries(); if ( ! errors.isEmpty() ) { StringBuilder failingQueries = new StringBuilder( "Errors in named queries: " ); String sep = ""; for ( Map.Entry entry : errors.entrySet() ) { LOG.namedQueryError( entry.getKey(), entry.getValue() ); failingQueries.append( entry.getKey() ).append( sep ); sep = ", "; } throw new HibernateException( failingQueries.toString() ); } } // this needs to happen after persisters are all ready to go... this.fetchProfiles = new HashMap(); for ( org.hibernate.metamodel.binding.FetchProfile mappingProfile : metadata.getFetchProfiles() ) { final FetchProfile fetchProfile = new FetchProfile( mappingProfile.getName() ); for ( org.hibernate.metamodel.binding.FetchProfile.Fetch mappingFetch : mappingProfile.getFetches() ) { // resolve the persister owning the fetch final String entityName = getImportedClassName( mappingFetch.getEntity() ); final EntityPersister owner = entityName == null ? null : entityPersisters.get( entityName ); if ( owner == null ) { throw new HibernateException( "Unable to resolve entity reference [" + mappingFetch.getEntity() + "] in fetch profile [" + fetchProfile.getName() + "]" ); } // validate the specified association fetch Type associationType = owner.getPropertyType( mappingFetch.getAssociation() ); if ( associationType == null || ! associationType.isAssociationType() ) { throw new HibernateException( "Fetch profile [" + fetchProfile.getName() + "] specified an invalid association" ); } // resolve the style final Fetch.Style fetchStyle = Fetch.Style.parse( mappingFetch.getStyle() ); // then construct the fetch instance... fetchProfile.addFetch( new Association( owner, mappingFetch.getAssociation() ), fetchStyle ); ( ( Loadable ) owner ).registerAffectingFetchProfile( fetchProfile.getName() ); } fetchProfiles.put( fetchProfile.getName(), fetchProfile ); } this.customEntityDirtinessStrategy = determineCustomEntityDirtinessStrategy(); this.currentTenantIdentifierResolver = determineCurrentTenantIdentifierResolver( null ); this.transactionEnvironment = new TransactionEnvironmentImpl( this ); this.observer.sessionFactoryCreated( this ); } @SuppressWarnings( {"unchecked"} ) private static Properties createPropertiesFromMap(Map map) { Properties properties = new Properties(); properties.putAll( map ); return properties; } public Session openSession() throws HibernateException { return withOptions().openSession(); } public Session openTemporarySession() throws HibernateException { return withOptions() .autoClose( false ) .flushBeforeCompletion( false ) .connectionReleaseMode( ConnectionReleaseMode.AFTER_STATEMENT ) .openSession(); } public Session getCurrentSession() throws HibernateException { if ( currentSessionContext == null ) { throw new HibernateException( "No CurrentSessionContext configured!" ); } return currentSessionContext.currentSession(); } @Override public SessionBuilderImplementor withOptions() { return new SessionBuilderImpl( this ); } @Override public StatelessSessionBuilder withStatelessOptions() { return new StatelessSessionBuilderImpl( this ); } public StatelessSession openStatelessSession() { return withStatelessOptions().openStatelessSession(); } public StatelessSession openStatelessSession(Connection connection) { return withStatelessOptions().connection( connection ).openStatelessSession(); } @Override public void addObserver(SessionFactoryObserver observer) { this.observer.addObserver( observer ); } public TransactionEnvironment getTransactionEnvironment() { return transactionEnvironment; } public Properties getProperties() { return properties; } public IdentifierGeneratorFactory getIdentifierGeneratorFactory() { return null; } public TypeResolver getTypeResolver() { return typeResolver; } private void registerEntityNameResolvers(EntityPersister persister) { if ( persister.getEntityMetamodel() == null || persister.getEntityMetamodel().getTuplizer() == null ) { return; } registerEntityNameResolvers( persister.getEntityMetamodel().getTuplizer() ); } private void registerEntityNameResolvers(EntityTuplizer tuplizer) { EntityNameResolver[] resolvers = tuplizer.getEntityNameResolvers(); if ( resolvers == null ) { return; } for ( EntityNameResolver resolver : resolvers ) { registerEntityNameResolver( resolver ); } } private static final Object ENTITY_NAME_RESOLVER_MAP_VALUE = new Object(); public void registerEntityNameResolver(EntityNameResolver resolver) { entityNameResolvers.put( resolver, ENTITY_NAME_RESOLVER_MAP_VALUE ); } @Override public Iterable iterateEntityNameResolvers() { return entityNameResolvers.keySet(); } public QueryPlanCache getQueryPlanCache() { return queryPlanCache; } private Map checkNamedQueries() throws HibernateException { return namedQueryRepository.checkNamedQueries( queryPlanCache ); } public EntityPersister getEntityPersister(String entityName) throws MappingException { EntityPersister result = entityPersisters.get(entityName); if ( result == null ) { throw new MappingException( "Unknown entity: " + entityName ); } return result; } @Override public Map getCollectionPersisters() { return collectionPersisters; } @Override public Map getEntityPersisters() { return entityPersisters; } public CollectionPersister getCollectionPersister(String role) throws MappingException { CollectionPersister result = collectionPersisters.get(role); if ( result == null ) { throw new MappingException( "Unknown collection role: " + role ); } return result; } public Settings getSettings() { return settings; } @Override public SessionFactoryOptions getSessionFactoryOptions() { return sessionFactoryOptions; } public JdbcServices getJdbcServices() { return jdbcServices; } public Dialect getDialect() { if ( serviceRegistry == null ) { throw new IllegalStateException( "Cannot determine dialect because serviceRegistry is null." ); } return dialect; } public Interceptor getInterceptor() { return sessionFactoryOptions.getInterceptor(); } public SQLExceptionConverter getSQLExceptionConverter() { return getSQLExceptionHelper().getSqlExceptionConverter(); } public SqlExceptionHelper getSQLExceptionHelper() { return getJdbcServices().getSqlExceptionHelper(); } public Set getCollectionRolesByEntityParticipant(String entityName) { return collectionRolesByEntityParticipant.get( entityName ); } @Override public Reference getReference() { // from javax.naming.Referenceable LOG.debug( "Returning a Reference to the SessionFactory" ); return new Reference( SessionFactoryImpl.class.getName(), new StringRefAddr("uuid", uuid), SessionFactoryRegistry.ObjectFactoryImpl.class.getName(), null ); } @Override public NamedQueryRepository getNamedQueryRepository() { return namedQueryRepository; } public void registerNamedQueryDefinition(String name, NamedQueryDefinition definition) { namedQueryRepository.registerNamedQueryDefinition( name, definition ); } public NamedQueryDefinition getNamedQuery(String queryName) { return namedQueryRepository.getNamedQueryDefinition( queryName ); } public void registerNamedSQLQueryDefinition(String name, NamedSQLQueryDefinition definition) { namedQueryRepository.registerNamedSQLQueryDefinition( name, definition ); } public NamedSQLQueryDefinition getNamedSQLQuery(String queryName) { return namedQueryRepository.getNamedSQLQueryDefinition( queryName ); } public ResultSetMappingDefinition getResultSetMapping(String mappingName) { return namedQueryRepository.getResultSetMappingDefinition( mappingName ); } public Type getIdentifierType(String className) throws MappingException { return getEntityPersister(className).getIdentifierType(); } public String getIdentifierPropertyName(String className) throws MappingException { return getEntityPersister(className).getIdentifierPropertyName(); } public Type[] getReturnTypes(String queryString) throws HibernateException { final ReturnMetadata metadata = queryPlanCache.getHQLQueryPlan( queryString, false, Collections.EMPTY_MAP ) .getReturnMetadata(); return metadata == null ? null : metadata.getReturnTypes(); } public String[] getReturnAliases(String queryString) throws HibernateException { final ReturnMetadata metadata = queryPlanCache.getHQLQueryPlan( queryString, false, Collections.EMPTY_MAP ) .getReturnMetadata(); return metadata == null ? null : metadata.getReturnAliases(); } public ClassMetadata getClassMetadata(Class persistentClass) throws HibernateException { return getClassMetadata( persistentClass.getName() ); } public CollectionMetadata getCollectionMetadata(String roleName) throws HibernateException { return collectionMetadata.get(roleName); } public ClassMetadata getClassMetadata(String entityName) throws HibernateException { return classMetadata.get( entityName ); } /** * Given the name of an entity class, determine all the class and interface names by which it can be * referenced in an HQL query. * * @param className The name of the entity class * * @return the names of all persistent (mapped) classes that extend or implement the * given class or interface, accounting for implicit/explicit polymorphism settings * and excluding mapped subclasses/joined-subclasses of other classes in the result. * @throws MappingException */ public String[] getImplementors(String className) throws MappingException { final Class clazz; try { clazz = serviceRegistry.getService( ClassLoaderService.class ).classForName( className ); } catch (ClassLoadingException cnfe) { return new String[] { className }; //for a dynamic-class } ArrayList results = new ArrayList(); for ( EntityPersister checkPersister : entityPersisters.values() ) { if ( ! Queryable.class.isInstance( checkPersister ) ) { continue; } final Queryable checkQueryable = Queryable.class.cast( checkPersister ); final String checkQueryableEntityName = checkQueryable.getEntityName(); final boolean isMappedClass = className.equals( checkQueryableEntityName ); if ( checkQueryable.isExplicitPolymorphism() ) { if ( isMappedClass ) { return new String[] { className }; //NOTE EARLY EXIT } } else { if ( isMappedClass ) { results.add( checkQueryableEntityName ); } else { final Class mappedClass = checkQueryable.getMappedClass(); if ( mappedClass != null && clazz.isAssignableFrom( mappedClass ) ) { final boolean assignableSuperclass; if ( checkQueryable.isInherited() ) { Class mappedSuperclass = getEntityPersister( checkQueryable.getMappedSuperclass() ).getMappedClass(); assignableSuperclass = clazz.isAssignableFrom( mappedSuperclass ); } else { assignableSuperclass = false; } if ( !assignableSuperclass ) { results.add( checkQueryableEntityName ); } } } } } return results.toArray( new String[results.size()] ); } @Override public String getImportedClassName(String className) { String result = imports.get( className ); if ( result == null ) { try { serviceRegistry.getService( ClassLoaderService.class ).classForName( className ); imports.put( className, className ); return className; } catch ( ClassLoadingException cnfe ) { return null; } } else { return result; } } public Map getAllClassMetadata() throws HibernateException { return classMetadata; } public Map getAllCollectionMetadata() throws HibernateException { return collectionMetadata; } public Type getReferencedPropertyType(String className, String propertyName) throws MappingException { return getEntityPersister( className ).getPropertyType( propertyName ); } public ConnectionProvider getConnectionProvider() { return jdbcServices.getConnectionProvider(); } /** * Closes the session factory, releasing all held resources. * *
    *
  1. cleans up used cache regions and "stops" the cache provider. *
  2. close the JDBC connection *
  3. remove the JNDI binding *
* * Note: Be aware that the sessionFactory instance still can * be a "heavy" object memory wise after close() has been called. Thus * it is important to not keep referencing the instance to let the garbage * collector release the memory. * @throws HibernateException */ public void close() throws HibernateException { if ( isClosed ) { LOG.trace( "Already closed" ); return; } LOG.closing(); isClosed = true; settings.getMultiTableBulkIdStrategy().release( jdbcServices, buildLocalConnectionAccess() ); Iterator iter = entityPersisters.values().iterator(); while ( iter.hasNext() ) { EntityPersister p = (EntityPersister) iter.next(); if ( p.hasCache() ) { p.getCacheAccessStrategy().getRegion().destroy(); } } iter = collectionPersisters.values().iterator(); while ( iter.hasNext() ) { CollectionPersister p = (CollectionPersister) iter.next(); if ( p.hasCache() ) { p.getCacheAccessStrategy().getRegion().destroy(); } } cacheAccess.close(); queryPlanCache.cleanup(); if ( settings.isAutoDropSchema() ) { schemaExport.drop( false, true ); } SessionFactoryRegistry.INSTANCE.removeSessionFactory( uuid, name, settings.isSessionFactoryNameAlsoJndiName(), serviceRegistry.getService( JndiService.class ) ); observer.sessionFactoryClosed( this ); serviceRegistry.destroy(); } public Cache getCache() { return cacheAccess; } public void evictEntity(String entityName, Serializable id) throws HibernateException { getCache().evictEntity( entityName, id ); } public void evictEntity(String entityName) throws HibernateException { getCache().evictEntityRegion( entityName ); } public void evict(Class persistentClass, Serializable id) throws HibernateException { getCache().evictEntity( persistentClass, id ); } public void evict(Class persistentClass) throws HibernateException { getCache().evictEntityRegion( persistentClass ); } public void evictCollection(String roleName, Serializable id) throws HibernateException { getCache().evictCollection( roleName, id ); } public void evictCollection(String roleName) throws HibernateException { getCache().evictCollectionRegion( roleName ); } public void evictQueries() throws HibernateException { cacheAccess.evictQueries(); } public void evictQueries(String regionName) throws HibernateException { getCache().evictQueryRegion( regionName ); } public UpdateTimestampsCache getUpdateTimestampsCache() { return cacheAccess.getUpdateTimestampsCache(); } public QueryCache getQueryCache() { return cacheAccess.getQueryCache(); } public QueryCache getQueryCache(String regionName) throws HibernateException { return cacheAccess.getQueryCache( regionName ); } public Region getSecondLevelCacheRegion(String regionName) { return cacheAccess.getSecondLevelCacheRegion( regionName ); } public Region getNaturalIdCacheRegion(String regionName) { return cacheAccess.getNaturalIdCacheRegion( regionName ); } @SuppressWarnings( {"unchecked"}) public Map getAllSecondLevelCacheRegions() { return cacheAccess.getAllSecondLevelCacheRegions(); } public boolean isClosed() { return isClosed; } public Statistics getStatistics() { return getStatisticsImplementor(); } public StatisticsImplementor getStatisticsImplementor() { return serviceRegistry.getService( StatisticsImplementor.class ); } public FilterDefinition getFilterDefinition(String filterName) throws HibernateException { FilterDefinition def = filters.get( filterName ); if ( def == null ) { throw new HibernateException( "No such filter configured [" + filterName + "]" ); } return def; } public boolean containsFetchProfileDefinition(String name) { return fetchProfiles.containsKey( name ); } public Set getDefinedFilterNames() { return filters.keySet(); } public IdentifierGenerator getIdentifierGenerator(String rootEntityName) { return identifierGenerators.get(rootEntityName); } private TransactionFactory transactionFactory() { return serviceRegistry.getService( TransactionFactory.class ); } private boolean canAccessTransactionManager() { try { return serviceRegistry.getService( JtaPlatform.class ).retrieveTransactionManager() != null; } catch (Exception e) { return false; } } private CurrentSessionContext buildCurrentSessionContext() { String impl = properties.getProperty( Environment.CURRENT_SESSION_CONTEXT_CLASS ); // for backward-compatibility if ( impl == null ) { if ( canAccessTransactionManager() ) { impl = "jta"; } else { return null; } } if ( "jta".equals( impl ) ) { if ( ! transactionFactory().compatibleWithJtaSynchronization() ) { LOG.autoFlushWillNotWork(); } return new JTASessionContext( this ); } else if ( "thread".equals( impl ) ) { return new ThreadLocalSessionContext( this ); } else if ( "managed".equals( impl ) ) { return new ManagedSessionContext( this ); } else { try { Class implClass = serviceRegistry.getService( ClassLoaderService.class ).classForName( impl ); return ( CurrentSessionContext ) implClass .getConstructor( new Class[] { SessionFactoryImplementor.class } ) .newInstance( this ); } catch( Throwable t ) { LOG.unableToConstructCurrentSessionContext( impl, t ); return null; } } } @Override public ServiceRegistryImplementor getServiceRegistry() { return serviceRegistry; } @Override public EntityNotFoundDelegate getEntityNotFoundDelegate() { return sessionFactoryOptions.getEntityNotFoundDelegate(); } public SQLFunctionRegistry getSqlFunctionRegistry() { return sqlFunctionRegistry; } public FetchProfile getFetchProfile(String name) { return fetchProfiles.get( name ); } public TypeHelper getTypeHelper() { return typeHelper; } static class SessionBuilderImpl implements SessionBuilderImplementor { private static final Logger log = CoreLogging.logger( SessionBuilderImpl.class ); private final SessionFactoryImpl sessionFactory; private SessionOwner sessionOwner; private Interceptor interceptor; private Connection connection; private ConnectionReleaseMode connectionReleaseMode; private boolean autoClose; private boolean autoJoinTransactions = true; private boolean flushBeforeCompletion; private String tenantIdentifier; private List listeners; SessionBuilderImpl(SessionFactoryImpl sessionFactory) { this.sessionFactory = sessionFactory; this.sessionOwner = null; final Settings settings = sessionFactory.settings; // set up default builder values... this.interceptor = sessionFactory.getInterceptor(); this.connectionReleaseMode = settings.getConnectionReleaseMode(); this.autoClose = settings.isAutoCloseSessionEnabled(); this.flushBeforeCompletion = settings.isFlushBeforeCompletionEnabled(); if ( sessionFactory.getCurrentTenantIdentifierResolver() != null ) { tenantIdentifier = sessionFactory.getCurrentTenantIdentifierResolver().resolveCurrentTenantIdentifier(); } listeners = settings.getBaselineSessionEventsListenerBuilder().buildBaselineList(); } protected TransactionCoordinatorImpl getTransactionCoordinator() { return null; } protected ActionQueue.TransactionCompletionProcesses getTransactionCompletionProcesses() { return null; } @Override public Session openSession() { log.tracef( "Opening Hibernate Session. tenant=%s, owner=%s", tenantIdentifier, sessionOwner ); final SessionImpl session = new SessionImpl( connection, sessionFactory, sessionOwner, getTransactionCoordinator(), getTransactionCompletionProcesses(), autoJoinTransactions, sessionFactory.settings.getRegionFactory().nextTimestamp(), interceptor, flushBeforeCompletion, autoClose, connectionReleaseMode, tenantIdentifier ); for ( SessionEventListener listener : listeners ) { session.getEventListenerManager().addListener( listener ); } return session; } @Override public SessionBuilder owner(SessionOwner sessionOwner) { this.sessionOwner = sessionOwner; return this; } @Override public SessionBuilder interceptor(Interceptor interceptor) { this.interceptor = interceptor; return this; } @Override public SessionBuilder noInterceptor() { this.interceptor = EmptyInterceptor.INSTANCE; return this; } @Override public SessionBuilder connection(Connection connection) { this.connection = connection; return this; } @Override public SessionBuilder connectionReleaseMode(ConnectionReleaseMode connectionReleaseMode) { this.connectionReleaseMode = connectionReleaseMode; return this; } @Override public SessionBuilder autoJoinTransactions(boolean autoJoinTransactions) { this.autoJoinTransactions = autoJoinTransactions; return this; } @Override public SessionBuilder autoClose(boolean autoClose) { this.autoClose = autoClose; return this; } @Override public SessionBuilder flushBeforeCompletion(boolean flushBeforeCompletion) { this.flushBeforeCompletion = flushBeforeCompletion; return this; } @Override public SessionBuilder tenantIdentifier(String tenantIdentifier) { this.tenantIdentifier = tenantIdentifier; return this; } @Override public SessionBuilder eventListeners(SessionEventListener... listeners) { Collections.addAll( this.listeners, listeners ); return this; } @Override public SessionBuilder clearEventListeners() { listeners.clear(); return this; } } public static class StatelessSessionBuilderImpl implements StatelessSessionBuilder { private final SessionFactoryImpl sessionFactory; private Connection connection; private String tenantIdentifier; public StatelessSessionBuilderImpl(SessionFactoryImpl sessionFactory) { this.sessionFactory = sessionFactory; if ( sessionFactory.getCurrentTenantIdentifierResolver() != null ) { tenantIdentifier = sessionFactory.getCurrentTenantIdentifierResolver().resolveCurrentTenantIdentifier(); } } @Override public StatelessSession openStatelessSession() { return new StatelessSessionImpl( connection, tenantIdentifier, sessionFactory, sessionFactory.settings.getRegionFactory().nextTimestamp() ); } @Override public StatelessSessionBuilder connection(Connection connection) { this.connection = connection; return this; } @Override public StatelessSessionBuilder tenantIdentifier(String tenantIdentifier) { this.tenantIdentifier = tenantIdentifier; return this; } } @Override public CustomEntityDirtinessStrategy getCustomEntityDirtinessStrategy() { return customEntityDirtinessStrategy; } @Override public CurrentTenantIdentifierResolver getCurrentTenantIdentifierResolver() { return currentTenantIdentifierResolver; } // Serialization handling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * Custom serialization hook defined by Java spec. Used when the factory is directly serialized * * @param out The stream into which the object is being serialized. * * @throws IOException Can be thrown by the stream */ private void writeObject(ObjectOutputStream out) throws IOException { LOG.debugf( "Serializing: %s", uuid ); out.defaultWriteObject(); LOG.trace( "Serialized" ); } /** * Custom serialization hook defined by Java spec. Used when the factory is directly deserialized * * @param in The stream from which the object is being deserialized. * * @throws IOException Can be thrown by the stream * @throws ClassNotFoundException Again, can be thrown by the stream */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { LOG.trace( "Deserializing" ); in.defaultReadObject(); LOG.debugf( "Deserialized: %s", uuid ); } /** * Custom serialization hook defined by Java spec. Used when the factory is directly deserialized. * Here we resolve the uuid/name read from the stream previously to resolve the SessionFactory * instance to use based on the registrations with the {@link SessionFactoryRegistry} * * @return The resolved factory to use. * * @throws InvalidObjectException Thrown if we could not resolve the factory by uuid/name. */ private Object readResolve() throws InvalidObjectException { LOG.trace( "Resolving serialized SessionFactory" ); return locateSessionFactoryOnDeserialization( uuid, name ); } private static SessionFactory locateSessionFactoryOnDeserialization(String uuid, String name) throws InvalidObjectException{ final SessionFactory uuidResult = SessionFactoryRegistry.INSTANCE.getSessionFactory( uuid ); if ( uuidResult != null ) { LOG.debugf( "Resolved SessionFactory by UUID [%s]", uuid ); return uuidResult; } // in case we were deserialized in a different JVM, look for an instance with the same name // (provided we were given a name) if ( name != null ) { final SessionFactory namedResult = SessionFactoryRegistry.INSTANCE.getNamedSessionFactory( name ); if ( namedResult != null ) { LOG.debugf( "Resolved SessionFactory by name [%s]", name ); return namedResult; } } throw new InvalidObjectException( "Could not find a SessionFactory [uuid=" + uuid + ",name=" + name + "]" ); } /** * Custom serialization hook used during Session serialization. * * @param oos The stream to which to write the factory * @throws IOException Indicates problems writing out the serial data stream */ void serialize(ObjectOutputStream oos) throws IOException { oos.writeUTF( uuid ); oos.writeBoolean( name != null ); if ( name != null ) { oos.writeUTF( name ); } } /** * Custom deserialization hook used during Session deserialization. * * @param ois The stream from which to "read" the factory * @return The deserialized factory * @throws IOException indicates problems reading back serial data stream * @throws ClassNotFoundException indicates problems reading back serial data stream */ static SessionFactoryImpl deserialize(ObjectInputStream ois) throws IOException, ClassNotFoundException { LOG.trace( "Deserializing SessionFactory from Session" ); final String uuid = ois.readUTF(); boolean isNamed = ois.readBoolean(); final String name = isNamed ? ois.readUTF() : null; return (SessionFactoryImpl) locateSessionFactoryOnDeserialization( uuid, name ); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy