1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 package org.hibernate.engine.loading;
26
27 import org.hibernate.CacheMode;
28 import org.hibernate.EntityMode;
29 import org.hibernate.HibernateException;
30 import org.hibernate.cache.CacheKey;
31 import org.hibernate.cache.entry.CollectionCacheEntry;
32 import org.hibernate.collection.PersistentCollection;
33 import org.hibernate.engine.*;
34 import org.hibernate.persister.collection.CollectionPersister;
35 import org.hibernate.pretty.MessageHelper;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 import java.io.Serializable;
40 import java.sql.ResultSet;
41 import java.util.*;
42
43
44
45
46
47
48
49
50
51
52
53 public class CollectionLoadContext {
54 private static final Logger log = LoggerFactory.getLogger( CollectionLoadContext.class );
55
56 private final LoadContexts loadContexts;
57 private final ResultSet resultSet;
58 private Set localLoadingCollectionKeys = new HashSet();
59
60
61
62
63
64
65
66 public CollectionLoadContext(LoadContexts loadContexts, ResultSet resultSet) {
67 this.loadContexts = loadContexts;
68 this.resultSet = resultSet;
69 }
70
71 public ResultSet getResultSet() {
72 return resultSet;
73 }
74
75 public LoadContexts getLoadContext() {
76 return loadContexts;
77 }
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101 public PersistentCollection getLoadingCollection(final CollectionPersister persister, final Serializable key) {
102 final EntityMode em = loadContexts.getPersistenceContext().getSession().getEntityMode();
103 final CollectionKey collectionKey = new CollectionKey( persister, key, em );
104 if ( log.isTraceEnabled() ) {
105 log.trace( "starting attempt to find loading collection [" + MessageHelper.collectionInfoString( persister.getRole(), key ) + "]" );
106 }
107 final LoadingCollectionEntry loadingCollectionEntry = loadContexts.locateLoadingCollectionEntry( collectionKey );
108 if ( loadingCollectionEntry == null ) {
109
110 PersistentCollection collection = loadContexts.getPersistenceContext().getCollection( collectionKey );
111 if ( collection != null ) {
112 if ( collection.wasInitialized() ) {
113 log.trace( "collection already initialized; ignoring" );
114 return null;
115 }
116 else {
117
118 log.trace( "collection not yet initialized; initializing" );
119 }
120 }
121 else {
122 Object owner = loadContexts.getPersistenceContext().getCollectionOwner( key, persister );
123 final boolean newlySavedEntity = owner != null
124 && loadContexts.getPersistenceContext().getEntry( owner ).getStatus() != Status.LOADING
125 && em != EntityMode.DOM4J;
126 if ( newlySavedEntity ) {
127
128
129 log.trace( "owning entity already loaded; ignoring" );
130 return null;
131 }
132 else {
133
134 if ( log.isTraceEnabled() ) {
135 log.trace( "instantiating new collection [key=" + key + ", rs=" + resultSet + "]" );
136 }
137 collection = persister.getCollectionType()
138 .instantiate( loadContexts.getPersistenceContext().getSession(), persister, key );
139 }
140 }
141 collection.beforeInitialize( persister, -1 );
142 collection.beginRead();
143 localLoadingCollectionKeys.add( collectionKey );
144 loadContexts.registerLoadingCollectionXRef( collectionKey, new LoadingCollectionEntry( resultSet, persister, key, collection ) );
145 return collection;
146 }
147 else {
148 if ( loadingCollectionEntry.getResultSet() == resultSet ) {
149 log.trace( "found loading collection bound to current result set processing; reading row" );
150 return loadingCollectionEntry.getCollection();
151 }
152 else {
153
154
155 log.trace( "collection is already being initialized; ignoring row" );
156 return null;
157 }
158 }
159 }
160
161
162
163
164
165
166
167
168 public void endLoadingCollections(CollectionPersister persister) {
169 SessionImplementor session = getLoadContext().getPersistenceContext().getSession();
170 if ( !loadContexts.hasLoadingCollectionEntries()
171 && localLoadingCollectionKeys.isEmpty() ) {
172 return;
173 }
174
175
176
177
178
179
180
181 List matches = null;
182 Iterator iter = localLoadingCollectionKeys.iterator();
183 while ( iter.hasNext() ) {
184 final CollectionKey collectionKey = (CollectionKey) iter.next();
185 final LoadingCollectionEntry lce = loadContexts.locateLoadingCollectionEntry( collectionKey );
186 if ( lce == null) {
187 log.warn( "In CollectionLoadContext#endLoadingCollections, localLoadingCollectionKeys contained [" + collectionKey + "], but no LoadingCollectionEntry was found in loadContexts" );
188 }
189 else if ( lce.getResultSet() == resultSet && lce.getPersister() == persister ) {
190 if ( matches == null ) {
191 matches = new ArrayList();
192 }
193 matches.add( lce );
194 if ( lce.getCollection().getOwner() == null ) {
195 session.getPersistenceContext().addUnownedCollection(
196 new CollectionKey( persister, lce.getKey(), session.getEntityMode() ),
197 lce.getCollection()
198 );
199 }
200 if ( log.isTraceEnabled() ) {
201 log.trace( "removing collection load entry [" + lce + "]" );
202 }
203
204
205 loadContexts.unregisterLoadingCollectionXRef( collectionKey );
206 iter.remove();
207 }
208 }
209
210 endLoadingCollections( persister, matches );
211 if ( localLoadingCollectionKeys.isEmpty() ) {
212
213
214
215
216
217
218 loadContexts.cleanup( resultSet );
219 }
220 }
221
222 private void endLoadingCollections(CollectionPersister persister, List matchedCollectionEntries) {
223 if ( matchedCollectionEntries == null ) {
224 if ( log.isDebugEnabled() ) {
225 log.debug( "no collections were found in result set for role: " + persister.getRole() );
226 }
227 return;
228 }
229
230 final int count = matchedCollectionEntries.size();
231 if ( log.isDebugEnabled() ) {
232 log.debug( count + " collections were found in result set for role: " + persister.getRole() );
233 }
234
235 for ( int i = 0; i < count; i++ ) {
236 LoadingCollectionEntry lce = ( LoadingCollectionEntry ) matchedCollectionEntries.get( i );
237 endLoadingCollection( lce, persister );
238 }
239
240 if ( log.isDebugEnabled() ) {
241 log.debug( count + " collections initialized for role: " + persister.getRole() );
242 }
243 }
244
245 private void endLoadingCollection(LoadingCollectionEntry lce, CollectionPersister persister) {
246 if ( log.isTraceEnabled() ) {
247 log.debug( "ending loading collection [" + lce + "]" );
248 }
249 final SessionImplementor session = getLoadContext().getPersistenceContext().getSession();
250 final EntityMode em = session.getEntityMode();
251
252 boolean hasNoQueuedAdds = lce.getCollection().endRead();
253
254 if ( persister.getCollectionType().hasHolder( em ) ) {
255 getLoadContext().getPersistenceContext().addCollectionHolder( lce.getCollection() );
256 }
257
258 CollectionEntry ce = getLoadContext().getPersistenceContext().getCollectionEntry( lce.getCollection() );
259 if ( ce == null ) {
260 ce = getLoadContext().getPersistenceContext().addInitializedCollection( persister, lce.getCollection(), lce.getKey() );
261 }
262 else {
263 ce.postInitialize( lce.getCollection() );
264 }
265
266 boolean addToCache = hasNoQueuedAdds &&
267 persister.hasCache() &&
268 session.getCacheMode().isPutEnabled() &&
269 !ce.isDoremove();
270 if ( addToCache ) {
271 addCollectionToCache( lce, persister );
272 }
273
274 if ( log.isDebugEnabled() ) {
275 log.debug( "collection fully initialized: " + MessageHelper.collectionInfoString(persister, lce.getKey(), session.getFactory() ) );
276 }
277
278 if ( session.getFactory().getStatistics().isStatisticsEnabled() ) {
279 session.getFactory().getStatisticsImplementor().loadCollection( persister.getRole() );
280 }
281 }
282
283
284
285
286
287
288
289 private void addCollectionToCache(LoadingCollectionEntry lce, CollectionPersister persister) {
290 final SessionImplementor session = getLoadContext().getPersistenceContext().getSession();
291 final SessionFactoryImplementor factory = session.getFactory();
292
293 if ( log.isDebugEnabled() ) {
294 log.debug( "Caching collection: " + MessageHelper.collectionInfoString( persister, lce.getKey(), factory ) );
295 }
296
297 if ( !session.getEnabledFilters().isEmpty() && persister.isAffectedByEnabledFilters( session ) ) {
298
299 log.debug( "Refusing to add to cache due to enabled filters" );
300
301
302
303
304
305 return;
306 }
307
308 final Object version;
309 if ( persister.isVersioned() ) {
310 Object collectionOwner = getLoadContext().getPersistenceContext().getCollectionOwner( lce.getKey(), persister );
311 if ( collectionOwner == null ) {
312
313
314
315
316
317 if ( lce.getCollection() != null ) {
318 Object linkedOwner = lce.getCollection().getOwner();
319 if ( linkedOwner != null ) {
320 final Serializable ownerKey = persister.getOwnerEntityPersister().getIdentifier( linkedOwner, session );
321 collectionOwner = getLoadContext().getPersistenceContext().getCollectionOwner( ownerKey, persister );
322 }
323 }
324 if ( collectionOwner == null ) {
325 throw new HibernateException(
326 "Unable to resolve owner of loading collection [" +
327 MessageHelper.collectionInfoString( persister, lce.getKey(), factory ) +
328 "] for second level caching"
329 );
330 }
331 }
332 version = getLoadContext().getPersistenceContext().getEntry( collectionOwner ).getVersion();
333 }
334 else {
335 version = null;
336 }
337
338 CollectionCacheEntry entry = new CollectionCacheEntry( lce.getCollection(), persister );
339 CacheKey cacheKey = new CacheKey(
340 lce.getKey(),
341 persister.getKeyType(),
342 persister.getRole(),
343 session.getEntityMode(),
344 session.getFactory()
345 );
346 boolean put = persister.getCacheAccessStrategy().putFromLoad(
347 cacheKey,
348 persister.getCacheEntryStructure().structure(entry),
349 session.getTimestamp(),
350 version,
351 factory.getSettings().isMinimalPutsEnabled() && session.getCacheMode()!= CacheMode.REFRESH
352 );
353
354 if ( put && factory.getStatistics().isStatisticsEnabled() ) {
355 factory.getStatisticsImplementor().secondLevelCachePut( persister.getCacheAccessStrategy().getRegion().getName() );
356 }
357 }
358
359 void cleanup() {
360 if ( !localLoadingCollectionKeys.isEmpty() ) {
361 log.warn( "On CollectionLoadContext#cleanup, localLoadingCollectionKeys contained [" + localLoadingCollectionKeys.size() + "] entries" );
362 }
363 loadContexts.cleanupCollectionXRefs( localLoadingCollectionKeys );
364 localLoadingCollectionKeys.clear();
365 }
366
367
368 public String toString() {
369 return super.toString() + "<rs=" + resultSet + ">";
370 }
371 }