FileDocCategorySizeDatePackage
DefaultLoadEventListener.javaAPI DocHibernate 3.2.519313Mon Nov 13 11:53:58 GMT 2006org.hibernate.event.def

DefaultLoadEventListener

public class DefaultLoadEventListener extends AbstractLockUpgradeEventListener implements org.hibernate.event.LoadEventListener
Defines the default load event listeners used by hibernate for loading entities in response to generated load events.
author
Steve Ebersole

Fields Summary
public static final Object
REMOVED_ENTITY_MARKER
public static final Object
INCONSISTENT_RTN_CLASS_MARKER
public static final org.hibernate.LockMode
DEFAULT_LOCK_MODE
private static final Log
log
Constructors Summary
Methods Summary
private java.lang.ObjectassembleCacheEntry(org.hibernate.cache.entry.CacheEntry entry, java.io.Serializable id, org.hibernate.persister.entity.EntityPersister persister, org.hibernate.event.LoadEvent event)

		
		final Object optionalObject = event.getInstanceToLoad();
		final EventSource session = event.getSession();
		final SessionFactoryImplementor factory = session.getFactory();
		
		if ( log.isTraceEnabled() ) {
			log.trace(
					"assembling entity from second-level cache: " +
					MessageHelper.infoString( persister, id, factory )
				);
		}

		EntityPersister subclassPersister = factory.getEntityPersister( entry.getSubclass() );
		Object result = optionalObject == null ? 
				session.instantiate( subclassPersister, id ) : optionalObject;
				
		// make it circular-reference safe
		TwoPhaseLoad.addUninitializedCachedEntity( 
				new EntityKey( id, subclassPersister, session.getEntityMode() ), 
				result, 
				subclassPersister, 
				LockMode.NONE, 
				entry.areLazyPropertiesUnfetched(),
				entry.getVersion(),
				session
			);

		Type[] types = subclassPersister.getPropertyTypes();
		Object[] values = entry.assemble( result, id, subclassPersister, session.getInterceptor(), session ); // intializes result by side-effect
		TypeFactory.deepCopy( 
				values, 
				types, 
				subclassPersister.getPropertyUpdateability(), 
				values, 
				session
			);
		
		Object version = Versioning.getVersion( values, subclassPersister );
		if ( log.isTraceEnabled() ) log.trace( "Cached Version: " + version );
		
		final PersistenceContext persistenceContext = session.getPersistenceContext();
		persistenceContext.addEntry( 
				result, 
				Status.MANAGED, 
				values, 
				null, 
				id, 
				version, 
				LockMode.NONE, 
				true, 
				subclassPersister, 
				false, 
				entry.areLazyPropertiesUnfetched() 
			);
		subclassPersister.afterInitialize( result, entry.areLazyPropertiesUnfetched(), session );
		persistenceContext.initializeNonLazyCollections();
		// upgrade the lock if necessary:
		//lock(result, lockMode);

		//PostLoad is needed for EJB3
		//TODO: reuse the PostLoadEvent...
		PostLoadEvent postLoadEvent = new PostLoadEvent(session).setEntity(result)
				.setId(id).setPersister(persister);
		PostLoadEventListener[] listeners = session.getListeners().getPostLoadEventListeners();
		for ( int i = 0; i < listeners.length; i++ ) {
			listeners[i].onPostLoad(postLoadEvent);
		}
		
		return result;
	
private java.lang.ObjectcreateProxyIfNecessary(org.hibernate.event.LoadEvent event, org.hibernate.persister.entity.EntityPersister persister, org.hibernate.engine.EntityKey keyToLoad, LoadEventListener.LoadType options, org.hibernate.engine.PersistenceContext persistenceContext)
Given that there is no pre-existing proxy. Check if the entity is already loaded. If it is, return the entity, otherwise create and return a proxy.

		Object existing = persistenceContext.getEntity( keyToLoad );
		if ( existing != null ) {
			// return existing object or initialized proxy (unless deleted)
			log.trace( "entity found in session cache" );
			if ( options.isCheckDeleted() ) {
				EntityEntry entry = persistenceContext.getEntry( existing );
				Status status = entry.getStatus();
				if ( status == Status.DELETED || status == Status.GONE ) {
					return null;
				}
			}
			return existing;
		}
		else {
			log.trace( "creating new proxy for entity" );
			// return new uninitialized proxy
			Object proxy = persister.createProxy( event.getEntityId(), event.getSession() );
			persistenceContext.getBatchFetchQueue().addBatchLoadableEntityKey(keyToLoad);
			persistenceContext.addProxy(keyToLoad, proxy);
			return proxy;
		}
	
