[hibernate-commits] Hibernate SVN: r11301 - in branches/Branch_3_2/Hibernate3/src/org/hibernate: engine and 3 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Mon Mar 19 16:43:47 EDT 2007


Author: steve.ebersole at jboss.com
Date: 2007-03-19 16:43:46 -0400 (Mon, 19 Mar 2007)
New Revision: 11301

Added:
   branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/loading/
   branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/loading/CollectionLoadContext.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/loading/EntityLoadContext.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/loading/LoadContexts.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/loading/LoadingCollectionEntry.java
Removed:
   branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/CollectionLoadContext.java
Modified:
   branches/Branch_3_2/Hibernate3/src/org/hibernate/collection/AbstractPersistentCollection.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/PersistenceContext.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/StatefulPersistenceContext.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/loader/Loader.java
   branches/Branch_3_2/Hibernate3/src/org/hibernate/type/CollectionType.java
Log:
HHH-2495 : ResultSet processing context

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/collection/AbstractPersistentCollection.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/collection/AbstractPersistentCollection.java	2007-03-19 19:48:21 UTC (rev 11300)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/collection/AbstractPersistentCollection.java	2007-03-19 20:43:46 UTC (rev 11301)
@@ -538,7 +538,7 @@
 	/**
 	 * Get the current session
 	 */
