Save This Page
Home » Hibernate-3.3.2.GA » org.hibernate » engine » [javadoc | source]
    1   /*
    2    * Hibernate, Relational Persistence for Idiomatic Java
    3    *
    4    * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
    5    * indicated by the @author tags or express copyright attribution
    6    * statements applied by the authors.  All third-party contributions are
    7    * distributed under license by Red Hat Middleware LLC.
    8    *
    9    * This copyrighted material is made available to anyone wishing to use, modify,
   10    * copy, or redistribute it subject to the terms and conditions of the GNU
   11    * Lesser General Public License, as published by the Free Software Foundation.
   12    *
   13    * This program is distributed in the hope that it will be useful,
   14    * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   15    * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
   16    * for more details.
   17    *
   18    * You should have received a copy of the GNU Lesser General Public License
   19    * along with this distribution; if not, write to:
   20    * Free Software Foundation, Inc.
   21    * 51 Franklin Street, Fifth Floor
   22    * Boston, MA  02110-1301  USA
   23    *
   24    */
   25   package org.hibernate.engine;
   26   
   27   import java.io.Serializable;
   28   
   29   import org.slf4j.Logger;
   30   import org.slf4j.LoggerFactory;
   31   import org.hibernate.AssertionFailure;
   32   import org.hibernate.CacheMode;
   33   import org.hibernate.HibernateException;
   34   import org.hibernate.LockMode;
   35   import org.hibernate.cache.CacheKey;
   36   import org.hibernate.cache.entry.CacheEntry;
   37   import org.hibernate.event.PostLoadEvent;
   38   import org.hibernate.event.PostLoadEventListener;
   39   import org.hibernate.event.PreLoadEvent;
   40   import org.hibernate.event.PreLoadEventListener;
   41   import org.hibernate.intercept.LazyPropertyInitializer;
   42   import org.hibernate.persister.entity.EntityPersister;
   43   import org.hibernate.pretty.MessageHelper;
   44   import org.hibernate.property.BackrefPropertyAccessor;
   45   import org.hibernate.type.Type;
   46   import org.hibernate.type.TypeFactory;
   47   
   48   /**
   49    * Functionality relating to Hibernate's two-phase loading process,
   50    * that may be reused by persisters that do not use the Loader
   51    * framework
   52    * 
   53    * @author Gavin King
   54    */
   55   public final class TwoPhaseLoad {
   56   
   57   	private static final Logger log = LoggerFactory.getLogger(TwoPhaseLoad.class);
   58   	
   59   	private TwoPhaseLoad() {}
   60   
   61   	/**
   62   	 * Register the "hydrated" state of an entity instance, after the first step of 2-phase loading.
   63   	 * 
   64   	 * Add the "hydrated state" (an array) of an uninitialized entity to the session. We don't try
   65   	 * to resolve any associations yet, because there might be other entities waiting to be
   66   	 * read from the JDBC result set we are currently processing
   67   	 */
   68   	public static void postHydrate(
   69   		final EntityPersister persister, 
   70   		final Serializable id, 
   71   		final Object[] values, 
   72   		final Object rowId,
   73   		final Object object, 
   74   		final LockMode lockMode,
   75   		final boolean lazyPropertiesAreUnfetched, 
   76   		final SessionImplementor session) 
   77   	throws HibernateException {
   78   		
   79   		Object version = Versioning.getVersion(values, persister);
   80   		session.getPersistenceContext().addEntry( 
   81   				object, 
   82   				Status.LOADING,
   83   				values, 
   84   				rowId, 
   85   				id, 
   86   				version, 
   87   				lockMode, 
   88   				true, 
   89   				persister, 
   90   				false, 
   91   				lazyPropertiesAreUnfetched 
   92   			);
   93   	
   94   		if ( log.isTraceEnabled() && version!=null ) {
   95   			String versionStr = persister.isVersioned()
   96   					? persister.getVersionType().toLoggableString( version, session.getFactory() )
   97   			        : "null";
   98   			log.trace( "Version: " + versionStr );
   99   		}
  100   	
  101   	}
  102   
  103   	/**
  104   	 * Perform the second step of 2-phase load. Fully initialize the entity 
  105   	 * instance.
  106   	 *
  107   	 * After processing a JDBC result set, we "resolve" all the associations
  108   	 * between the entities which were instantiated and had their state
  109   	 * "hydrated" into an array
  110   	 */
  111   	public static void initializeEntity(
  112   			final Object entity, 
  113   			final boolean readOnly,
  114   			final SessionImplementor session,
  115   			final PreLoadEvent preLoadEvent,
  116   			final PostLoadEvent postLoadEvent) throws HibernateException {
  117   		
  118   		//TODO: Should this be an InitializeEntityEventListener??? (watch out for performance!)
  119   	
  120   		final PersistenceContext persistenceContext = session.getPersistenceContext();
  121   		EntityEntry entityEntry = persistenceContext.getEntry(entity);
  122   		if ( entityEntry == null ) {
  123   			throw new AssertionFailure( "possible non-threadsafe access to the session" );
  124   		}
  125   		EntityPersister persister = entityEntry.getPersister();
  126   		Serializable id = entityEntry.getId();
  127   		Object[] hydratedState = entityEntry.getLoadedState();
  128   	
  129   		if ( log.isDebugEnabled() )
  130   			log.debug(
  131   					"resolving associations for " +
  132   					MessageHelper.infoString(persister, id, session.getFactory())
  133   				);
  134   	
  135   		Type[] types = persister.getPropertyTypes();
  136   		for ( int i = 0; i < hydratedState.length; i++ ) {
  137   			final Object value = hydratedState[i];
  138   			if ( value!=LazyPropertyInitializer.UNFETCHED_PROPERTY && value!=BackrefPropertyAccessor.UNKNOWN ) {
  139   				hydratedState[i] = types[i].resolve( value, session, entity );
  140   			}
  141   		}
  142   	
  143   		//Must occur after resolving identifiers!
  144   		if ( session.isEventSource() ) {
  145   			preLoadEvent.setEntity(entity).setState(hydratedState).setId(id).setPersister(persister);
  146   			PreLoadEventListener[] listeners = session.getListeners().getPreLoadEventListeners();
  147   			for ( int i = 0; i < listeners.length; i++ ) {
  148   				listeners[i].onPreLoad(preLoadEvent);
  149   			}
  150   		}
  151   	
  152   		persister.setPropertyValues( entity, hydratedState, session.getEntityMode() );
  153   	
  154   		final SessionFactoryImplementor factory = session.getFactory();
  155   		if ( persister.hasCache() && session.getCacheMode().isPutEnabled() ) {
  156   			
  157   			if ( log.isDebugEnabled() )
  158   				log.debug(
  159   						"adding entity to second-level cache: " +
  160   						MessageHelper.infoString( persister, id, session.getFactory() )
  161   					);
  162   
  163   			Object version = Versioning.getVersion(hydratedState, persister);
  164   			CacheEntry entry = new CacheEntry(
  165   					hydratedState, 
  166   					persister, 
  167   					entityEntry.isLoadedWithLazyPropertiesUnfetched(), 
  168   					version, 
  169   					session, 
  170   					entity
  171   			);
  172   			CacheKey cacheKey = new CacheKey( 
  173   					id, 
  174   					persister.getIdentifierType(), 
  175   					persister.getRootEntityName(), 
  176   					session.getEntityMode(), 
  177   					session.getFactory() 
  178   			);
  179   			boolean put = persister.getCacheAccessStrategy().putFromLoad(
  180   					cacheKey,
  181   					persister.getCacheEntryStructure().structure( entry ),
  182   					session.getTimestamp(),
  183   					version,
  184   					useMinimalPuts( session, entityEntry )
  185   			);
  186   
  187   			if ( put && factory.getStatistics().isStatisticsEnabled() ) {
  188   				factory.getStatisticsImplementor().secondLevelCachePut( persister.getCacheAccessStrategy().getRegion().getName() );
  189   			}
  190   		}
  191   	
  192   		if ( readOnly || !persister.isMutable() ) {
  193   			//no need to take a snapshot - this is a 
  194   			//performance optimization, but not really
  195   			//important, except for entities with huge 
  196   			//mutable property values
  197   			persistenceContext.setEntryStatus(entityEntry, Status.READ_ONLY);
  198   		}
  199   		else {
  200   			//take a snapshot
  201   			TypeFactory.deepCopy( 
  202   					hydratedState, 
  203   					persister.getPropertyTypes(), 
  204   					persister.getPropertyUpdateability(), 
  205   					hydratedState,  //after setting values to object, entityMode
  206   					session
  207   				);
  208   			persistenceContext.setEntryStatus(entityEntry, Status.MANAGED);
  209   		}
  210   		
  211   		persister.afterInitialize(
  212   				entity, 
  213   				entityEntry.isLoadedWithLazyPropertiesUnfetched(), 
  214   				session
  215   			);
  216   		
  217   		if ( session.isEventSource() ) {
  218   			postLoadEvent.setEntity(entity).setId(id).setPersister(persister);
  219   			PostLoadEventListener[] listeners = session.getListeners().getPostLoadEventListeners();
  220   			for ( int i = 0; i < listeners.length; i++ ) {
  221   				listeners[i].onPostLoad(postLoadEvent);
  222   			}
  223   		}
  224   		
  225   		if ( log.isDebugEnabled() )
  226   			log.debug(
  227   					"done materializing entity " +
  228   					MessageHelper.infoString( persister, id, session.getFactory() )
  229   				);
  230   		
  231   		if ( factory.getStatistics().isStatisticsEnabled() ) {
  232   			factory.getStatisticsImplementor().loadEntity( persister.getEntityName() );
  233   		}
  234   	
  235   	}
  236   
  237   	private static boolean useMinimalPuts(SessionImplementor session, EntityEntry entityEntry) {
  238   		return ( session.getFactory().getSettings().isMinimalPutsEnabled() && 
  239   						session.getCacheMode()!=CacheMode.REFRESH ) ||
  240   				( entityEntry.getPersister().hasLazyProperties() && 
  241   						entityEntry.isLoadedWithLazyPropertiesUnfetched() && 
  242   						entityEntry.getPersister().isLazyPropertiesCacheable() );
  243   	}
  244   
  245   	/**
  246   	 * Add an uninitialized instance of an entity class, as a placeholder to ensure object 
  247   	 * identity. Must be called before <tt>postHydrate()</tt>.
  248   	 *
  249   	 * Create a "temporary" entry for a newly instantiated entity. The entity is uninitialized,
  250   	 * but we need the mapping from id to instance in order to guarantee uniqueness.
  251   	 */
  252   	public static void addUninitializedEntity(
  253   			final EntityKey key, 
  254   			final Object object, 
  255   			final EntityPersister persister, 
  256   			final LockMode lockMode,
  257   			final boolean lazyPropertiesAreUnfetched, 
  258   			final SessionImplementor session
  259   	) {
  260   		session.getPersistenceContext().addEntity(
  261   				object, 
  262   				Status.LOADING, 
  263   				null, 
  264   				key, 
  265   				null, 
  266   				lockMode, 
  267   				true, 
  268   				persister, 
  269   				false, 
  270   				lazyPropertiesAreUnfetched
  271   			);
  272   	}
  273   
  274   	public static void addUninitializedCachedEntity(
  275   			final EntityKey key, 
  276   			final Object object, 
  277   			final EntityPersister persister, 
  278   			final LockMode lockMode,
  279   			final boolean lazyPropertiesAreUnfetched,
  280   			final Object version,
  281   			final SessionImplementor session
  282   	) {
  283   		session.getPersistenceContext().addEntity(
  284   				object, 
  285   				Status.LOADING, 
  286   				null, 
  287   				key, 
  288   				version, 
  289   				lockMode, 
  290   				true, 
  291   				persister, 
  292   				false, 
  293   				lazyPropertiesAreUnfetched
  294   			);
  295   	}
  296   }

Save This Page
Home » Hibernate-3.3.2.GA » org.hibernate » engine » [javadoc | source]