protected java.lang.ObjectdoLoad(org.hibernate.event.LoadEvent event, org.hibernate.persister.entity.EntityPersister persister, org.hibernate.engine.EntityKey keyToLoad, LoadEventListener.LoadType options)
Coordinates the efforts to load a given entity. First, an attempt is made to load the entity from the session-level cache. If not found there, an attempt is made to locate it in second-level cache. Lastly, an attempt is made to load it directly from the datasource.

param
event The load event
param
persister The persister for the entity being requested for load
param
keyToLoad The EntityKey representing the entity to be loaded.
param
options The load options.
return
The loaded entity, or null.
throws
HibernateException

		
		if ( log.isTraceEnabled() ) {
			log.trace(
					"attempting to resolve: " + 
					MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
				);
		}

		Object entity = loadFromSessionCache( event, keyToLoad, options );
		if ( entity == REMOVED_ENTITY_MARKER ) {
			log.debug( "load request found matching entity in context, but it is scheduled for removal; returning null" );
			return null;
		}
		if ( entity == INCONSISTENT_RTN_CLASS_MARKER ) {
			log.debug( "load request found matching entity in context, but the matched entity was of an inconsistent return type; returning null" );
			return null;
		}
		if ( entity != null ) {
			if ( log.isTraceEnabled() ) {
				log.trace(
						"resolved object in session cache: " +
						MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory()  )
					);
			}
			return entity;
		}

		entity = loadFromSecondLevelCache(event, persister, options);
		if ( entity != null ) {
			if ( log.isTraceEnabled() ) {
				log.trace(
						"resolved object in second-level cache: " +
						MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
					);
			}
			return entity;
		}

		if ( log.isTraceEnabled() ) {
			log.trace(
					"object not resolved in any cache: " +
					MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
				);
		}

		return loadFromDatasource(event, persister, keyToLoad, options);
	
protected java.lang.Objectload(org.hibernate.event.LoadEvent event, org.hibernate.persister.entity.EntityPersister persister, org.hibernate.engine.EntityKey keyToLoad, LoadEventListener.LoadType options)
Perfoms the load of an entity.

return
The loaded entity.
throws
HibernateException

	
		if ( event.getInstanceToLoad() != null ) {
			if ( event.getSession().getPersistenceContext().getEntry( event.getInstanceToLoad() ) != null ) {
				throw new PersistentObjectException(
						"attempted to load into an instance that was already associated with the session: " +
						MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
					);
			}
			persister.setIdentifier( event.getInstanceToLoad(), event.getEntityId(), event.getSession().getEntityMode() );
		}

		Object entity = doLoad(event, persister, keyToLoad, options);
		
		boolean isOptionalInstance = event.getInstanceToLoad() != null;
		
		if ( !options.isAllowNulls() || isOptionalInstance ) {
			if ( entity == null ) {
				event.getSession().getFactory().getEntityNotFoundDelegate().handleEntityNotFound( event.getEntityClassName(), event.getEntityId() );
			}
		}

		if ( isOptionalInstance && entity != event.getInstanceToLoad() ) {
			throw new NonUniqueObjectException( event.getEntityId(), event.getEntityClassName() );
		}

		return entity;
	
protected java.lang.ObjectloadFromDatasource(org.hibernate.event.LoadEvent event, org.hibernate.persister.entity.EntityPersister persister, org.hibernate.engine.EntityKey keyToLoad, LoadEventListener.LoadType options)
Performs the process of loading an entity from the configured underlying datasource.

param
event The load event
param
persister The persister for the entity being requested for load
param
keyToLoad The EntityKey representing the entity to be loaded.
param
options The load options.
return
The object loaded from the datasource, or null if not found.
throws
HibernateException

		final SessionImplementor source = event.getSession();
		Object entity = persister.load(
				event.getEntityId(),
				event.getInstanceToLoad(),
				event.getLockMode(),
				source
		);

		if ( event.isAssociationFetch() && source.getFactory().getStatistics().isStatisticsEnabled() ) {
			source.getFactory().getStatisticsImplementor().fetchEntity( event.getEntityClassName() );
		}

		return entity;
	