-	protected final SessionImplementor getSession() {
+	public final SessionImplementor getSession() {
 		return session;
 	}
 

Deleted: branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/CollectionLoadContext.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/CollectionLoadContext.java	2007-03-19 19:48:21 UTC (rev 11300)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/CollectionLoadContext.java	2007-03-19 20:43:46 UTC (rev 11301)
@@ -1,340 +0,0 @@
-//$Id$
-package org.hibernate.engine;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.hibernate.CacheMode;
-import org.hibernate.EntityMode;
-import org.hibernate.HibernateException;
-import org.hibernate.cache.CacheKey;
-import org.hibernate.cache.entry.CollectionCacheEntry;
-import org.hibernate.collection.PersistentCollection;
-import org.hibernate.persister.collection.CollectionPersister;
-import org.hibernate.pretty.MessageHelper;
-
-/**
- * Represents the state of collections currently being loaded. Eventually, I
- * would like to have multiple instances of this per session - one per JDBC
- * result set, instead of the resultSetId being passed.
- * @author Gavin King
- */
-public class CollectionLoadContext {
-	
-	private static final Log log = LogFactory.getLog(CollectionLoadContext.class);
-
-	// The collections we are currently loading
-	private final Map loadingCollections = new HashMap(8);
-	private final PersistenceContext context;
-	
-	public CollectionLoadContext(PersistenceContext context) {
-		this.context = context;
-	}
-	
-	private static final class LoadingCollectionEntry {
-
-		final PersistentCollection collection;
-		final Serializable key;
-		final Object resultSetId;
-		final CollectionPersister persister;
-
-		LoadingCollectionEntry(
-				final PersistentCollection collection, 
-				final Serializable key, 
-				final CollectionPersister persister, 
-				final Object resultSetId
-		) {
-			this.collection = collection;
-			this.key = key;
-			this.persister = persister;
-			this.resultSetId = resultSetId;
-		}
-	}
-
-	/**
-	 * Retrieve a collection that is in the process of being loaded, instantiating
-	 * a new collection if there is nothing for the given id, or returning null
-	 * if the collection with the given id is already fully loaded in the session
-	 */
-	public PersistentCollection getLoadingCollection(
-			final CollectionPersister persister, 
-			final Serializable key, 
-			final Object resultSetId, 
-			final EntityMode em)
-	throws HibernateException {
-		CollectionKey ckey = new CollectionKey(persister, key, em);
-		LoadingCollectionEntry lce = getLoadingCollectionEntry(ckey);
-		if ( lce == null ) {
-			//look for existing collection
-			PersistentCollection collection = context.getCollection(ckey);
-			if ( collection != null ) {
-				if ( collection.wasInitialized() ) {
-					log.trace( "collection already initialized: ignoring" );
-					return null; //ignore this row of results! Note the early exit
-				}
-				else {
-					//initialize this collection
-					log.trace( "uninitialized collection: initializing" );
-				}
-			}
-			else {
-				Object entity = context.getCollectionOwner(key, persister);
-				final boolean newlySavedEntity = entity != null && 
-						context.getEntry(entity).getStatus() != Status.LOADING && 
-						em!=EntityMode.DOM4J;
-				if ( newlySavedEntity ) {
-					//important, to account for newly saved entities in query
-					//TODO: some kind of check for new status...
-					log.trace( "owning entity already loaded: ignoring" );
-					return null;
-				}
-				else {
-					//create one
-					log.trace( "new collection: instantiating" );
-					collection = persister.getCollectionType()
-							.instantiate( context.getSession(), persister, key );
-				}
-			}
-			collection.beforeInitialize( persister, -1 );
-			collection.beginRead();
-			addLoadingCollectionEntry(ckey, collection, persister, resultSetId);
-			return collection;
-		}
-		else {
-			if ( lce.resultSetId == resultSetId ) {
-				log.trace( "reading row" );
-				return lce.collection;
-			}
-			else {
-				// ignore this row, the collection is in process of
-				// being loaded somewhere further "up" the stack
-				log.trace( "collection is already being initialized: ignoring row" );
-				return null;
-			}
-		}
-	}
-
-	/**
-	 * Retrieve a collection that is in the process of being loaded, returning null
-	 * if there is no loading collection with the given id
-	 */
-	public PersistentCollection getLoadingCollection(CollectionPersister persister, Serializable id, EntityMode em) {
-		LoadingCollectionEntry lce = getLoadingCollectionEntry( new CollectionKey(persister, id, em) );
-		if ( lce != null ) {
-			if ( log.isTraceEnabled() ) {
-				log.trace( 
-						"returning loading collection:" + 
-						MessageHelper.collectionInfoString(persister, id, context.getSession().getFactory()) 
-					);
-			}		
-			return lce.collection;
-		}
-		else {
-			if ( log.isTraceEnabled() ) {
-				log.trace( 
-						"creating collection wrapper:" + 
-						MessageHelper.collectionInfoString(persister, id, context.getSession().getFactory()) 
-					);
-			}
-			return null;
-		}
-	}
-
-	/**
-	 * Create a new loading collection entry
-	 */
-	private void addLoadingCollectionEntry(
-			final CollectionKey collectionKey, 
-			final PersistentCollection collection, 
-			final CollectionPersister persister, 
-			final Object resultSetId 
-	) {
-		loadingCollections.put(
-				collectionKey,
-				new LoadingCollectionEntry(
-						collection,
-						collectionKey.getKey(),
-						persister,
-						resultSetId
-					)
-			);
-	}
-
-	/**
-	 * get an existing new loading collection entry
-	 */
-	private LoadingCollectionEntry getLoadingCollectionEntry(CollectionKey collectionKey) {
-		return ( LoadingCollectionEntry ) loadingCollections.get( collectionKey );
-	}
-
-	/**
-	 * After we have finished processing a result set, a particular loading collection that
-	 * we are done.
-	 */
-	private void endLoadingCollection(LoadingCollectionEntry lce, CollectionPersister persister, EntityMode em) {
-
-		boolean hasNoQueuedAdds = lce.collection.endRead(); //warning: can cause a recursive query! (proxy initialization)
-
-		if ( persister.getCollectionType().hasHolder(em) ) {
-			context.addCollectionHolder(lce.collection);
-		}
-		
-		CollectionEntry ce = context.getCollectionEntry(lce.collection);
-		if ( ce==null ) {
-			ce = context.addInitializedCollection(persister, lce.collection, lce.key);
-		}
-		else {
-			ce.postInitialize(lce.collection);
-		}
-
-		final SessionImplementor session = context.getSession();
-		
-		boolean addToCache = hasNoQueuedAdds && // there were no queued additions
-				persister.hasCache() &&             // and the role has a cache
-				session.getCacheMode().isPutEnabled() &&
-				!ce.isDoremove();                   // and this is not a forced initialization during flush
-		if (addToCache) addCollectionToCache(lce, persister);
-
-		if ( log.isDebugEnabled() ) {
-			log.debug(
-					"collection fully initialized: " +
-					MessageHelper.collectionInfoString(persister, lce.key, context.getSession().getFactory())
-				);
-		}
-
-		if ( session.getFactory().getStatistics().isStatisticsEnabled() ) {
-			session.getFactory().getStatisticsImplementor().loadCollection(
-					persister.getRole()
-				);
-		}
-
-	}
-	/**
-	 * Finish the process of loading collections for a particular result set
-	 */
-	public void endLoadingCollections(CollectionPersister persister, Object resultSetId, SessionImplementor session)
-	throws HibernateException {
-
-		// scan the loading collections for collections from this result set
-		// put them in a new temp collection so that we are safe from concurrent
-		// modification when the call to endRead() causes a proxy to be
-		// initialized
-		List resultSetCollections = null; //TODO: make this the resultSetId?
-		Iterator iter = loadingCollections.values().iterator();
-		while ( iter.hasNext() ) {
-			LoadingCollectionEntry lce = (LoadingCollectionEntry) iter.next();
-			if ( lce.resultSetId == resultSetId && lce.persister==persister) {
-				if ( resultSetCollections == null ) {
-					resultSetCollections = new ArrayList();
-				}
-				resultSetCollections.add(lce);
-				if ( lce.collection.getOwner()==null ) {
-					session.getPersistenceContext()
-							.addUnownedCollection( 
-									new CollectionKey( persister, lce.key, session.getEntityMode() ), 
-									lce.collection
-								);
-				}
-				iter.remove();
-			}
-		}
-
-		endLoadingCollections( persister, resultSetCollections, session.getEntityMode() );
-	}
-	
-	/**
-	 * After we have finished processing a result set, notify the loading collections that
-	 * we are done.
-	 */
-	private void endLoadingCollections(CollectionPersister persister, List resultSetCollections, EntityMode em)
-	throws HibernateException {
-
-		final int count = (resultSetCollections == null) ? 0 : resultSetCollections.size();
-
-		if ( log.isDebugEnabled() ) {
-			log.debug( count + " collections were found in result set for role: " + persister.getRole() );
-		}
-
-		//now finish them
-		for ( int i = 0; i < count; i++ ) {
-			LoadingCollectionEntry lce = (LoadingCollectionEntry) resultSetCollections.get(i);
-			endLoadingCollection(lce, persister, em);
-		}
-
-		if ( log.isDebugEnabled() ) {
-			log.debug( count + " collections initialized for role: " + persister.getRole() );
-		}
-	}
-
-	/**
-	 * Add a collection to the second-level cache
-	 */
-	private void addCollectionToCache(LoadingCollectionEntry lce, CollectionPersister persister) {
-
-		if ( log.isDebugEnabled() ) {
-			log.debug(
-					"Caching collection: " +
-					MessageHelper.collectionInfoString( persister, lce.key, context.getSession().getFactory() )
-				);
-		}
-
-		final SessionImplementor session = context.getSession();
-		final SessionFactoryImplementor factory = session.getFactory();
-
-		if ( !session.getEnabledFilters().isEmpty() && persister.isAffectedByEnabledFilters( session ) ) {
-			// some filters affecting the collection are enabled on the session, so do not do the put into the cache.
-			log.debug( "Refusing to add to cache due to enabled filters" );
-			// todo : add the notion of enabled filters to the CacheKey to differentiate filtered collections from non-filtered;
-			//      but CacheKey is currently used for both collections and entities; would ideally need to define two seperate ones;
-			//      currently this works in conjuction with the check on
-			//      DefaultInitializeCollectionEventHandler.initializeCollectionFromCache() (which makes sure to not read from
-			//      cache with enabled filters).
-			return; // EARLY EXIT!!!!!
-		}
-
-		final Comparator versionComparator;
-		final Object version;
-		if ( persister.isVersioned() ) {
-			versionComparator = persister.getOwnerEntityPersister().getVersionType().getComparator();
-			version = context.getEntry( context.getCollectionOwner(lce.key, persister) ).getVersion();
-		}
-		else {
-			version = null;
-			versionComparator = null;
-		}
-		
-		CollectionCacheEntry entry = new CollectionCacheEntry(lce.collection, persister);
-
-		CacheKey cacheKey = new CacheKey( 
-				lce.key, 
-				persister.getKeyType(), 
-				persister.getRole(), 
-				session.getEntityMode(), 
-				session.getFactory() 
-			);
-		boolean put = persister.getCache().put(
-				cacheKey,
-				persister.getCacheEntryStructure().structure(entry),
-				session.getTimestamp(),
-				version,
-				versionComparator,
-				factory.getSettings().isMinimalPutsEnabled() && 
-						session.getCacheMode()!=CacheMode.REFRESH
-			);
-
-		if ( put && factory.getStatistics().isStatisticsEnabled() ) {
-			factory.getStatisticsImplementor().secondLevelCachePut(
-					persister.getCache().getRegionName()
-				);
-		}
-	}
-
-
-}

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/PersistenceContext.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/PersistenceContext.java	2007-03-19 19:48:21 UTC (rev 11300)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/PersistenceContext.java	2007-03-19 20:43:46 UTC (rev 11301)
@@ -8,6 +8,7 @@
 import org.hibernate.HibernateException;
 import org.hibernate.LockMode;
 import org.hibernate.MappingException;
+import org.hibernate.engine.loading.LoadContexts;
 import org.hibernate.collection.PersistentCollection;
 import org.hibernate.persister.collection.CollectionPersister;
 import org.hibernate.persister.entity.EntityPersister;
@@ -21,16 +22,20 @@
 public interface PersistenceContext {
 	
 	public boolean isStateless();
-	
+
 	/**
-	 * Get the session
+	 * Get the session to which this persistence context is bound.
+	 *
+	 * @return The session.
 	 */
 	public SessionImplementor getSession();
-	
+
 	/**
-	 * Get the context for collection loading
+	 * Retrieve this persistence context's managed load context.
+	 *
+	 * @return The load context
 	 */
-	public CollectionLoadContext getCollectionLoadContext();
+	public LoadContexts getLoadContexts();
 
 	/**
 	 * Add a collection which has no owner loaded

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/StatefulPersistenceContext.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/StatefulPersistenceContext.java	2007-03-19 19:48:21 UTC (rev 11300)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/StatefulPersistenceContext.java	2007-03-19 20:43:46 UTC (rev 11301)
@@ -24,6 +24,7 @@
 import org.hibernate.NonUniqueObjectException;
 import org.hibernate.PersistentObjectException;
 import org.hibernate.TransientObjectException;
+import org.hibernate.engine.loading.LoadContexts;
 import org.hibernate.pretty.MessageHelper;
 import org.hibernate.collection.PersistentCollection;
 import org.hibernate.persister.collection.CollectionPersister;
@@ -101,7 +102,7 @@
 	
 	private boolean hasNonReadOnlyEntities = false;
 	
-	private CollectionLoadContext collectionLoadContext;
+	private LoadContexts loadContexts;
 	private BatchFetchQueue batchFetchQueue;
 
 
@@ -142,11 +143,11 @@
 		return session;
 	}
 	
-	public CollectionLoadContext getCollectionLoadContext() {
-		if (collectionLoadContext==null) {
-			collectionLoadContext = new CollectionLoadContext(this);
+	public LoadContexts getLoadContexts() {
+		if ( loadContexts == null ) {
+			loadContexts = new LoadContexts( this );
 		}
-		return collectionLoadContext;
+		return loadContexts;
 	}
 	
 	public void addUnownedCollection(CollectionKey key, PersistentCollection collection) {

Added: branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/loading/CollectionLoadContext.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/loading/CollectionLoadContext.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/loading/CollectionLoadContext.java	2007-03-19 20:43:46 UTC (rev 11301)
@@ -0,0 +1,332 @@
+package org.hibernate.engine.loading;
+
+import java.sql.ResultSet;
+import java.io.Serializable;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.Comparator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.EntityMode;
+import org.hibernate.CacheMode;
+import org.hibernate.cache.entry.CollectionCacheEntry;
+import org.hibernate.cache.CacheKey;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.engine.CollectionKey;
+import org.hibernate.engine.Status;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.CollectionEntry;
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * Represents state associated with the processing of a given {@link ResultSet}
+ * in regards to loading collections.
+ * <p/>
+ * Another implementation option to consider is to not expose {@link ResultSet}s
+ * directly (in the JDBC redesign) but to always "wrap" them and apply a
+ * [series of] context[s] to that wrapper.
+ *
+ * @author Steve Ebersole
+ */
+public class CollectionLoadContext {
+	private static final Log log = LogFactory.getLog( CollectionLoadContext.class );
+
+	private final LoadContexts loadContexts;
+	private final ResultSet resultSet;
+	private final Map loadingCollections = new HashMap( 8 );
+
+	/**
+	 * Creates a collection load context for the given result set.
+	 *
+	 * @param loadContexts Callback to other collection load contexts.
+	 * @param resultSet The result set this is "wrapping".
+	 */
+	public CollectionLoadContext(LoadContexts loadContexts, ResultSet resultSet) {
+		this.loadContexts = loadContexts;
+		this.resultSet = resultSet;
+	}
+
+	public ResultSet getResultSet() {
+		return resultSet;
+	}
+
+	public LoadContexts getLoadContext() {
+		return loadContexts;
+	}
+
+	/**
+	 * Retrieve the collection that is being loaded as part of processing this
+	 * result set.
+	 * <p/>
+	 * Basically, there are two valid return values from this method:<ul>
+	 * <li>an instance of {@link PersistentCollection} which indicates to
+	 * continue loading the result set row data into that returned collection
+	 * instance; this may be either an instance already associated and in the
+	 * midst of being loaded, or a newly instantiated instance as a matching
+	 * associated collection was not found.</li>
+	 * <li><i>null</i> indicates to ignore the corresponding result set row
+	 * data relating to the requested collection; this indicates that either
+	 * the collection was found to already be associated with the persistence
+	 * context in a fully loaded state, or it was found in a loading state
+	 * associated with another result set processing context.</li>
+	 * </ul>
+	 *
+	 * @param persister The persister for the collection being requested.
+	 * @param key The key of the collection being requested.
+	 *
+	 * @return The loading collection (see discussion above).
+	 */
+	public PersistentCollection getLoadingCollection(final CollectionPersister persister, final Serializable key) {
+		final EntityMode em = loadContexts.getPersistenceContext().getSession().getEntityMode();
+		final CollectionKey collectionKey = new CollectionKey( persister, key, em );
+		if ( log.isTraceEnabled() ) {
+			log.trace( "starting attempt to find loading collection [" + MessageHelper.collectionInfoString( persister.getRole(), key ) + "]" );
+		}
+		final LoadingCollectionEntry loadingCollectionEntry = locateLoadingCollectionEntry( collectionKey );
+		if ( loadingCollectionEntry == null ) {
+			// look for existing collection as part of the persistence context
+			PersistentCollection collection = loadContexts.getPersistenceContext().getCollection( collectionKey );
+			if ( collection != null ) {
+				if ( collection.wasInitialized() ) {
+					log.trace( "collection already initialized; ignoring" );
+					return null; // ignore this row of results! Note the early exit
+				}
+				else {
+					// initialize this collection
+					log.trace( "collection not yet initialized; initializing" );
+				}
+			}
+			else {
+				Object owner = loadContexts.getPersistenceContext().getCollectionOwner( key, persister );
+				final boolean newlySavedEntity = owner != null
+						&& loadContexts.getPersistenceContext().getEntry( owner ).getStatus() != Status.LOADING
+						&& em != EntityMode.DOM4J;
+				if ( newlySavedEntity ) {
+					// important, to account for newly saved entities in query
+					// todo : some kind of check for new status...
+					log.trace( "owning entity already loaded; ignoring" );
+					return null;
+				}
+				else {
+					// create one
+					if ( log.isTraceEnabled() ) {
+						log.trace( "instantiating new collection [key=" + key + ", rs=" + resultSet + "]" );
+					}
+					collection = persister.getCollectionType()
+							.instantiate( loadContexts.getPersistenceContext().getSession(), persister, key );
+				}
+			}
+			collection.beforeInitialize( persister, -1 );
+			collection.beginRead();
+			loadingCollections.put( collectionKey, new LoadingCollectionEntry( resultSet, persister, key, collection ) );
+			return collection;
+		}
+		else {
+			if ( loadingCollectionEntry.getResultSet() == resultSet ) {
+				log.trace( "found loading collection bound to current result set processing; reading row" );
+				return loadingCollectionEntry.getCollection();
+			}
+			else {
+				// ignore this row, the collection is in process of
+				// being loaded somewhere further "up" the stack
+				log.trace( "collection is already being initialized; ignoring row" );
+				return null;
+			}
+		}
+	}
+
+	private LoadingCollectionEntry locateLoadingCollectionEntry(CollectionKey collectionKey) {
+		if ( log.isTraceEnabled() ) {
+			log.trace( "attempting to locate loading collection entry [" + collectionKey + "]" );
+		}
+		// first try our loading collections
+		LoadingCollectionEntry loadingCollectionEntry = getLocalLoadingCollectionEntry( collectionKey );
+		if ( loadingCollectionEntry == null ) {
+			// the loading collection is not associated with our result set, so check the other
+			// result sets registered with the load context...
+			loadingCollectionEntry = loadContexts.locateLoadingCollectionEntry( collectionKey, this );
+		}
+		return loadingCollectionEntry;
+	}
+
+	LoadingCollectionEntry getLocalLoadingCollectionEntry(CollectionKey key) {
+		if ( log.isTraceEnabled() ) {
+			log.trace( "attempting to locally locate loading collection entry [key=" + key + ", rs=" + resultSet + "]" );
+		}
+		return ( LoadingCollectionEntry ) loadingCollections.get( key );
+	}
+
+	/**
+	 * Finish the process of collection-loading for this bound result set.  Mainly this
+	 * involves cleaning up resources and notifying the collections that loading is
+	 * complete.
+	 *
+	 * @param persister The persister for which to complete loading.
+	 */
+	public void endLoadingCollections(CollectionPersister persister) {
+		SessionImplementor session = getLoadContext().getPersistenceContext().getSession();
+
+		// in an effort to avoid concurrent-modification-exceptions (from
+		// potential recursive calls back through here as a result of the
+		// eventual call to PersistentCollection#endRead), we scan the
+		// internal loadingCollections map for matches and store those matches
+		// in a temp collection.  the temp collection is then used to "drive"
+		// the #endRead processing.
+		List matches = null;
+		Iterator iter = loadingCollections.values().iterator();
+		while ( iter.hasNext() ) {
+			LoadingCollectionEntry lce = (LoadingCollectionEntry) iter.next();
+			if ( lce.getResultSet() == resultSet && lce.getPersister() == persister) {
+				if ( matches == null ) {
+					matches = new ArrayList();
+				}
+				matches.add( lce );
+				if ( lce.getCollection().getOwner() == null ) {
+					session.getPersistenceContext().addUnownedCollection(
+							new CollectionKey( persister, lce.getKey(), session.getEntityMode() ),
+							lce.getCollection()
+					);
+				}
+				if ( log.isTraceEnabled() ) {
+					log.trace( "removing collection load entry [" + lce + "]" );
+				}
+				iter.remove();
+			}
+		}
+
+		endLoadingCollections( persister, matches );
+	}
+
+	private void endLoadingCollections(CollectionPersister persister, List matchedCollectionEntries) {
+		final int count = ( matchedCollectionEntries == null ) ? 0 : matchedCollectionEntries.size();
+
+		if ( log.isDebugEnabled() ) {
+			log.debug( count + " collections were found in result set for role: " + persister.getRole() );
+		}
+
+		for ( int i = 0; i < count; i++ ) {
+			LoadingCollectionEntry lce = ( LoadingCollectionEntry ) matchedCollectionEntries.get( i );
+			endLoadingCollection( lce, persister );
+		}
+
+		if ( log.isDebugEnabled() ) {
+			log.debug( count + " collections initialized for role: " + persister.getRole() );
+		}
+	}
+
+	private void endLoadingCollection(LoadingCollectionEntry lce, CollectionPersister persister) {
+		if ( log.isTraceEnabled() ) {
+			log.debug( "ending loading collection [" + lce + "]" );
+		}
+		final SessionImplementor session = getLoadContext().getPersistenceContext().getSession();
+		final EntityMode em = session.getEntityMode();
+
+		boolean hasNoQueuedAdds = lce.getCollection().endRead(); // warning: can cause a recursive calls! (proxy initialization)
+
+		if ( persister.getCollectionType().hasHolder( em ) ) {
+			getLoadContext().getPersistenceContext().addCollectionHolder( lce.getCollection() );
+		}
+
+		CollectionEntry ce = getLoadContext().getPersistenceContext().getCollectionEntry( lce.getCollection() );
+		if ( ce == null ) {
+			ce = getLoadContext().getPersistenceContext().addInitializedCollection( persister, lce.getCollection(), lce.getKey() );
+		}
+		else {
+			ce.postInitialize( lce.getCollection() );
+		}
+
+		boolean addToCache = hasNoQueuedAdds && // there were no queued additions
+				persister.hasCache() &&             // and the role has a cache
+				session.getCacheMode().isPutEnabled() &&
+				!ce.isDoremove();                   // and this is not a forced initialization during flush
+		if ( addToCache ) {
+			addCollectionToCache( lce, persister );
+		}
+
+		if ( log.isDebugEnabled() ) {
+			log.debug( "collection fully initialized: " + MessageHelper.collectionInfoString(persister, lce.getKey(), session.getFactory() ) );
+		}
+
+		if ( session.getFactory().getStatistics().isStatisticsEnabled() ) {
+			session.getFactory().getStatisticsImplementor().loadCollection( persister.getRole() );
+		}
+	}
+
+	/**
+	 * Add the collection to the second-level cache
+	 *
+	 * @param lce The entry representing the collection to add
+	 * @param persister The persister
+	 */
+	private void addCollectionToCache(LoadingCollectionEntry lce, CollectionPersister persister) {
+		final SessionImplementor session = getLoadContext().getPersistenceContext().getSession();
+		final SessionFactoryImplementor factory = session.getFactory();
+
+		if ( log.isDebugEnabled() ) {
+			log.debug( "Caching collection: " + MessageHelper.collectionInfoString( persister, lce.getKey(), factory ) );
+		}
+
+		if ( !session.getEnabledFilters().isEmpty() && persister.isAffectedByEnabledFilters( session ) ) {
+			// some filters affecting the collection are enabled on the session, so do not do the put into the cache.
+			log.debug( "Refusing to add to cache due to enabled filters" );
+			// todo : add the notion of enabled filters to the CacheKey to differentiate filtered collections from non-filtered;
+			//      but CacheKey is currently used for both collections and entities; would ideally need to define two seperate ones;
+			//      currently this works in conjuction with the check on
+			//      DefaultInitializeCollectionEventHandler.initializeCollectionFromCache() (which makes sure to not read from
+			//      cache with enabled filters).
+			return; // EARLY EXIT!!!!!
+		}
+
+		final Comparator versionComparator;
+		final Object version;
+		if ( persister.isVersioned() ) {
+			versionComparator = persister.getOwnerEntityPersister().getVersionType().getComparator();
+			final Object collectionOwner = getLoadContext().getPersistenceContext().getCollectionOwner( lce.getKey(), persister );
+			version = getLoadContext().getPersistenceContext().getEntry( collectionOwner ).getVersion();
+		}
+		else {
+			version = null;
+			versionComparator = null;
+		}
+
+		CollectionCacheEntry entry = new CollectionCacheEntry( lce.getCollection(), persister );
+		CacheKey cacheKey = new CacheKey(
+				lce.getKey(),
+				persister.getKeyType(),
+				persister.getRole(),
+				session.getEntityMode(),
+				session.getFactory()
+		);
+		boolean put = persister.getCache().put(
+				cacheKey,
+				persister.getCacheEntryStructure().structure(entry),
+				session.getTimestamp(),
+				version,
+				versionComparator,
+				factory.getSettings().isMinimalPutsEnabled() && session.getCacheMode()!= CacheMode.REFRESH
+		);
+
+		if ( put && factory.getStatistics().isStatisticsEnabled() ) {
+			factory.getStatisticsImplementor().secondLevelCachePut( persister.getCache().getRegionName() );
+		}
+	}
+
+	void cleanup() {
+		if ( !loadingCollections.isEmpty() ) {
+			log.warn( "On CollectionLoadContext#clear, loadingCollections contained [" + loadingCollections.size() + "] entries" );
+		}
+		loadingCollections.clear();
+	}
+
+
+	public String toString() {
+		return super.toString() + "<rs=" + resultSet + ">";
+	}
+}

Added: branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/loading/EntityLoadContext.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/loading/EntityLoadContext.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/loading/EntityLoadContext.java	2007-03-19 20:43:46 UTC (rev 11301)
@@ -0,0 +1,33 @@
+package org.hibernate.engine.loading;
+
+import java.sql.ResultSet;
+import java.util.List;
+import java.util.ArrayList;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * {@inheritDoc}
+ *
+ * @author Steve Ebersole
+ */
+public class EntityLoadContext {
+	private static final Log log = LogFactory.getLog( EntityLoadContext.class );
+
+	private final LoadContexts loadContexts;
+	private final ResultSet resultSet;
+	private final List hydratingEntities = new ArrayList( 20 ); // todo : need map? the prob is a proper key, right?
+
+	public EntityLoadContext(LoadContexts loadContexts, ResultSet resultSet) {
+		this.loadContexts = loadContexts;
+		this.resultSet = resultSet;
+	}
+
+	void cleanup() {
+		if ( !hydratingEntities.isEmpty() ) {
+			log.warn( "On CollectionLoadContext#clear, hydratingEntities contained [" + hydratingEntities.size() + "] entries" );
+		}
+		hydratingEntities.clear();
+	}
+}

Added: branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/loading/LoadContexts.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/loading/LoadContexts.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/loading/LoadContexts.java	2007-03-19 20:43:46 UTC (rev 11301)
@@ -0,0 +1,184 @@
+package org.hibernate.engine.loading;
+
+import java.sql.ResultSet;
+import java.util.Map;
+import java.util.Iterator;
+import java.io.Serializable;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.util.IdentityMap;
+import org.hibernate.engine.PersistenceContext;
+import org.hibernate.engine.CollectionKey;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.pretty.MessageHelper;
+import org.hibernate.EntityMode;
+
+/**
+ * Maps {@link ResultSet result-sets} to specific contextual data
+ * related to processing that {@link ResultSet result-sets}.
+ * <p/>
+ * Implementation note: internally an {@link IdentityMap} is used to maintain
+ * the mappings; {@link IdentityMap} was chosen because I'd rather not be
+ * dependent upon potentially bad {@link ResultSet#equals} and {ResultSet#hashCode}
+ * implementations.
+ * <p/>
+ * Considering the JDBC-redesign work, would further like this contextual info
+ * not mapped seperately, but available based on the result set being processed.
+ * This would also allow maintaining a single mapping as we could reliably get
+ * notification of the result-set closing...
+ *
+ * @author Steve Ebersole
+ */
+public class LoadContexts {
+	private static final Log log = LogFactory.getLog( LoadContexts.class );
+
+	private final PersistenceContext persistenceContext;
+	private Map collectionLoadContexts;
+	private Map entityLoadContexts;
+
+	/**
+	 * Creates and binds this to the given persistence context.
+	 *
+	 * @param persistenceContext The persistence context to which this
+	 * will be bound.
+	 */
+	public LoadContexts(PersistenceContext persistenceContext) {
+		this.persistenceContext = persistenceContext;
+	}
+
+	/**
+	 * Retrieves the persistence context to which this is bound.
+	 *
+	 * @return The persistence context to which this is bound.
+	 */
+	public PersistenceContext getPersistenceContext() {
+		return persistenceContext;
+	}
+
+	/**
+	 * Get the {@link CollectionLoadContext} associated with the given
+	 * {@link ResultSet}, creating one if needed.
+	 *
+	 * @param resultSet The result set for which to retrieve the context.
+	 * @return The processing context.
+	 */
+	public CollectionLoadContext getCollectionLoadContext(ResultSet resultSet) {
+		CollectionLoadContext context = null;
+		if ( collectionLoadContexts == null ) {
+			collectionLoadContexts = IdentityMap.instantiate( 8 );
+		}
+		else {
+			context = ( CollectionLoadContext ) collectionLoadContexts.get( resultSet );
+		}
+		if ( context == null ) {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "constructing collection load context for result set [" + resultSet + "]" );
+			}
+			context = new CollectionLoadContext( this, resultSet );
+			collectionLoadContexts.put( resultSet, context );
+		}
+		return context;
+	}
+
+	/**
+	 * Attempt to locate the loading collection given the owner's key.  The lookup here
+	 * occurs against all result-set contexts...
+	 *
+	 * @param persister The collection persister
+	 * @param ownerKey The owner key
+	 * @return The loading collection, or null if not found.
+	 */
+	public PersistentCollection locateLoadingCollection(CollectionPersister persister, Serializable ownerKey) {
+		LoadingCollectionEntry lce = locateLoadingCollectionEntry( new CollectionKey( persister, ownerKey, getEntityMode() ), null ); // note: null because here we are interested in all contexts...
+		if ( lce != null ) {
+			if ( log.isTraceEnabled() ) {
+				log.trace( "returning loading collection:" + MessageHelper.collectionInfoString( persister, ownerKey, getSession().getFactory() ) );
+			}
+			return lce.getCollection();
+		}
+		else {
+			// todo : should really move this log statement to CollectionType, where this is used from...
+			if ( log.isTraceEnabled() ) {
+				log.trace( "creating collection wrapper:" + MessageHelper.collectionInfoString( persister, ownerKey, getSession().getFactory() ) );
+			}
+			return null;
+		}
+	}
+
+	/**
+	 * Locate the LoadingCollectionEntry within *any* of the tracked
+	 * {@link CollectionLoadContext}s.
+	 * <p/>
+	 * Implementation note: package protected, as this is meant solely for use
+	 * by {@link CollectionLoadContext} to be able to locate collections
+	 * being loaded by other {@link CollectionLoadContext}s/{@link ResultSet}s.
+	 *
+	 * @param key The collection key.
+	 * @param caller The collection load context making this call (for performance optimization)
+	 * @return The located entry; or null.
+	 */
+	LoadingCollectionEntry locateLoadingCollectionEntry(CollectionKey key, CollectionLoadContext caller) {
+		if ( collectionLoadContexts == null ) {
+			return null;
+		}
+		if ( log.isTraceEnabled() ) {
+			log.trace( "attempting to locate loading collection entry [" + key + "] in any result-set context" );
+		}
+		LoadingCollectionEntry rtn = null;
+		Iterator itr = collectionLoadContexts.values().iterator();
+		while ( itr.hasNext() ) {
+			final CollectionLoadContext collectionLoadContext = ( CollectionLoadContext ) itr.next();
+			if ( collectionLoadContext == caller ) {
+				continue;
+			}
+			rtn = collectionLoadContext.getLocalLoadingCollectionEntry( key );
+			if ( rtn != null ) {
+				if ( log.isTraceEnabled() ) {
+					log.trace( "collection [" + key + "] located in load context [" + collectionLoadContext + "]" );
+				}
+				break;
+			}
+		}
+		return rtn;
+	}
+
+	public EntityLoadContext getEntityLoadContext(ResultSet resultSet) {
+		EntityLoadContext context = null;
+		if ( entityLoadContexts == null ) {
+			entityLoadContexts = IdentityMap.instantiate( 8 );
+		}
+		else {
+			context = ( EntityLoadContext ) entityLoadContexts.get( resultSet );
+		}
+		if ( context == null ) {
+			context = new EntityLoadContext( this, resultSet );
+			entityLoadContexts.put( resultSet, context );
+		}
+		return context;
+	}
+
+	public void cleanup(ResultSet resultSet) {
+		if ( collectionLoadContexts != null ) {
+			CollectionLoadContext collectionLoadContext = ( CollectionLoadContext ) collectionLoadContexts.remove( resultSet );
+			collectionLoadContext.cleanup();
+		}
+		if ( entityLoadContexts != null ) {
+			EntityLoadContext entityLoadContext = ( EntityLoadContext ) entityLoadContexts.remove( resultSet );
+			entityLoadContext.cleanup();
+		}
+	}
+
+	private SessionImplementor getSession() {
+		return getPersistenceContext().getSession();
+	}
+
+	private EntityMode getEntityMode() {
+		return getSession().getEntityMode();
+	}
+
+
+}

