defaultloadeventlistener.java

来自「好东西,hibernate-3.2.0,他是一开元的树杖hibernate-3.」· Java 代码 · 共 584 行 · 第 1/2 页

JAVA
584
字号
//$Id: DefaultLoadEventListener.java 9995 2006-06-06 20:51:29Z steve.ebersole@jboss.com $
package org.hibernate.event.def;

import java.io.Serializable;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.NonUniqueObjectException;
import org.hibernate.ObjectDeletedException;
import org.hibernate.PersistentObjectException;
import org.hibernate.TypeMismatchException;
import org.hibernate.EntityMode;
import org.hibernate.cache.CacheConcurrencyStrategy;
import org.hibernate.cache.CacheKey;
import org.hibernate.cache.entry.CacheEntry;
import org.hibernate.engine.EntityEntry;
import org.hibernate.engine.EntityKey;
import org.hibernate.engine.PersistenceContext;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.Status;
import org.hibernate.engine.TwoPhaseLoad;
import org.hibernate.engine.Versioning;
import org.hibernate.event.EventSource;
import org.hibernate.event.LoadEvent;
import org.hibernate.event.LoadEventListener;
import org.hibernate.event.PostLoadEvent;
import org.hibernate.event.PostLoadEventListener;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.type.Type;
import org.hibernate.type.TypeFactory;

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

	private static final Log log = LogFactory.getLog(DefaultLoadEventListener.class);

	public static final LockMode DEFAULT_LOCK_MODE = LockMode.NONE;

	/** 
	 * Handle the given load event.
	 *
	 * @param event The load event to be handled.
	 * @throws HibernateException
	 */
	public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType) 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;
		}
	}

	/**
	 * Perfoms the load of an entity.
	 *
	 * @return The loaded entity.
	 * @throws HibernateException
	 */
	protected Object load(
		final LoadEvent event, 
		final EntityPersister persister, 
		final EntityKey keyToLoad, 
		final LoadEventListener.LoadType options)
	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;
	}

	/** 
	 * 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
	 */
	protected Object proxyOrLoad(
		final LoadEvent event, 
		final EntityPersister persister,
		final EntityKey keyToLoad, 
		final LoadEventListener.LoadType options) 
	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);
				}
			}
			
		}
	}

	/**
	 * Given that there is a pre-existing proxy.
	 * Initialize it if necessary; narrow if necessary.
	 */
	private Object returnNarrowedProxy(
			final LoadEvent event, 
			final EntityPersister persister, 
			final EntityKey keyToLoad, 
			final LoadEventListener.LoadType options, 
			final PersistenceContext persistenceContext, 
			final Object proxy
	) {
		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 );
	}
	
	/**
	 * 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.
	 */
	private Object createProxyIfNecessary(
			final LoadEvent event, 
			final EntityPersister persister, 
			final EntityKey keyToLoad, 
			final LoadEventListener.LoadType options,
			final PersistenceContext persistenceContext
	) {
		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;
		}
	}

	/** 
	 * 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
	 */
	protected Object lockAndLoad(
		final LoadEvent event, 
		final EntityPersister persister,
		final EntityKey keyToLoad, 
		final LoadEventListener.LoadType options,
		final SessionImplementor source) 
	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;
		}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?