KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hibernate > engine > CollectionLoadContext


1 //$Id: CollectionLoadContext.java,v 1.16 2005/07/20 19:56:46 oneovthafew Exp $
2
package org.hibernate.engine;
3
4 import java.io.Serializable JavaDoc;
5 import java.util.ArrayList JavaDoc;
6 import java.util.Comparator JavaDoc;
7 import java.util.HashMap JavaDoc;
8 import java.util.Iterator JavaDoc;
9 import java.util.List JavaDoc;
10 import java.util.Map JavaDoc;
11
12 import org.apache.commons.logging.Log;
13 import org.apache.commons.logging.LogFactory;
14 import org.hibernate.CacheMode;
15 import org.hibernate.EntityMode;
16 import org.hibernate.HibernateException;
17 import org.hibernate.cache.CacheKey;
18 import org.hibernate.cache.entry.CollectionCacheEntry;
19 import org.hibernate.collection.PersistentCollection;
20 import org.hibernate.persister.collection.CollectionPersister;
21 import org.hibernate.pretty.MessageHelper;
22
23 /**
24  * Represents the state of collections currently being loaded. Eventually, I
25  * would like to have multiple instances of this per session - one per JDBC
26  * result set, instead of the resultSetId being passed.
27  * @author Gavin King
28  */