Added: branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/loading/LoadingCollectionEntry.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/loading/LoadingCollectionEntry.java	                        (rev 0)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/engine/loading/LoadingCollectionEntry.java	2007-03-19 20:43:46 UTC (rev 11301)
@@ -0,0 +1,51 @@
+package org.hibernate.engine.loading;
+
+import java.io.Serializable;
+import java.sql.ResultSet;
+
+import org.hibernate.collection.PersistentCollection;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.pretty.MessageHelper;
+
+/**
+ * Represents a collection currently being loaded.
+ *
+ * @author Steve Ebersole
+ */
+public class LoadingCollectionEntry {
+	private final ResultSet resultSet;
+	private final CollectionPersister persister;
+	private final Serializable key;
+	private final PersistentCollection collection;
+
+	public LoadingCollectionEntry(
+			ResultSet resultSet,
+			CollectionPersister persister,
+			Serializable key,
+			PersistentCollection collection) {
+		this.resultSet = resultSet;
+		this.persister = persister;
+		this.key = key;
+		this.collection = collection;
+	}
+
+	public ResultSet getResultSet() {
+		return resultSet;
+	}
+
+	public CollectionPersister getPersister() {
+		return persister;
+	}
+
+	public Serializable getKey() {
+		return key;
+	}
+
+	public PersistentCollection getCollection() {
+		return collection;
+	}
+
+	public String toString() {
+		return getClass().getName() + "<rs=" + resultSet + ", coll=" + MessageHelper.collectionInfoString( persister.getRole(), key ) + ">@" + Integer.toHexString( hashCode() );
+	}
+}

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/loader/Loader.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/loader/Loader.java	2007-03-19 19:48:21 UTC (rev 11300)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/loader/Loader.java	2007-03-19 20:43:46 UTC (rev 11301)
@@ -89,18 +89,24 @@
 
 	/**
 	 * The SQL query string to be called; implemented by all subclasses
+	 *
+	 * @return The sql command this loader should use to get its {@link ResultSet}.
 	 */
 	protected abstract String getSQLString();
 
 	/**
 	 * An array of persisters of entity classes contained in each row of results;
 	 * implemented by all subclasses
+	 *
+	 * @return The entity persisters.
 	 */
 	protected abstract Loadable[] getEntityPersisters();