protected java.lang.ObjectloadFromSecondLevelCache(org.hibernate.event.LoadEvent event, org.hibernate.persister.entity.EntityPersister persister, LoadEventListener.LoadType options)
Attempts to load the entity from the second-level cache.

param
event The load event
param
persister The persister for the entity being requested for load
param
options The load options.
return
The entity from the second-level cache, or null.
throws
HibernateException

		
		final SessionImplementor source = event.getSession();
		
		final boolean useCache = persister.hasCache() && 
			source.getCacheMode().isGetEnabled() && 
			event.getLockMode().lessThan(LockMode.READ);
		
		if (useCache) {
			
			final SessionFactoryImplementor factory = source.getFactory();
			
			final CacheKey ck = new CacheKey( 
					event.getEntityId(), 
					persister.getIdentifierType(), 
					persister.getRootEntityName(),
					source.getEntityMode(), 
					source.getFactory()
				);
			Object ce = persister.getCache()
				.get( ck, source.getTimestamp() );
			
			if ( factory.getStatistics().isStatisticsEnabled() ) {
				if (ce==null) {
					factory.getStatisticsImplementor().secondLevelCacheMiss( 
						persister.getCache().getRegionName() 
					);
				}
				else {
					factory.getStatisticsImplementor().secondLevelCacheHit( 
						persister.getCache().getRegionName() 
					);
				}
			}

			if ( ce != null ) {

				CacheEntry entry = (CacheEntry) persister.getCacheEntryStructure()
						.destructure(ce, factory);
			
				// Entity was found in second-level cache...
				return assembleCacheEntry(
						entry,
						event.getEntityId(),
						persister,
						event
					);
			}
		}
		
		return null;
	
protected java.lang.ObjectloadFromSessionCache(org.hibernate.event.LoadEvent event, org.hibernate.engine.EntityKey keyToLoad, LoadEventListener.LoadType options)
Attempts to locate the entity in the session-level cache.

If allowed to return nulls, then if the entity happens to be found in the session cache, we check the entity type for proper handling of entity hierarchies.

If checkDeleted was set to true, then if the entity is found in the session-level cache, it's current status within the session cache is checked to see if it has previously been scheduled for deletion.

param
event The load event
param
keyToLoad The EntityKey representing the entity to be loaded.
param
options The load options.
return
The entity from the session-level cache, or null.
throws
HibernateException Generally indicates problems applying a lock-mode.

		
		SessionImplementor session = event.getSession();
		Object old = session.getEntityUsingInterceptor( keyToLoad );

		if ( old != null ) {
			// this object was already loaded
			EntityEntry oldEntry = session.getPersistenceContext().getEntry( old );
			if ( options.isCheckDeleted() ) {
				Status status = oldEntry.getStatus();
				if ( status == Status.DELETED || status == Status.GONE ) {
					return REMOVED_ENTITY_MARKER;
				}
			}
			if ( options.isAllowNulls() ) {
				EntityPersister persister = event.getSession().getFactory().getEntityPersister( event.getEntityClassName() );
				if ( ! persister.isInstance( old, event.getSession().getEntityMode() ) ) {
					return INCONSISTENT_RTN_CLASS_MARKER;
				}
			}
			upgradeLock( old, oldEntry, event.getLockMode(), session );
		}

		return old;
	
protected java.lang.ObjectlockAndLoad(org.hibernate.event.LoadEvent event, org.hibernate.persister.entity.EntityPersister persister, org.hibernate.engine.EntityKey keyToLoad, LoadEventListener.LoadType options, org.hibernate.engine.SessionImplementor source)
If the class to be loaded has been configured with a cache, then lock given id in that cache and then perform the load.

return
The loaded entity
throws
HibernateException

		
		CacheConcurrencyStrategy.SoftLock lock = null;
		final CacheKey ck;
		if ( persister.hasCache() ) {
			ck = new CacheKey( 
					event.getEntityId(), 
					persister.getIdentifierType(), 
					persister.getRootEntityName(), 
					source.getEntityMode(), 
					source.getFactory() 
				);
			lock = persister.getCache().lock(ck, null );
		}
		else {
			ck = null;
		}

		Object entity;
		try {
			entity = load(event, persister, keyToLoad, options);
		}
		finally {
			if ( persister.hasCache() ) {
				persister.getCache().release(ck, lock );
			}
		}

		Object proxy = event.getSession().getPersistenceContext()
				.proxyFor( persister, keyToLoad, entity );
		
		return proxy;
	
