Project

General

Profile

Download (42.5 KB) Statistics
| Branch: | Tag: | Revision:
1
/*
2
 * Hibernate, Relational Persistence for Idiomatic Java
3
 *
4
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5
 * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6
 */
7
package org.hibernate.collection.internal;
8

    
9
import java.io.Serializable;
10
import java.lang.reflect.Field;
11
import java.util.ArrayList;
12
import java.util.Collection;
13
import java.util.Collections;
14
import java.util.HashSet;
15
import java.util.Iterator;
16
import java.util.List;
17
import java.util.ListIterator;
18
import java.util.Map;
19

    
20
import org.hibernate.AssertionFailure;
21
import org.hibernate.FlushMode;
22
import org.hibernate.HibernateException;
23
import org.hibernate.LazyInitializationException;
24
import org.hibernate.Session;
25
import org.hibernate.collection.spi.PersistentCollection;
26
import org.hibernate.engine.internal.ForeignKeys;
27
import org.hibernate.engine.spi.CollectionEntry;
28
import org.hibernate.engine.spi.EntityEntry;
29
import org.hibernate.engine.spi.PersistenceContext;
30
import org.hibernate.engine.spi.SessionFactoryImplementor;
31
import org.hibernate.engine.spi.SessionImplementor;
32
import org.hibernate.engine.spi.SharedSessionContractImplementor;
33
import org.hibernate.engine.spi.Status;
34
import org.hibernate.engine.spi.TypedValue;
35
import org.hibernate.internal.CoreLogging;
36
import org.hibernate.internal.CoreMessageLogger;
37
import org.hibernate.internal.SessionFactoryRegistry;
38
import org.hibernate.internal.util.MarkerObject;
39
import org.hibernate.internal.util.collections.IdentitySet;
40
import org.hibernate.persister.collection.CollectionPersister;
41
import org.hibernate.persister.entity.EntityPersister;
42
import org.hibernate.pretty.MessageHelper;
43
import org.hibernate.resource.transaction.spi.TransactionStatus;
44
import org.hibernate.type.CompositeType;
45
import org.hibernate.type.IntegerType;
46
import org.hibernate.type.LongType;
47
import org.hibernate.type.PostgresUUIDType;
48
import org.hibernate.type.StringType;
49
import org.hibernate.type.Type;
50
import org.hibernate.type.UUIDBinaryType;
51
import org.hibernate.type.UUIDCharType;
52

    
53
import eu.etaxonomy.cdm.api.application.CdmApplicationRemoteConfiguration;
54
import eu.etaxonomy.cdm.cache.ProxyUtils;
55
import eu.etaxonomy.cdm.model.common.CdmBase;
56
import eu.etaxonomy.taxeditor.remoting.CdmEagerLoadingException;
57
import eu.etaxonomy.taxeditor.service.ICachedCommonService;
58

    
59
/**
60
 * Base class implementing {@link org.hibernate.collection.spi.PersistentCollection}
61
 *
62
 * This is an extended copy of the original class from hibernate. It has been extended to
63
 * allow making remote service calls to spring httpinvoker services (see section at the bottom
64
 * of this class).
65
 *
66
 * NOTE: For updating this class to the latest hibernate version, update the serialVersionUID as
67
 *       described above, copy the new class to the old class BUT keep those 5 places marked with
68
 *       ##REMOTING-KEEP##
69
 *
70
 * @author Gavin King
71
 * @author Cherian Mathew
72
 */