-	
+
 	/**
 	 * An array indicating whether the entities have eager property fetching
-	 * enabled
+	 * enabled.
+	 *
+	 * @return Eager property fetching indicators.
 	 */
 	protected boolean[] getEntityEagerPropertyFetches() {
 		return null;
@@ -108,15 +114,21 @@
 
 	/**
 	 * An array of indexes of the entity that owns a one-to-one association
-	 * to the entity at the given index (-1 if there is no "owner")
+	 * to the entity at the given index (-1 if there is no "owner").  The
+	 * indexes contained here are relative to the result of
+	 * {@link #getEntityPersisters}.
+	 *
+	 * @return The owner indicators (see discussion above).
 	 */
 	protected int[] getOwners() {
 		return null;
 	}
 
 	/**
-	 * An array of unique key property names by which the corresponding
-	 * entities are referenced by other entities in the result set
+	 * An array of the owner types corresponding to the {@link #getOwners()}
+	 * returns.  Indices indicating no owner would be null here.
+	 *
+	 * @return The types for the owners.
 	 */
 	protected EntityType[] getOwnerAssociationTypes() {
 		return null;
@@ -858,13 +870,14 @@
 	}
 
 	private void endCollectionLoad(
-			final Object resultSetId, 
-			final SessionImplementor session, 
-			final CollectionPersister collectionPersister
-	) {
+			final Object resultSetId,
+			final SessionImplementor session,
+			final CollectionPersister collectionPersister) {
 		//this is a query and we are loading multiple instances of the same collection role
-		session.getPersistenceContext().getCollectionLoadContext()
-				.endLoadingCollections( collectionPersister, resultSetId, session );
+		session.getPersistenceContext()
+				.getLoadContexts()
+				.getCollectionLoadContext( ( ResultSet ) resultSetId )
+				.endLoadingCollections( collectionPersister );
 	}
 
 	protected List getResultList(List results, ResultTransformer resultTransformer) throws QueryException {
@@ -987,8 +1000,9 @@
 				}
 			}
 