public voidonLoad(org.hibernate.event.LoadEvent event, LoadEventListener.LoadType loadType)
Handle the given load event.

param
event The load event to be handled.
throws
HibernateException



	                	 
	        

		final SessionImplementor source = event.getSession();

		EntityPersister persister;
		if ( event.getInstanceToLoad() != null ) {
			persister = source.getEntityPersister( null, event.getInstanceToLoad() ); //the load() which takes an entity does not pass an entityName
			event.setEntityClassName( event.getInstanceToLoad().getClass().getName() );
		}
		else {
			persister = source.getFactory().getEntityPersister( event.getEntityClassName() );
		}

		if ( persister == null ) {
			throw new HibernateException( 
					"Unable to locate persister: " + 
					event.getEntityClassName() 
				);
		}

		if ( persister.getIdentifierType().isComponentType() && EntityMode.DOM4J == event.getSession().getEntityMode() ) {
			// skip this check for composite-ids relating to dom4j entity-mode;
			// alternatively, we could add a check to make sure the incoming id value is
			// an instance of Element...
		}
		else {
			Class idClass = persister.getIdentifierType().getReturnedClass();
			if ( idClass != null && ! idClass.isInstance( event.getEntityId() ) ) {
				throw new TypeMismatchException(
						"Provided id of the wrong type. Expected: " + idClass + ", got " + event.getEntityId().getClass()
				);
			}
		}

		EntityKey keyToLoad = new EntityKey( event.getEntityId(), persister, source.getEntityMode()  );

		try {
			if ( loadType.isNakedEntityReturned() ) {
				//do not return a proxy!
				//(this option indicates we are initializing a proxy)
				event.setResult( load(event, persister, keyToLoad, loadType) );
			}
			else {
				//return a proxy if appropriate
				if ( event.getLockMode() == LockMode.NONE ) {
					event.setResult( proxyOrLoad(event, persister, keyToLoad, loadType) );
				}
				else {
					event.setResult( lockAndLoad(event, persister, keyToLoad, loadType, source) );
				}
			}
		}
		catch(HibernateException e) {
			log.info("Error performing load command", e);
			throw e;
		}
	
protected java.lang.ObjectproxyOrLoad(org.hibernate.event.LoadEvent event, org.hibernate.persister.entity.EntityPersister persister, org.hibernate.engine.EntityKey keyToLoad, LoadEventListener.LoadType options)
Based on configured options, will either return a pre-existing proxy, generate a new proxy, or perform an actual load.

return
The result of the proxy/load operation.
throws
HibernateException

		
		if ( log.isTraceEnabled() ) {
			log.trace(
					"loading entity: " + 
					MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
				);
		}

		if ( !persister.hasProxy() ) {
			// this class has no proxies (so do a shortcut)
			return load(event, persister, keyToLoad, options);
		}
		else {
			final PersistenceContext persistenceContext = event.getSession().getPersistenceContext();

			// look for a proxy
			Object proxy = persistenceContext.getProxy(keyToLoad);
			if ( proxy != null ) {
				return returnNarrowedProxy( event, persister, keyToLoad, options, persistenceContext, proxy );
			}
			else {
				if ( options.isAllowProxyCreation() ) {
					return createProxyIfNecessary( event, persister, keyToLoad, options, persistenceContext );
				}
				else {
					// return a newly loaded object
					return load(event, persister, keyToLoad, options);
				}
			}
			
		}
	
private java.lang.ObjectreturnNarrowedProxy(org.hibernate.event.LoadEvent event, org.hibernate.persister.entity.EntityPersister persister, org.hibernate.engine.EntityKey keyToLoad, LoadEventListener.LoadType options, org.hibernate.engine.PersistenceContext persistenceContext, java.lang.Object proxy)
Given that there is a pre-existing proxy. Initialize it if necessary; narrow if necessary.

		log.trace("entity proxy found in session cache");
		LazyInitializer li = ( (HibernateProxy) proxy ).getHibernateLazyInitializer();
		if ( li.isUnwrap() ) {
			return li.getImplementation();
		}
		Object impl = null;
		if ( !options.isAllowProxyCreation() ) {
			impl = load( event, persister, keyToLoad, options );
			if ( impl == null ) {
				event.getSession().getFactory().getEntityNotFoundDelegate().handleEntityNotFound( persister.getEntityName(), keyToLoad.getIdentifier());
			}
		}
		return persistenceContext.narrowProxy( proxy, persister, keyToLoad, impl );