73
public abstract class AbstractPersistentCollection implements Serializable, PersistentCollection {
74
	private static final CoreMessageLogger LOG = CoreLogging.messageLogger( AbstractPersistentCollection.class );
75

    
76
	/**
77
	 * <b>IMPORTANT:</b><br>
78
	 * This serialVersionUID must be kept in sync with the serialVersionUID which is generated
79
	 * on the fly for serialized AbstractPersistentCollection objects coming from the httpInvoker
80
	 * service.
81
	 * This is most probably necessary after updating hibernate to a newer version. In any case
82
	 * it the need for updating this <code>serialVersionUID</code> becomes obvious when the attempt
83
	 * to connect to the server side fails with an  <code>InvalidClassException</code>:
84
	 *
85
	 * <pre>
86
	 * java.io.InvalidClassException: org.hibernate.collection.internal.AbstractPersistentCollection;
87
	 * local class incompatible:
88
	 * stream classdesc serialVersionUID = 2742261122392386159,
89
	 * local class serialVersionUID = -7238232378593030571
90
	 * </pre>
91
	 * The correct <code>serialVersionUID</code> is the <code>stream classdesc serialVersionUID</code>
92
	 * from the error message.
93
	 */
94
	private static final long serialVersionUID = 6275967693128102740L;
95

    
96
	private transient SharedSessionContractImplementor session;
97
	private boolean isTempSession = false;
98
	private boolean initialized;
99
	private transient List<DelayedOperation> operationQueue;
100
	private transient boolean directlyAccessible;
101
	private transient boolean initializing;
102
	private Object owner;
103
	private int cachedSize = -1;
104

    
105
	private String role;
106
	private Serializable key;
107
	// collections detect changes made via their public interface and mark
108
	// themselves as dirty as a performance optimization
109
	private boolean dirty;
110
	protected boolean elementRemoved;
111
	private Serializable storedSnapshot;
112

    
113
	private String sessionFactoryUuid;
114
	private boolean allowLoadOutsideTransaction;
115

    
116
	/**
117
	 * Not called by Hibernate, but used by non-JDK serialization,
118
	 * eg. SOAP libraries.
119
	 */
120
	public AbstractPersistentCollection() {
121
	}
122

    
123
	protected AbstractPersistentCollection(SharedSessionContractImplementor session) {
124
		this.session = session;
125
	}
126

    
127
	/**
128
	 * @deprecated {@link #AbstractPersistentCollection(SharedSessionContractImplementor)} should be used instead.
129
	 */
130
	@Deprecated
131
	protected AbstractPersistentCollection(SessionImplementor session) {
132
		this( (SharedSessionContractImplementor) session );
133
	}
134

    
135
	@Override
136
	public final String getRole() {
137
		return role;
138
	}
139

    
140
	@Override
141
	public final Serializable getKey() {
142
		return key;
143
	}
144

    
145
	@Override
146
	public final boolean isUnreferenced() {
147
		return role == null;
148
	}
149

    
150
	@Override
151
	public final boolean isDirty() {
152
		return dirty;
153
	}
154

    
155
	@Override
156
	public boolean isElementRemoved() {
157
		return elementRemoved;
158
	}
159

    
160
	@Override
161
	public final void clearDirty() {
162
		dirty = false;
163
		elementRemoved = false;
164
	}
165

    
166
	@Override
167
	public final void dirty() {
168
		dirty = true;
169
	}
170

    
171
	@Override
172
	public final Serializable getStoredSnapshot() {
173
		return storedSnapshot;
174
	}
175

    
176
	//Careful: these methods do not initialize the collection.
177

    
178
	@Override
179
	public abstract boolean empty();
180

    
181
	/**
182
	 * Called by any read-only method of the collection interface
183
	 */
184
	protected final void read() {
185
		initialize( false );
186
	}
187

    
188
	/**
189
	 * Called by the {@link Collection#size} method
190
	 */
191
	@SuppressWarnings({"JavaDoc"})
192
	protected boolean readSize() {
193
		if ( !initialized ) {
194
			if ( cachedSize != -1 && !hasQueuedOperations() ) {
195
				return true;
196
			}
197
			else {
198
				//##REMOTING-KEEP##
199
				// In remoting we are sure that session is null
200
				// both when using property paths and switching off conversations
201
				if(session == null && remoting) {
202
					LOG.info("--> readSize, of " + getRole() + " with key " + getKey());
203
					read();
204
				} else {
205
			    //keep formatting below to ease update to newer hibernate version
206
				//##REMOTING-KEEP END##
207
				final boolean isExtraLazy = withTemporarySessionIfNeeded(
208
						new LazyInitializationWork<Boolean>() {
209
							@Override
210
							public Boolean doWork() {
211
								final CollectionEntry entry = session.getPersistenceContextInternal().getCollectionEntry( AbstractPersistentCollection.this );
212

    
213
								if ( entry != null ) {
214
									final CollectionPersister persister = entry.getLoadedPersister();
215
									if ( persister.isExtraLazy() ) {
216
										if ( hasQueuedOperations() ) {
217
											session.flush();
218
										}
219
										cachedSize = persister.getSize( entry.getLoadedKey(), session );
220
										return true;
221
									}
222
									else {
223
										read();
224
									}
225
								}
226
								else{
227
									throwLazyInitializationExceptionIfNotConnected();
228
								}
229
								return false;
230
							}
231
						}
232
				);
233
				if ( isExtraLazy ) {
234
					return true;
235
				}
236
				}
237
			}
238
		}
239
		return false;
240
	}
241

    
242
	/**
243
	 * TBH not sure why this is public
244
	 *
245
	 * @param <T> The java type of the return for this LazyInitializationWork
246
	 */
247
	public static interface LazyInitializationWork<T> {
248
		/**
249
		 * Do the represented work and return the result.
250
		 *
251
		 * @return The result
252
		 */
253
		public T doWork();
254
	}
255

    
256
	private <T> T withTemporarySessionIfNeeded(LazyInitializationWork<T> lazyInitializationWork) {
257
		SharedSessionContractImplementor tempSession = null;
258

    
259
		if ( session == null ) {
260
			if ( allowLoadOutsideTransaction ) {
261
				tempSession = openTemporarySessionForLoading();
262
			}
263
			else {
264
				throwLazyInitializationException( "could not initialize proxy - no Session" );
265
			}
266
		}
267
		else if ( !session.isOpenOrWaitingForAutoClose() ) {
268
			if ( allowLoadOutsideTransaction ) {
269
				tempSession = openTemporarySessionForLoading();
270
			}
271
			else {
272
				throwLazyInitializationException( "could not initialize proxy - the owning Session was closed" );
273
			}
274
		}
275
		else if ( !session.isConnected() ) {
276
			if ( allowLoadOutsideTransaction ) {
277
				tempSession = openTemporarySessionForLoading();
278
			}
279
			else {
280
				throwLazyInitializationException( "could not initialize proxy - the owning Session is disconnected" );
281
			}
282
		}
283

    
284
		SharedSessionContractImplementor originalSession = null;
285
		boolean isJTA = false;
286

    
287
		if ( tempSession != null ) {
288
			isTempSession = true;
289
			originalSession = session;
290
			session = tempSession;
291

    
292
			isJTA = session.getTransactionCoordinator().getTransactionCoordinatorBuilder().isJta();
293

    
294
			if ( !isJTA ) {
295
				// Explicitly handle the transactions only if we're not in
296
				// a JTA environment.  A lazy loading temporary session can
297
				// be created even if a current session and transaction are
298
				// open (ex: session.clear() was used).  We must prevent
299
				// multiple transactions.
300
				( (Session) session ).beginTransaction();
301
			}
302

    
303
			session.getPersistenceContextInternal().addUninitializedDetachedCollection(
304
					session.getFactory().getCollectionPersister( getRole() ),
305
					this
306
			);
307
		}
308

    
309
		try {
310
			return lazyInitializationWork.doWork();
311
		}
312
		finally {
313
			if ( tempSession != null ) {
314
				// make sure the just opened temp session gets closed!
315
				isTempSession = false;
316
				session = originalSession;
317

    
318
				try {
319
					if ( !isJTA ) {
320
						( (Session) tempSession ).getTransaction().commit();
321
					}
322
					( (Session) tempSession ).close();
323
				}
324
				catch (Exception e) {
325
					LOG.warn( "Unable to close temporary session used to load lazy collection associated to no session" );
326
				}
327
			}
328
		}
329
	}
330

    
331
	private SharedSessionContractImplementor openTemporarySessionForLoading() {
332
		if ( sessionFactoryUuid == null ) {
333
			throwLazyInitializationException( "SessionFactory UUID not known to create temporary Session for loading" );
334
		}
335

    
336
		final SessionFactoryImplementor sf = (SessionFactoryImplementor)
337
				SessionFactoryRegistry.INSTANCE.getSessionFactory( sessionFactoryUuid );
338
		final SharedSessionContractImplementor session = (SharedSessionContractImplementor) sf.openSession();
339
		session.getPersistenceContextInternal().setDefaultReadOnly( true );
340
		session.setFlushMode( FlushMode.MANUAL );
341
		return session;
342
	}
343

    
344
	protected Boolean readIndexExistence(final Object index) {
345
		if ( !initialized ) {
346
			//##REMOTING-KEEP##
347
			// In remoting we are sure that session is null
348
			// both when using property paths and switching off conversations
349
			if(session == null && remoting) {
350
				LOG.info("--> readIndexExistence, of " + getRole() + " with key " + getKey());
351
				read();
352
			} else {
353
		    //keep formatting below to ease update to newer hibernate version
354
			//##REMOTING-KEEP END##
355
			final Boolean extraLazyExistenceCheck = withTemporarySessionIfNeeded(
356
					new LazyInitializationWork<Boolean>() {
357
						@Override
358
						public Boolean doWork() {
359
							final CollectionEntry entry = session.getPersistenceContextInternal().getCollectionEntry( AbstractPersistentCollection.this );
360
							final CollectionPersister persister = entry.getLoadedPersister();
361
							if ( persister.isExtraLazy() ) {
362
								if ( hasQueuedOperations() ) {
363
									session.flush();
364
								}
365
								return persister.indexExists( entry.getLoadedKey(), index, session );
366
							}
367
							else {
368
								read();
369
							}
370
							return null;
371
						}
372
					}
373
			);
374
			if ( extraLazyExistenceCheck != null ) {
375
				return extraLazyExistenceCheck;
376
			}
377
			}
378
		}
379
		return null;
380
	}
381

    
382
	protected Boolean readElementExistence(final Object element) {
383
		if ( !initialized ) {
384
			//##REMOTING-KEEP##
385
			// In remoting we are sure that session is null
386
			// both when using property paths and switching off conversations
387
			if(session == null && remoting) {
388
				LOG.info("--> readElementExistence, of " + getRole() + " with key " + getKey());
389
				read();
390

    
391
			} else {
392
		    //keep formatting below to ease update to newer hibernate version
393
			//##REMOTING-KEEP END##
394
			final Boolean extraLazyExistenceCheck = withTemporarySessionIfNeeded(
395
					new LazyInitializationWork<Boolean>() {
396
						@Override
397
						public Boolean doWork() {
398
							final CollectionEntry entry = session.getPersistenceContextInternal().getCollectionEntry( AbstractPersistentCollection.this );
399
							final CollectionPersister persister = entry.getLoadedPersister();
400
							if ( persister.isExtraLazy() ) {
401
								if ( hasQueuedOperations() ) {
402
									session.flush();
403
								}
404
								return persister.elementExists( entry.getLoadedKey(), element, session );
405
							}
406
							else {
407
								read();
408
							}
409
							return null;
410
						}
411
					}
412
			);
413
			if ( extraLazyExistenceCheck != null ) {
414
				return extraLazyExistenceCheck;
415
			}
416
			}
417
		}
418
		return null;
419
	}
420

    
421
	protected static final Object UNKNOWN = new MarkerObject( "UNKNOWN" );
422

    
423
	protected Object readElementByIndex(final Object index) {
424
		if ( !initialized ) {
425
			//##REMOTING-KEEP##
426
			// In remoting we are sure that session is null
427
			// both when using property paths and switching off conversations
428
			if(session == null && remoting) {
429
				LOG.info("--> readElementByIndex, of " + getRole() + " with key " + getKey());
430
				read();
431

    
432
			} else {
433
		    //keep formatting below to ease update to newer hibernate version
434
			//##REMOTING-KEEP END##
435
			class ExtraLazyElementByIndexReader implements LazyInitializationWork {
436
				private boolean isExtraLazy;
437
				private Object element;
438

    
439
				@Override
440
				public Object doWork() {
441
					final CollectionEntry entry = session.getPersistenceContextInternal().getCollectionEntry( AbstractPersistentCollection.this );
442
					final CollectionPersister persister = entry.getLoadedPersister();
443
					isExtraLazy = persister.isExtraLazy();
444
					if ( isExtraLazy ) {
445
						if ( hasQueuedOperations() ) {
446
							session.flush();
447
						}
448
						element = persister.getElementByIndex( entry.getLoadedKey(), index, session, owner );
449
					}
450
					else {
451
						read();
452
					}
453
					return null;
454
				}
455
			}
456

    
457
			final ExtraLazyElementByIndexReader reader = new ExtraLazyElementByIndexReader();
458
			//noinspection unchecked
459
			withTemporarySessionIfNeeded( reader );
460
			if ( reader.isExtraLazy ) {
461
				return reader.element;
462
			}
463
			}
464
		}
465
		return UNKNOWN;
466

    
467
	}
468

    
469
	protected int getCachedSize() {
470
		return cachedSize;
471
	}
472

    
473
	protected boolean isConnectedToSession() {
474
		return session != null
475
				&& session.isOpen()
476
				&& session.getPersistenceContextInternal().containsCollection( this );
477
	}
478

    
479
	protected boolean isInitialized() {
480
		return initialized;
481
	}
482

    
483
	/**
484
	 * Called by any writer method of the collection interface
485
	 */
486
	protected final void write() {
487
		initialize( true );
488
		dirty();
489
	}
490

    
491
	/**
492
	 * Is this collection in a state that would allow us to
493
	 * "queue" operations?
494
	 */
495
	@SuppressWarnings({"JavaDoc"})
496
	protected boolean isOperationQueueEnabled() {
497
		return !initialized
498
				&& isConnectedToSession()
499
				&& isInverseCollection();
500
	}
501

    
502
	/**
503
	 * Is this collection in a state that would allow us to
504
	 * "queue" puts? This is a special case, because of orphan
505
	 * delete.
506
	 */
507
	@SuppressWarnings({"JavaDoc"})
508
	protected boolean isPutQueueEnabled() {
509
		return !initialized
510
				&& isConnectedToSession()
511
				&& isInverseOneToManyOrNoOrphanDelete();
512
	}
513

    
514
	/**
515
	 * Is this collection in a state that would allow us to
516
	 * "queue" clear? This is a special case, because of orphan
517
	 * delete.
518
	 */
519
	@SuppressWarnings({"JavaDoc"})
520
	protected boolean isClearQueueEnabled() {
521
		return !initialized
522
				&& isConnectedToSession()
523
				&& isInverseCollectionNoOrphanDelete();
524
	}
525

    
526
	/**
527
	 * Is this the "inverse" end of a bidirectional association?
528
	 */
529
	@SuppressWarnings({"JavaDoc"})
530
	protected boolean isInverseCollection() {
531
		final CollectionEntry ce = session.getPersistenceContextInternal().getCollectionEntry( this );
532
		return ce != null && ce.getLoadedPersister().isInverse();
533
	}
534

    
535
	/**
536
	 * Is this the "inverse" end of a bidirectional association with
537
	 * no orphan delete enabled?
538
	 */
539
	@SuppressWarnings({"JavaDoc"})
540
	protected boolean isInverseCollectionNoOrphanDelete() {
541
		final CollectionEntry ce = session.getPersistenceContextInternal().getCollectionEntry( this );
542
		if ( ce == null ) {
543
			return false;
544
		}
545
		final CollectionPersister loadedPersister = ce.getLoadedPersister();
546
		return loadedPersister.isInverse() && !loadedPersister.hasOrphanDelete();
547
	}
548

    
549
	/**
550
	 * Is this the "inverse" end of a bidirectional one-to-many, or
551
	 * of a collection with no orphan delete?
552
	 */
553
	@SuppressWarnings({"JavaDoc"})
554
	protected boolean isInverseOneToManyOrNoOrphanDelete() {
555
		final CollectionEntry ce = session.getPersistenceContextInternal().getCollectionEntry( this );
556
		if ( ce == null ) {
557
			return false;
558
		}
559
		final CollectionPersister loadedPersister = ce.getLoadedPersister();
560
		return loadedPersister.isInverse() && ( loadedPersister.isOneToMany() || !loadedPersister.hasOrphanDelete() );
561
	}
562

    
563
	/**
564
	 * Queue an addition
565
	 */
566
	@SuppressWarnings({"JavaDoc"})
567
	protected final void queueOperation(DelayedOperation operation) {
568
		if ( operationQueue == null ) {
569
			operationQueue = new ArrayList<DelayedOperation>( 10 );
570
		}
571
		operationQueue.add( operation );
572
		//needed so that we remove this collection from the second-level cache
573
		dirty = true;
574
	}
575

    
576
	/**
577
	 * Replace entity instances with copy in {@code copyCache}/.
578
	 *
579
	 * @param copyCache - mapping from entity in the process of being
580
	 *                    merged to managed copy.
581
	 */
582
	public final void replaceQueuedOperationValues(CollectionPersister persister, Map copyCache) {
583
		for ( DelayedOperation operation : operationQueue ) {
584
			if ( ValueDelayedOperation.class.isInstance( operation ) ) {
585
				( (ValueDelayedOperation) operation ).replace( persister, copyCache );
586
			}
587
		}
588
	}
589

    
590
	/**
591
	 * After reading all existing elements from the database,
592
	 * add the queued elements to the underlying collection.
593
	 */
594
	protected final void performQueuedOperations() {
595
		for ( DelayedOperation operation : operationQueue ) {
596
			operation.operate();
597
		}
598
		clearOperationQueue();
599
	}
600

    
601
	@Override
602
	public void setSnapshot(Serializable key, String role, Serializable snapshot) {
603
		this.key = key;
604
		this.role = role;
605
		this.storedSnapshot = snapshot;
606
	}
607

    
608
	@Override
609
	public void postAction() {
610
		clearOperationQueue();
611
		cachedSize = -1;
612
		clearDirty();
613
	}
614

    
615
	public final void clearOperationQueue() {
616
		operationQueue = null;
617
	}
618

    
619
	@Override
620
	public Object getValue() {
621
		return this;
622
	}
623

    
624
	@Override
625
	public void beginRead() {
626
		// override on some subclasses
627
		initializing = true;
628
	}
629

    
630
	@Override
631
	public boolean endRead() {
632
		//override on some subclasses
633
		return afterInitialize();
634
	}
635

    
636
	@Override
637
	public boolean afterInitialize() {
638
		setInitialized();
639
		//do this bit after setting initialized to true or it will recurse
640
		if ( hasQueuedOperations() ) {
641
			performQueuedOperations();
642
			cachedSize = -1;
643
			return false;
644
		}
645
		else {
646
			return true;
647
		}
648
	}
649

    
650
	/**
651
	 * Initialize the collection, if possible, wrapping any exceptions
652
	 * in a runtime exception
653
	 *
654
	 * @param writing currently obsolete
655
	 *
656
	 * @throws LazyInitializationException if we cannot initialize
657
	 */
658
	protected final void initialize(final boolean writing) {
659
		if ( initialized ) {
660
			return;
661
		}
662
		//##REMOTING-KEEP##
663
	    // In remoting we are sure that session is null
664
	    // both when using property paths and switching off conversations
665
	    if(session == null && remoting) {
666
	        remoteInitialize();
667
	    } else {
668
	    //keep formatting below to ease update to newer hibernate version
669
		//##REMOTING-KEEP END##
670
	    withTemporarySessionIfNeeded(
671
				new LazyInitializationWork<Object>() {
672
					@Override
673
					public Object doWork() {
674
						session.initializeCollection( AbstractPersistentCollection.this, writing );
675
						return null;
676
					}
677
				}
678
		);
679
	    }
680
	}
681

    
682
	private void throwLazyInitializationExceptionIfNotConnected() {
683
		if ( !isConnectedToSession() ) {
684
			throwLazyInitializationException( "no session or session was closed" );
685
		}
686
		if ( !session.isConnected() ) {
687
			throwLazyInitializationException( "session is disconnected" );
688
		}
689
	}
690

    
691
	private void throwLazyInitializationException(String message) {
692
		throw new LazyInitializationException(
693
				"failed to lazily initialize a collection" +
694
						(role == null ? "" : " of role: " + role) +
695
						", " + message
696
		);
697
	}
698

    
699
	protected final void setInitialized() {
700
		this.initializing = false;
701
		this.initialized = true;
702
	}
703

    
704
	protected final void setDirectlyAccessible(boolean directlyAccessible) {
705
		this.directlyAccessible = directlyAccessible;
706
	}
707

    
708
	@Override
709
	public boolean isDirectlyAccessible() {
710
		return directlyAccessible;
711
	}
712

    
713
	@Override
714
	public final boolean unsetSession(SharedSessionContractImplementor currentSession) {
715
		prepareForPossibleLoadingOutsideTransaction();
716
		if ( currentSession == this.session ) {
717
			if ( !isTempSession ) {
718
				if ( hasQueuedOperations() ) {
719
					final String collectionInfoString = MessageHelper.collectionInfoString( getRole(), getKey() );
720
					try {
721
						final TransactionStatus transactionStatus =
722
								session.getTransactionCoordinator().getTransactionDriverControl().getStatus();
723
						if ( transactionStatus.isOneOf(
724
								TransactionStatus.ROLLED_BACK,
725
								TransactionStatus.MARKED_ROLLBACK,
726
								TransactionStatus.FAILED_COMMIT,
727
								TransactionStatus.FAILED_ROLLBACK,
728
								TransactionStatus.ROLLING_BACK
729
						) ) {
730
							// It was due to a rollback.
731
							LOG.queuedOperationWhenDetachFromSessionOnRollback( collectionInfoString );
732
						}
733
						else {
734
							// We don't know why the collection is being detached.
735
							// Just log the info.
736
							LOG.queuedOperationWhenDetachFromSession( collectionInfoString );
737
						}
738
					}
739
					catch (Exception e) {
740
						// We don't know why the collection is being detached.
741
						// Just log the info.
742
						LOG.queuedOperationWhenDetachFromSession( collectionInfoString );
743
					}
744
				}
745
				if ( allowLoadOutsideTransaction && !initialized && session.getLoadQueryInfluencers().hasEnabledFilters() ) {
746
					final String collectionInfoString = MessageHelper.collectionInfoString( getRole(), getKey() );
747
					LOG.enabledFiltersWhenDetachFromSession( collectionInfoString );
748
				}
749
				this.session = null;
750
			}
751
			return true;
752
		}
753
		else {
754
			if ( this.session != null ) {
755
				LOG.logCannotUnsetUnexpectedSessionInCollection( generateUnexpectedSessionStateMessage( currentSession ) );
756
			}
757
			return false;
758
		}
759
	}
760

    
761
	protected void prepareForPossibleLoadingOutsideTransaction() {
762
		if ( session != null ) {
763
			allowLoadOutsideTransaction = session.getFactory().getSessionFactoryOptions().isInitializeLazyStateOutsideTransactionsEnabled();
764

    
765
			if ( allowLoadOutsideTransaction && sessionFactoryUuid == null ) {
766
				sessionFactoryUuid = session.getFactory().getUuid();
767
			}
768
		}
769
	}
770

    
771
	@Override
772
	public final boolean setCurrentSession(SharedSessionContractImplementor session) throws HibernateException {
773
		if ( session == this.session ) {
774
			return false;
775
		}
776
		else if ( this.session != null ) {
777
			final String msg = generateUnexpectedSessionStateMessage( session );
778
			if ( isConnectedToSession() ) {
779
				throw new HibernateException(
780
						"Illegal attempt to associate a collection with two open sessions. " + msg
781
				);
782
			}
783
			else {
784
				LOG.logUnexpectedSessionInCollectionNotConnected( msg );
785
			}
786
		}
787
		if ( hasQueuedOperations() ) {
788
			LOG.queuedOperationWhenAttachToSession( MessageHelper.collectionInfoString( getRole(), getKey() ) );
789
		}
790
		this.session = session;
791
		return true;
792
	}
793

    
794
	private String generateUnexpectedSessionStateMessage(SharedSessionContractImplementor session) {
795
		// NOTE: If this.session != null, this.session may be operating on this collection
796
		// (e.g., by changing this.role, this.key, or even this.session) in a different thread.
797

    
798
		// Grab the current role and key (it can still get changed by this.session...)
799
		// If this collection is connected to this.session, then this.role and this.key should
800
		// be consistent with the CollectionEntry in this.session (as long as this.session doesn't
801
		// change it). Don't access the CollectionEntry in this.session because that could result
802
		// in multi-threaded access to this.session.
803
		final String roleCurrent = role;
804
		final Serializable keyCurrent = key;
805

    
806
		final StringBuilder sb = new StringBuilder( "Collection : " );
807
		if ( roleCurrent != null ) {
808
			sb.append( MessageHelper.collectionInfoString( roleCurrent, keyCurrent ) );
809
		}
810
		else {
811
			final CollectionEntry ce = session.getPersistenceContextInternal().getCollectionEntry( this );
812
			if ( ce != null ) {
813
				sb.append(
814
						MessageHelper.collectionInfoString(
815
								ce.getLoadedPersister(),
816
								this,
817
								ce.getLoadedKey(),
818
								session
819
						)
820
				);
821
			}
822
			else {
823
				sb.append( "<unknown>" );
824
			}
825
		}
826
		// only include the collection contents if debug logging
827
		if ( LOG.isDebugEnabled() ) {
828
			final String collectionContents = wasInitialized() ? toString() : "<uninitialized>";
829
			sb.append( "\nCollection contents: [" ).append( collectionContents ).append( "]" );
830
		}
831
		return sb.toString();
832
	}
833

    
834
	@Override
835
	public boolean needsRecreate(CollectionPersister persister) {
836
		// Workaround for situations like HHH-7072.  If the collection element is a component that consists entirely
837
		// of nullable properties, we currently have to forcefully recreate the entire collection.  See the use
838
		// of hasNotNullableColumns in the AbstractCollectionPersister constructor for more info.  In order to delete
839
		// row-by-row, that would require SQL like "WHERE ( COL = ? OR ( COL is null AND ? is null ) )", rather than
840
		// the current "WHERE COL = ?" (fails for null for most DBs).  Note that
841
		// the param would have to be bound twice.  Until we eventually add "parameter bind points" concepts to the
842
		// AST in ORM 5+, handling this type of condition is either extremely difficult or impossible.  Forcing
843
		// recreation isn't ideal, but not really any other option in ORM 4.
844
		// Selecting a type used in where part of update statement
845
		// (must match condition in org.hibernate.persister.collection.BasicCollectionPersister#doUpdateRows).
846
		// See HHH-9474
847
		Type whereType;
848
		if ( persister.hasIndex() ) {
849
			whereType = persister.getIndexType();
850
		}
851
		else {
852
			whereType = persister.getElementType();
853
		}
854
		if ( whereType instanceof CompositeType ) {
855
			CompositeType componentIndexType = (CompositeType) whereType;
856
			return !componentIndexType.hasNotNullProperty();
857
		}
858
		return false;
859
	}
860

    
861
	@Override
862
	public final void forceInitialization() throws HibernateException {
863
		if ( !initialized ) {
864
			if ( initializing ) {
865
				throw new AssertionFailure( "force initialize loading collection" );
866
			}
867
			initialize( false );
868
		}
869
	}
870

    
871

    
872
	/**
873
	 * Get the current snapshot from the session
874
	 */
875
	@SuppressWarnings({"JavaDoc"})
876
	protected final Serializable getSnapshot() {
877
		return session.getPersistenceContext().getSnapshot( this );
878
	}
879

    
880
	@Override
881
	public final boolean wasInitialized() {
882
		return initialized;
883
	}
884

    
885
	@Override
886
	public boolean isRowUpdatePossible() {
887
		return true;
888
	}
889

    
890
	@Override
891
	public final boolean hasQueuedOperations() {
892
		return operationQueue != null;
893
	}
894

    
895
	@Override
896
	public final Iterator queuedAdditionIterator() {
897
		if ( hasQueuedOperations() ) {
898
			return new Iterator() {
899
				private int index;
900

    
901
				@Override
902
				public Object next() {
903
					return operationQueue.get( index++ ).getAddedInstance();
904
				}
905

    
906
				@Override
907
				public boolean hasNext() {
908
					return index < operationQueue.size();
909
				}
910

    
911
				@Override
912
				public void remove() {
913
					throw new UnsupportedOperationException();
914
				}
915
			};
916
		}
917
		else {
918
			return Collections.emptyIterator();
919
		}
920
	}
921

    
922
	@Override
923
	@SuppressWarnings({"unchecked"})
924
	public final Collection getQueuedOrphans(String entityName) {
925
		if ( hasQueuedOperations() ) {
926
			final Collection additions = new ArrayList( operationQueue.size() );
927
			final Collection removals = new ArrayList( operationQueue.size() );
928
			for ( DelayedOperation operation : operationQueue ) {
929
				additions.add( operation.getAddedInstance() );
930
				removals.add( operation.getOrphan() );
931
			}
932
			return getOrphans( removals, additions, entityName, session );
933
		}
934
		else {
935
			return Collections.EMPTY_LIST;
936
		}
937
	}
938

    
939
	@Override
940
	public void preInsert(CollectionPersister persister) throws HibernateException {
941
	}
942

    
943
	@Override
944
	public void afterRowInsert(CollectionPersister persister, Object entry, int i) throws HibernateException {
945
	}
946

    
947
	@Override
948
	public abstract Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException;
949

    
950
	/**
951
	 * Get the session currently associated with this collection.
952
	 *
953
	 * @return The session
954
	 */
955
	public final SharedSessionContractImplementor getSession() {
956
		return session;
957
	}
958

    
959
	protected final class IteratorProxy implements Iterator {
960
		protected final Iterator itr;
961

    
962
		public IteratorProxy(Iterator itr) {
963
			this.itr = itr;
964
		}
965

    
966
		@Override
967
		public boolean hasNext() {
968
			return itr.hasNext();
969
		}
970

    
971
		@Override
972
		public Object next() {
973
			return itr.next();
974
		}
975

    
976
		@Override
977
		public void remove() {
978
			write();
979
			itr.remove();
980
		}
981
	}
982

    
983
	protected final class ListIteratorProxy implements ListIterator {
984
		protected final ListIterator itr;
985

    
986
		public ListIteratorProxy(ListIterator itr) {
987
			this.itr = itr;
988
		}
989

    
990
		@Override
991
		@SuppressWarnings({"unchecked"})
992
		public void add(Object o) {
993
			write();
994
			itr.add( o );
995
		}
996

    
997
		@Override
998
		public boolean hasNext() {
999
			return itr.hasNext();
1000
		}
1001

    
1002
		@Override
1003
		public boolean hasPrevious() {
1004
			return itr.hasPrevious();
1005
		}
1006

    
1007
		@Override
1008
		public Object next() {
1009
			return itr.next();
1010
		}
1011

    
1012
		@Override
1013
		public int nextIndex() {
1014
			return itr.nextIndex();
1015
		}
1016

    
1017
		@Override
1018
		public Object previous() {
1019
			return itr.previous();
1020
		}
1021

    
1022
		@Override
1023
		public int previousIndex() {
1024
			return itr.previousIndex();
1025
		}
1026

    
1027
		@Override
1028
		public void remove() {
1029
			write();
1030
			itr.remove();
1031
		}
1032

    
1033
		@Override
1034
		@SuppressWarnings({"unchecked"})
1035
		public void set(Object o) {
1036
			write();
1037
			itr.set( o );
1038
		}
1039
	}
1040

    
1041
	protected class SetProxy implements java.util.Set {
1042
		protected final Collection set;
1043

    
1044
		public SetProxy(Collection set) {
1045
			this.set = set;
1046
		}
1047

    
1048
		@Override
1049
		@SuppressWarnings({"unchecked"})
1050
		public boolean add(Object o) {
1051
			write();
1052
			return set.add( o );
1053
		}
1054

    
1055
		@Override
1056
		@SuppressWarnings({"unchecked"})
1057
		public boolean addAll(Collection c) {
1058
			write();
1059
			return set.addAll( c );
1060
		}
1061

    
1062
		@Override
1063
		public void clear() {
1064
			write();
1065
			set.clear();
1066
		}
1067

    
1068
		@Override
1069
		public boolean contains(Object o) {
1070
			return set.contains( o );
1071
		}
1072

    
1073
		@Override
1074
		@SuppressWarnings("unchecked")
1075
		public boolean containsAll(Collection c) {
1076
			return set.containsAll( c );
1077
		}
1078

    
1079
		@Override
1080
		public boolean isEmpty() {
1081
			return set.isEmpty();
1082
		}
1083

    
1084
		@Override
1085
		public Iterator iterator() {
1086
			return new IteratorProxy( set.iterator() );
1087
		}
1088

    
1089
		@Override
1090
		public boolean remove(Object o) {
1091
			write();
1092
			return set.remove( o );
1093
		}
1094

    
1095
		@Override
1096
		@SuppressWarnings("unchecked")
1097
		public boolean removeAll(Collection c) {
1098
			write();
1099
			return set.removeAll( c );
1100
		}
1101

    
1102
		@Override
1103
		@SuppressWarnings("unchecked")
1104
		public boolean retainAll(Collection c) {
1105
			write();
1106
			return set.retainAll( c );
1107
		}
1108

    
1109
		@Override
1110
		public int size() {
1111
			return set.size();
1112
		}
1113

    
1114
		@Override
1115
		public Object[] toArray() {
1116
			return set.toArray();
1117
		}
1118

    
1119
		@Override
1120
		@SuppressWarnings({"unchecked"})
1121
		public Object[] toArray(Object[] array) {
1122
			return set.toArray( array );
1123
		}
1124
	}
1125

    
1126
	protected final class ListProxy implements java.util.List {
1127
		protected final List list;
1128

    
1129
		public ListProxy(List list) {
1130
			this.list = list;
1131
		}
1132

    
1133
		@Override
1134
		@SuppressWarnings({"unchecked"})
1135
		public void add(int index, Object value) {
1136
			write();
1137
			list.add( index, value );
1138
		}
1139

    
1140
		@Override
1141
		@SuppressWarnings({"unchecked"})
1142
		public boolean add(Object o) {
1143
			write();
1144
			return list.add( o );
1145
		}
1146

    
1147
		@Override
1148
		@SuppressWarnings({"unchecked"})
1149
		public boolean addAll(Collection c) {
1150
			write();
1151
			return list.addAll( c );
1152
		}
1153

    
1154
		@Override
1155
		@SuppressWarnings({"unchecked"})
1156
		public boolean addAll(int i, Collection c) {
1157
			write();
1158
			return list.addAll( i, c );
1159
		}
1160

    
1161
		@Override
1162
		public void clear() {
1163
			write();
1164
			list.clear();
1165
		}
1166

    
1167
		@Override
1168
		public boolean contains(Object o) {
1169
			return list.contains( o );
1170
		}
1171

    
1172
		@Override
1173
		@SuppressWarnings("unchecked")
1174
		public boolean containsAll(Collection c) {
1175
			return list.containsAll( c );
1176
		}
1177

    
1178
		@Override
1179
		public Object get(int i) {
1180
			return list.get( i );
1181
		}
1182

    
1183
		@Override
1184
		public int indexOf(Object o) {
1185
			return list.indexOf( o );
1186
		}
1187

    
1188
		@Override
1189
		public boolean isEmpty() {
1190
			return list.isEmpty();
1191
		}
1192

    
1193
		@Override
1194
		public Iterator iterator() {
1195
			return new IteratorProxy( list.iterator() );
1196
		}
1197

    
1198
		@Override
1199
		public int lastIndexOf(Object o) {
1200
			return list.lastIndexOf( o );
1201
		}
1202

    
1203
		@Override
1204
		public ListIterator listIterator() {
1205
			return new ListIteratorProxy( list.listIterator() );
1206
		}
1207

    
1208
		@Override
1209
		public ListIterator listIterator(int i) {
1210
			return new ListIteratorProxy( list.listIterator( i ) );
1211
		}
1212

    
1213
		@Override
1214
		public Object remove(int i) {
1215
			write();
1216
			return list.remove( i );
1217
		}
1218

    
1219
		@Override
1220
		public boolean remove(Object o) {
1221
			write();
1222
			return list.remove( o );
1223
		}
1224

    
1225
		@Override
1226
		@SuppressWarnings("unchecked")
1227
		public boolean removeAll(Collection c) {
1228
			write();
1229
			return list.removeAll( c );
1230
		}
1231

    
1232
		@Override
1233
		@SuppressWarnings("unchecked")
1234
		public boolean retainAll(Collection c) {
1235
			write();
1236
			return list.retainAll( c );
1237
		}
1238

    
1239
		@Override
1240
		@SuppressWarnings({"unchecked"})
1241
		public Object set(int i, Object o) {
1242
			write();
1243
			return list.set( i, o );
1244
		}
1245

    
1246
		@Override
1247
		public int size() {
1248
			return list.size();
1249
		}
1250

    
1251
		@Override
1252
		public List subList(int i, int j) {
1253
			return list.subList( i, j );
1254
		}
1255

    
1256
		@Override
1257
		public Object[] toArray() {
1258
			return list.toArray();
1259
		}
1260

    
1261
		@Override
1262
		@SuppressWarnings({"unchecked"})
1263
		public Object[] toArray(Object[] array) {
1264
			return list.toArray( array );
1265
		}
1266

    
1267
	}
1268

    
1269
	/**
1270
	 * Contract for operations which are part of a collection's operation queue.
1271
	 */
1272
	protected interface DelayedOperation {
1273
		public void operate();
1274

    
1275
		public Object getAddedInstance();
1276

    
1277
		public Object getOrphan();
1278
	}
1279

    
1280
	protected interface ValueDelayedOperation extends DelayedOperation {
1281
		void replace(CollectionPersister collectionPersister, Map copyCache);
1282
	}
1283

    
1284
	protected abstract class AbstractValueDelayedOperation implements ValueDelayedOperation {
1285
		private Object addedValue;
1286
		private Object orphan;
1287

    
1288
		protected AbstractValueDelayedOperation(Object addedValue, Object orphan) {
1289
			this.addedValue = addedValue;
1290
			this.orphan = orphan;
1291
		}
1292

    
1293
		@Override
1294
        public void replace(CollectionPersister persister, Map copyCache) {
1295
			if ( addedValue != null ) {
1296
				addedValue = getReplacement( persister.getElementType(), addedValue, copyCache );
1297
			}
1298
		}
1299

    
1300
		protected final Object getReplacement(Type type, Object current, Map copyCache) {
1301
			return type.replace( current, null, session, owner, copyCache );
1302
		}
1303

    
1304
		@Override
1305
		public final Object getAddedInstance() {
1306
			return addedValue;
1307
		}
1308

    
1309
		@Override
1310
		public final Object getOrphan() {
1311
			return orphan;
1312
		}
1313
	}
1314

    
1315
	/**
1316
	 * Given a collection of entity instances that used to
1317
	 * belong to the collection, and a collection of instances
1318
	 * that currently belong, return a collection of orphans
1319
	 */
1320
	@SuppressWarnings({"JavaDoc", "unchecked"})
1321
	protected static Collection getOrphans(
1322
			Collection oldElements,
1323
			Collection currentElements,
1324
			String entityName,
1325
			SharedSessionContractImplementor session) throws HibernateException {
1326

    
1327
		// short-circuit(s)
1328
		if ( currentElements.size() == 0 ) {
1329
			// no new elements, the old list contains only Orphans
1330
			return oldElements;
1331
		}
1332
		if ( oldElements.size() == 0 ) {
1333
			// no old elements, so no Orphans neither
1334
			return oldElements;
1335
		}
1336

    
1337
		final EntityPersister entityPersister = session.getFactory().getEntityPersister( entityName );
1338
		final Type idType = entityPersister.getIdentifierType();
1339
		final boolean useIdDirect = mayUseIdDirect( idType );
1340

    
1341
		// create the collection holding the Orphans
1342
		final Collection res = new ArrayList();
1343

    
1344
		// collect EntityIdentifier(s) of the *current* elements - add them into a HashSet for fast access
1345
		final java.util.Set currentIds = new HashSet();
1346
		final java.util.Set currentSaving = new IdentitySet();
1347
		final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
1348
		for ( Object current : currentElements ) {
1349
			if ( current != null && ForeignKeys.isNotTransient( entityName, current, null, session ) ) {
1350
				final EntityEntry ee = persistenceContext.getEntry( current );
1351
				if ( ee != null && ee.getStatus() == Status.SAVING ) {
1352
					currentSaving.add( current );
1353
				}
1354
				else {
1355
					final Serializable currentId = ForeignKeys.getEntityIdentifierIfNotUnsaved(
1356
							entityName,
1357
							current,
1358
							session
1359
					);
1360
					currentIds.add( useIdDirect ? currentId : new TypedValue( idType, currentId ) );
1361
				}
1362
			}
1363
		}
1364

    
1365
		// iterate over the *old* list
1366
		for ( Object old : oldElements ) {
1367
			if ( !currentSaving.contains( old ) ) {
1368
				final Serializable oldId = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, old, session );
1369
				if ( !currentIds.contains( useIdDirect ? oldId : new TypedValue( idType, oldId ) ) ) {
1370
					res.add( old );
1371
				}
1372
			}
1373
		}
1374

    
1375
		return res;
1376
	}