-			PersistentCollection rowCollection = persistenceContext.getCollectionLoadContext()
-			        .getLoadingCollection( persister, collectionRowKey, rs, session.getEntityMode() );
+			PersistentCollection rowCollection = persistenceContext.getLoadContexts()
+					.getCollectionLoadContext( rs )
+					.getLoadingCollection( persister, collectionRowKey );
 
 			if ( rowCollection != null ) {
 				rowCollection.readFrom( rs, persister, descriptor, owner );
@@ -1007,9 +1021,9 @@
 					);
 			}
 
-			persistenceContext.getCollectionLoadContext()
-					.getLoadingCollection( persister, optionalKey, rs, session.getEntityMode() ); //handle empty collection
-
+			persistenceContext.getLoadContexts()
+					.getCollectionLoadContext( rs )
+					.getLoadingCollection( persister, optionalKey ); // handle empty collection
 		}
 
 		// else no collection element, but also no owner
@@ -1024,7 +1038,7 @@
 	private void handleEmptyCollections(
 	        final Serializable[] keys,
 	        final Object resultSetId,
-	        final SessionImplementor session) throws HibernateException {
+	        final SessionImplementor session) {
 
 		if ( keys != null ) {
 			// this is a collection initializer, so we must create a collection
@@ -1042,18 +1056,13 @@
 								MessageHelper.collectionInfoString( collectionPersisters[j], keys[i], getFactory() ) 
 							);
 					}