29 public class CollectionLoadContext {
30     
31     private static final Log log = LogFactory.getLog(CollectionLoadContext.class);
32
33     // The collections we are currently loading
34
private final Map JavaDoc loadingCollections = new HashMap JavaDoc(8);
35     private final PersistenceContext context;
36     
37     public CollectionLoadContext(PersistenceContext context) {
38         this.context = context;
39     }
40     
41     private static final class LoadingCollectionEntry {
42
43         final PersistentCollection collection;
44         final Serializable JavaDoc key;
45         final Object JavaDoc resultSetId;
46         final CollectionPersister persister;
47
48         LoadingCollectionEntry(
49                 final PersistentCollection collection,
50                 final Serializable JavaDoc key,
51                 final CollectionPersister persister,
52                 final Object JavaDoc resultSetId
53         ) {
54             this.collection = collection;
55             this.key = key;
56             this.persister = persister;
57             this.resultSetId = resultSetId;
58         }
59     }
60
61     /**
62      * Retrieve a collection that is in the process of being loaded, instantiating
63      * a new collection if there is nothing for the given id, or returning null
64      * if the collection with the given id is already fully loaded in the session
65      */

66     public PersistentCollection getLoadingCollection(
67             final CollectionPersister persister,
68             final Serializable JavaDoc key,
69             final Object JavaDoc resultSetId,
70             final EntityMode em)
71     throws HibernateException {
72         CollectionKey ckey = new CollectionKey(persister, key, em);
73         LoadingCollectionEntry lce = getLoadingCollectionEntry(ckey);
74         if ( lce == null ) {
75             //look for existing collection
76
PersistentCollection collection = context.getCollection(ckey);
77             if ( collection != null ) {
78                 if ( collection.wasInitialized() ) {
79                     log.trace( "collection already initialized: ignoring" );
80                     return null; //ignore this row of results! Note the early exit
81
}
82                 else {
83                     //initialize this collection
84
log.trace( "uninitialized collection: initializing" );
85                 }
86             }
87             else {
88                 Object JavaDoc entity = context.getCollectionOwner(key, persister);
89                 final boolean newlySavedEntity = entity != null &&
90                         context.getEntry(entity).getStatus() != Status.LOADING &&
91                         em!=EntityMode.DOM4J;
92                 if ( newlySavedEntity ) {
93                     //important, to account for newly saved entities in query
94
//TODO: some kind of check for new status...
95
log.trace( "owning entity already loaded: ignoring" );
96                     return null;
97                 }
98                 else {
99                     //create one
100
log.trace( "new collection: instantiating" );
101                     collection = persister.getCollectionType()
102                             .instantiate( context.getSession(), persister, key );
103                 }
104             }
105             collection.beforeInitialize(persister);
106             collection.beginRead();
107             addLoadingCollectionEntry(ckey, collection, persister, resultSetId);
108             return collection;
109         }
110         else {
111             if ( lce.resultSetId == resultSetId ) {
112                 log.trace( "reading row" );
113                 return lce.collection;
114             }
115             else {
116                 // ignore this row, the collection is in process of
117
// being loaded somewhere further "up" the stack
118
log.trace( "collection is already being initialized: ignoring row" );
119                 return null;
120             }
121         }
122     }
123
124     /**
125      * Retrieve a collection that is in the process of being loaded, returning null
126      * if there is no loading collection with the given id
127      */

128     public PersistentCollection getLoadingCollection(CollectionPersister persister, Serializable JavaDoc id, EntityMode em) {
129         LoadingCollectionEntry lce = getLoadingCollectionEntry( new CollectionKey(persister, id, em) );
130         if ( lce != null ) {
131             if ( log.isTraceEnabled() ) {
132                 log.trace(
133                         "returning loading collection:" +
134                         MessageHelper.collectionInfoString(persister, id, context.getSession().getFactory())
135                     );
136             }
137             return lce.collection;
138         }
139         else {
140             if ( log.isTraceEnabled() ) {
141                 log.trace(
142                         "creating collection wrapper:" +
143                         MessageHelper.collectionInfoString(persister, id, context.getSession().getFactory())
144                     );
145             }
146             return null;
147         }
148     }
149
150     /**
151      * Create a new loading collection entry
152      */

153     private void addLoadingCollectionEntry(
154             final CollectionKey collectionKey,
155             final PersistentCollection collection,
156             final CollectionPersister persister,
157             final Object JavaDoc resultSetId
158     ) {
159         loadingCollections.put(
160                 collectionKey,
161                 new LoadingCollectionEntry(
162                         collection,
163                         collectionKey.getKey(),
164                         persister,
165                         resultSetId
166                     )
167             );
168     }
169
170     /**
171      * get an existing new loading collection entry
172      */

173     private LoadingCollectionEntry getLoadingCollectionEntry(CollectionKey collectionKey) {
174         return ( LoadingCollectionEntry ) loadingCollections.get( collectionKey );
175     }
176
177     /**
178      * After we have finished processing a result set, a particular loading collection that
179      * we are done.
180      */

181     private void endLoadingCollection(LoadingCollectionEntry lce, CollectionPersister persister, EntityMode em) {
182
183         boolean hasNoQueuedAdds = lce.collection.endRead(); //warning: can cause a recursive query! (proxy initialization)
184

185         if ( persister.getCollectionType().hasHolder(em) ) {
186             context.addCollectionHolder(lce.collection);
187         }
188         
189         CollectionEntry ce = context.getCollectionEntry(lce.collection);
190         if ( ce==null ) {
191             ce = context.addInitializedCollection(persister, lce.collection, lce.key);
192         }
193         else {
194             ce.postInitialize(lce.collection);
195         }
196
197         final SessionImplementor session = context.getSession();
198         
199         boolean addToCache = hasNoQueuedAdds && // there were no queued additions
200
persister.hasCache() && // and the role has a cache
201
session.getCacheMode().isPutEnabled() &&
202                 !ce.isDoremove(); // and this is not a forced initialization during flush
203
if (addToCache) addCollectionToCache(lce, persister);
204
205         if ( log.isDebugEnabled() ) {
206             log.debug(
207                     "collection fully initialized: " +
208                     MessageHelper.collectionInfoString(persister, lce.key, context.getSession().getFactory())
209                 );
210         }
211
212         if ( session.getFactory().getStatistics().isStatisticsEnabled() ) {
213             session.getFactory().getStatisticsImplementor().loadCollection(
214                     persister.getRole()
215                 );
216         }
217
218     }
219     /**
220      * Finish the process of loading collections for a particular result set
221      */

222     public void endLoadingCollections(CollectionPersister persister, Object JavaDoc resultSetId, SessionImplementor session)
223     throws HibernateException {
224
225         // scan the loading collections for collections from this result set
226
// put them in a new temp collection so that we are safe from concurrent
227
// modification when the call to endRead() causes a proxy to be
228
// initialized
229
List JavaDoc resultSetCollections = null; //TODO: make this the resultSetId?
230
Iterator JavaDoc iter = loadingCollections.values().iterator();
231         while ( iter.hasNext() ) {
232             LoadingCollectionEntry lce = (LoadingCollectionEntry) iter.next();
233             if ( lce.resultSetId == resultSetId && lce.persister==persister) {
234                 if ( resultSetCollections == null ) {
235                     resultSetCollections = new ArrayList JavaDoc();
236                 }
237                 resultSetCollections.add(lce);
238                 if ( lce.collection.getOwner()==null ) {
239                     session.getPersistenceContext()
240                             .addUnownedCollection(
241                                     new CollectionKey( persister, lce.key, session.getEntityMode() ),
242                                     lce.collection
243                                 );
244                 }
245                 iter.remove();
246             }
247         }
248
249         endLoadingCollections( persister, resultSetCollections, session.getEntityMode() );
250     }
251     
252     /**
253      * After we have finished processing a result set, notify the loading collections that
254      * we are done.
255      */

256     private void endLoadingCollections(CollectionPersister persister, List JavaDoc resultSetCollections, EntityMode em)
257     throws HibernateException {
258
259         final int count = (resultSetCollections == null) ? 0 : resultSetCollections.size();
260
261         if ( log.isDebugEnabled() ) {
262             log.debug( count + " collections were found in result set for role: " + persister.getRole() );
263         }
264
265         //now finish them
266
for ( int i = 0; i < count; i++ ) {
267             LoadingCollectionEntry lce = (LoadingCollectionEntry) resultSetCollections.get(i);
268             endLoadingCollection(lce, persister, em);
269         }
270
271         if ( log.isDebugEnabled() ) {
272             log.debug( count + " collections initialized for role: " + persister.getRole() );
273         }
274     }
275
276     /**
277      * Add a collection to the second-level cache
278      */

279     private void addCollectionToCache(LoadingCollectionEntry lce, CollectionPersister persister) {
280
281         if ( log.isDebugEnabled() ) {
282             log.debug(
283                     "Caching collection: " +
284                     MessageHelper.collectionInfoString( persister, lce.key, context.getSession().getFactory() )
285                 );
286         }
287
288         final SessionImplementor session = context.getSession();
289         final SessionFactoryImplementor factory = session.getFactory();
290
291         if ( !session.getEnabledFilters().isEmpty() && persister.isAffectedByEnabledFilters( session ) ) {
292             // some filters affecting the collection are enabled on the session, so do not do the put into the cache.
293
log.debug( "Refusing to add to cache due to enabled filters" );
294             // todo : add the notion of enabled filters to the CacheKey to differentiate filtered collections from non-filtered;
295
// but CacheKey is currently used for both collections and entities; would ideally need to define two seperate ones;
296
// currently this works in conjuction with the check on
297
// DefaultInitializeCollectionEventHandler.initializeCollectionFromCache() (which makes sure to not read from
298
// cache with enabled filters).
299
return; // EARLY EXIT!!!!!
300
}
301
302         final Comparator JavaDoc versionComparator;
303         final Object JavaDoc version;
304         if ( persister.isVersioned() ) {
305             versionComparator = persister.getOwnerEntityPersister().getVersionType().getComparator();
306             version = context.getEntry( context.getCollectionOwner(lce.key, persister) ).getVersion();
307         }
308         else {
309             version = null;
310             versionComparator = null;
311         }
312         
313         CollectionCacheEntry entry = new CollectionCacheEntry(lce.collection, persister);
314
315         boolean put = persister.getCache().put(
316                 new CacheKey( lce.key, persister.getKeyType(), persister.getRole(), session.getEntityMode(), session.getFactory() ),
317                 persister.getCacheEntryStructure().structure(entry),
318                 session.getTimestamp(),
319                 version,
320                 versionComparator,
321                 factory.getSettings().isMinimalPutsEnabled() && session.getCacheMode()!=CacheMode.REFRESH
322             );
323
324         if ( put && factory.getStatistics().isStatisticsEnabled() ) {
325             factory.getStatisticsImplementor().secondLevelCachePut(
326                     persister.getCache().getRegionName()
327                 );
328         }
329     }
330
331
332 }
333
Popular Tags