1377

    
1378
	private static boolean mayUseIdDirect(Type idType) {
1379
		return idType == StringType.INSTANCE
1380
			|| idType == IntegerType.INSTANCE
1381
			|| idType == LongType.INSTANCE
1382
			|| idType == UUIDBinaryType.INSTANCE
1383
			|| idType == UUIDCharType.INSTANCE
1384
			|| idType == PostgresUUIDType.INSTANCE;
1385
	}
1386

    
1387
	/**
1388
	 * Removes entity entries that have an equal identifier with the incoming entity instance
1389
	 *
1390
	 * @param list The list containing the entity instances
1391
	 * @param entityInstance The entity instance to match elements.
1392
	 * @param entityName The entity name
1393
	 * @param session The session
1394
	 */
1395
	public static void identityRemove(
1396
			Collection list,
1397
			Object entityInstance,
1398
			String entityName,
1399
			SharedSessionContractImplementor session) {
1400

    
1401
		if ( entityInstance != null && ForeignKeys.isNotTransient( entityName, entityInstance, null, session ) ) {
1402
			final EntityPersister entityPersister = session.getFactory().getEntityPersister( entityName );
1403
			final Type idType = entityPersister.getIdentifierType();
1404

    
1405
			final Serializable idOfCurrent = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, entityInstance, session );
1406
			final Iterator itr = list.iterator();
1407
			while ( itr.hasNext() ) {
1408
				final Serializable idOfOld = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, itr.next(), session );
1409
				if ( idType.isEqual( idOfCurrent, idOfOld, session.getFactory() ) ) {
1410
					itr.remove();
1411
					break;
1412
				}
1413
			}