-	
+
 					session.getPersistenceContext()
-						.getCollectionLoadContext()
-						.getLoadingCollection( 
-								collectionPersisters[j], 
-								keys[i], 
-								resultSetId, 
-								session.getEntityMode() 
-							);
+							.getLoadContexts()
+							.getCollectionLoadContext( ( ResultSet ) resultSetId )
+							.getLoadingCollection( collectionPersisters[j], keys[i] );
 				}
 			}
-
 		}
 
 		// else this is not a collection initializer (and empty collections will

Modified: branches/Branch_3_2/Hibernate3/src/org/hibernate/type/CollectionType.java
===================================================================
--- branches/Branch_3_2/Hibernate3/src/org/hibernate/type/CollectionType.java	2007-03-19 19:48:21 UTC (rev 11300)
+++ branches/Branch_3_2/Hibernate3/src/org/hibernate/type/CollectionType.java	2007-03-19 20:43:46 UTC (rev 11301)
@@ -101,9 +101,13 @@
 	/**
 	 * Instantiate an uninitialized collection wrapper or holder. Callers MUST add the holder to the
 	 * persistence context!
+	 *
+	 * @param session The session from which the request is originating.
+	 * @param persister The underlying collection persister (metadata)
+	 * @param key The owner key.
+	 * @return The instantiated collection.
 	 */