1414

    
1415
		}
1416
	}
1417

    
1418
	/**
1419
	 * Removes entity entries that have an equal identifier with the incoming entity instance
1420
	 *
1421
	 * @param list The list containing the entity instances
1422
	 * @param entityInstance The entity instance to match elements.
1423
	 * @param entityName The entity name
1424
	 * @param session The session
1425
	 *
1426
	 * @deprecated {@link #identityRemove(Collection, Object, String, SharedSessionContractImplementor)}
1427
	 *             should be used instead.
1428
	 */
1429
	@Deprecated
1430
	public static void identityRemove(
1431
			Collection list,
1432
			Object entityInstance,
1433
			String entityName,
1434
			SessionImplementor session) {
1435
		identityRemove( list, entityInstance, entityName, (SharedSessionContractImplementor) session );
1436
	}
1437

    
1438
	@Override
1439
	public Object getIdentifier(Object entry, int i) {
1440
		throw new UnsupportedOperationException();
1441
	}
1442

    
1443
	@Override
1444
	public Object getOwner() {
1445
		return owner;
1446
	}
1447

    
1448
	@Override
1449
	public void setOwner(Object owner) {
1450
		this.owner = owner;
1451
	}
1452

    
1453

    
1454
/** ##REMOTING-KEEP## #######################################################
1455

    
1456
    ADDED PART: Below is the section of code which makes remote service calls.
1457
    Keeps this code when upgrading to newer hibernate version. Also keep
1458
    other code marked with ##REMOTING-KEEP## in the following 5 methods:
1459

    
1460
    {@link #initialize(boolean)}
1461
	{@link #readSize()}
1462
	{@link #readIndexExistence(Object)}
1463
	{@link #readElementExistence(Object)}
1464
	{@link #readElementByIndex(Object)}
1465

    
1466
    ######################################################################### */
1467

    
1468
	private static CdmApplicationRemoteConfiguration configuration;
1469
	private static boolean remoting = false;
1470

    
1471
	public static void setConfiguration(CdmApplicationRemoteConfiguration conf) {
1472
	    remoting = true;
1473
		configuration = conf;
1474
	}
1475

    
1476
	private void remoteInitialize() {
1477

    
1478
		if (getOwner() != null && !initialized) {
1479
		    Object collectionType = null;
1480
		    Field field = null;
1481
		    String fieldName = null;
1482
		    Class<?> clazz = null;
1483
		    String codePart = "1";
1484
			try {
1485
				String role = getRole();
1486
				fieldName = role.substring(role.lastIndexOf(".") + 1);
1487
				LOG.info("--> Remote Lazy Initializing Collection " + getRole() + " , owner : " + getOwner().getClass() + "/" + getKey() + " , field : " + fieldName);
1488
				Object owner = getOwner();
1489
				CdmBase cdmBase;
1490
	            codePart = "2";
1491
				if(owner instanceof CdmBase) {
1492
				    cdmBase = (CdmBase)owner;
1493
				} else {
1494
				    throw new HibernateException("Owner of persistent collection is not a cdm entity");
1495
				}
1496
				if(configuration == null) {
1497
					throw new HibernateException("CdmApplicationRemoteConfiguration not initialized (null)");
1498
				}
1499
                codePart = "3";
1500

    
1501
				ICachedCommonService cachedCommonService = configuration.getCachedCommonService();
1502
				if(cachedCommonService == null) {
1503
					throw new HibernateException("commonService not initialized (null)");
1504
				}
1505
                codePart = "4";
1506

    
1507
				//Object obj = ProxyUtils.deproxyIfInitialized(cachedCommonService.initializeCollection(this));
1508
				Object obj = ProxyUtils.deproxyIfInitialized(cachedCommonService.initializeCollection(cdmBase.getUuid(), fieldName));
1509
				if(ProxyUtils.isUninitializedProxy(obj)) {
1510
				    throw new HibernateException("Persistent Collection initialized but is still a proxy");
1511
				}
1512
                codePart = "5";
1513
				afterInitialize();
1514

    
1515
				clazz = getClass();
1516
                codePart = "6";
1517
				if (clazz != null) {
1518
					collectionType = ProxyUtils.getCollectionType(obj, clazz);
1519
	                codePart = "7";
1520
					field = clazz.getDeclaredField(collectionType.toString());
1521
	                codePart = "8";
1522
					field.setAccessible(true);
1523
					field.set(this, obj);
1524
		            codePart = "9";
1525

    
1526
					ProxyUtils.setRoleValueInOwner(owner, role, obj);
1527
				}
1528
			} catch (Exception ex) {
1529
			    String originalMessage = ex.getMessage();
1530
			    String message = originalMessage + ", clazz: " + (clazz == null? "" :clazz.getSimpleName())+ ", field: " + field != null? field.getName(): fieldName + ", collectionType: " + collectionType + ", at code part: " + codePart;
1531
			    throw new CdmEagerLoadingException(message);
1532
			}
1533
		}
1534
	}
1535
    // ##REMOTING-KEEP END##
1536
}
    (1-1/1)