-	public abstract PersistentCollection instantiate(SessionImplementor session,
-			CollectionPersister persister, Serializable key) throws HibernateException;
+	public abstract PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister, Serializable key);
 
 	public Object nullSafeGet(ResultSet rs, String name, SessionImplementor session, Object owner)
 			throws HibernateException, SQLException {
@@ -145,8 +149,7 @@
 		}
 	}
 
-	protected String renderLoggableString(Object value, SessionFactoryImplementor factory)
-			throws HibernateException {
+	protected String renderLoggableString(Object value, SessionFactoryImplementor factory) {
 		if ( Element.class.isInstance( value ) ) {
 			// for DOM4J "collections" only
 			// TODO: it would be better if this was done at the higher level by Printer
@@ -174,6 +177,10 @@
 
 	/**
 	 * Get an iterator over the element set of the collection, which may not yet be wrapped
+	 *
+	 * @param collection The collection to be iterated
+	 * @param session The session from which the request is originating.
+	 * @return The iterator.
 	 */
 	public Iterator getElementsIterator(Object collection, SessionImplementor session) {
 		if ( session.getEntityMode()==EntityMode.DOM4J ) {
@@ -196,6 +203,9 @@
 
 	/**
 	 * Get an iterator over the element set of the collection in POJO mode
+	 *
+	 * @param collection The collection to be iterated
+	 * @return The iterator.
 	 */
 	protected Iterator getElementsIterator(Object collection) {
 		return ( (Collection) collection ).iterator();
@@ -241,16 +251,25 @@
 
 	/**
 	 * Is the owning entity versioned?
+	 *
+	 * @param session The session from which the request is originating.
+	 * @return True if the collection owner is versioned; false otherwise.
+	 * @throws MappingException Indicates the underlying persister could not be located.
 	 */
 	private boolean isOwnerVersioned(SessionImplementor session) throws MappingException {
-		return getPersister( session )
-				.getOwnerEntityPersister()
-				.isVersioned();
+		return getPersister( session ).getOwnerEntityPersister().isVersioned();
 	}
 
-	private CollectionPersister getPersister(SessionImplementor session) {
-		return session.getFactory()
-				.getCollectionPersister( role );
+	/**
+	 * Get our underlying collection persister (using the session to access the
+	 * factory).
+	 *
+	 * @param session The session from which the request is originating.
+	 * @return The underlying collection persister
+	 * @throws org.hibernate.MappingException Indicates the underlying persister could not be located.
+	 */
+	private CollectionPersister getPersister(SessionImplementor session) throws MappingException {
+		return session.getFactory().getCollectionPersister( role );
 	}
 
 	public boolean isDirty(Object old, Object current, SessionImplementor session)
@@ -269,9 +288,14 @@
 			throws HibernateException {
 		return isDirty(old, current, session);
 	}
+
 	/**
-	 * Wrap the naked collection instance in a wrapper, or instantiate a holder. Callers MUST add
-	 * the holder to the persistence context!
+	 * Wrap the naked collection instance in a wrapper, or instantiate a
+	 * holder. Callers <b>MUST</b> add the holder to the persistence context!
+	 *
+	 * @param session The session from which the request is originating.
+	 * @param collection The bare collection to be wrapped.
+	 * @return The wrapped collection.
 	 */
 	public abstract PersistentCollection wrap(SessionImplementor session, Object collection);
 
@@ -290,6 +314,10 @@
 	/**
 	 * Get the key value from the owning entity instance, usually the identifier, but might be some
 	 * other unique key, in the case of property-ref
+	 *
+	 * @param owner The collection owner
+	 * @param session The session from which the request is originating.
+	 * @return The collection owner's key
 	 */
 	public Serializable getKeyOfOwner(Object owner, SessionImplementor session) {
 		
@@ -518,9 +546,13 @@
 
 	/**
 	 * instantiate a collection wrapper (called when loading an object)
+	 *
+	 * @param key The collection owner key
+	 * @param session The session from which the request is originating.
+	 * @param owner The collection owner
+	 * @return The collection
 	 */
-	public Object getCollection(Serializable key, SessionImplementor session, Object owner)
-			throws HibernateException {
+	public Object getCollection(Serializable key, SessionImplementor session, Object owner) {
 
 		CollectionPersister persister = getPersister( session );
 		final PersistenceContext persistenceContext = session.getPersistenceContext();
@@ -529,25 +561,19 @@
 		if (entityMode==EntityMode.DOM4J && !isEmbeddedInXML) {
 			return UNFETCHED_COLLECTION;
 		}
-		
+
 		// check if collection is currently being loaded
-		PersistentCollection collection = persistenceContext
-				.getCollectionLoadContext()
-				.getLoadingCollection( persister, key, entityMode );
-		
+		PersistentCollection collection = persistenceContext.getLoadContexts().locateLoadingCollection( persister, key );
 		if ( collection == null ) {
-			
 			// check if it is already completely loaded, but unowned
 			collection = persistenceContext.useUnownedCollection( new CollectionKey(persister, key, entityMode) );
-			
-			if (collection==null) {
-
+			if ( collection == null ) {
 				// create a new collection wrapper, to be initialized later
 				collection = instantiate( session, persister, key );
-				collection.setOwner(owner);
-	
+				collection.setOwner( owner );
+
 				persistenceContext.addUninitializedCollection( persister, collection, key );
-	
+
 				// some collections are not lazy:
 				if ( initializeImmediately( entityMode ) ) {
 					session.initializeCollection( collection, false );
@@ -559,13 +585,9 @@
 				if ( hasHolder( entityMode ) ) {
 					session.getPersistenceContext().addCollectionHolder( collection );
 				}
-				
 			}
-			
 		}
-		
-		collection.setOwner(owner);
-
+		collection.setOwner( owner );
 		return collection.getValue();
 	}
 




More information about the hibernate-commits mailing list