Project

General

Profile

Download (37.3 KB) Statistics
| Branch: | Tag: | Revision:
1

    
2

    
3
/*
4
 * Hibernate, Relational Persistence for Idiomatic Java
5
 *
6
 * Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
7
 * indicated by the @author tags or express copyright attribution
8
 * statements applied by the authors.  All third-party contributions are
9
 * distributed under license by Red Hat Inc.
10
 *
11
 * This copyrighted material is made available to anyone wishing to use, modify,
12
 * copy, or redistribute it subject to the terms and conditions of the GNU
13
 * Lesser General Public License, as published by the Free Software Foundation.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
18
 * for more details.
19
 *
20
 * You should have received a copy of the GNU Lesser General Public License
21
 * along with this distribution; if not, write to:
22
 * Free Software Foundation, Inc.
23
 * 51 Franklin Street, Fifth Floor
24
 * Boston, MA  02110-1301  USA
25
 */
26
package org.hibernate.collection.internal;
27

    
28
import java.io.Serializable;
29
import java.lang.reflect.Field;
30
import java.util.ArrayList;
31
import java.util.Collection;
32
import java.util.Collections;
33
import java.util.HashSet;
34
import java.util.Iterator;
35
import java.util.List;
36
import java.util.ListIterator;
37
import java.util.Map;
38

    
39
import javax.naming.NamingException;
40

    
41
import org.hibernate.AssertionFailure;
42
import org.hibernate.FlushMode;
43
import org.hibernate.HibernateException;
44
import org.hibernate.LazyInitializationException;
45
import org.hibernate.Session;
46
import org.hibernate.collection.internal.AbstractPersistentCollection.DelayedOperation;
47
import org.hibernate.collection.internal.AbstractPersistentCollection.IteratorProxy;
48
import org.hibernate.collection.internal.AbstractPersistentCollection.LazyInitializationWork;
49
import org.hibernate.collection.internal.AbstractPersistentCollection.ListIteratorProxy;
50
import org.hibernate.collection.internal.AbstractPersistentCollection.ValueDelayedOperation;
51
import org.hibernate.collection.spi.PersistentCollection;
52
import org.hibernate.engine.internal.ForeignKeys;
53
import org.hibernate.engine.spi.CollectionEntry;
54
import org.hibernate.engine.spi.EntityEntry;
55
import org.hibernate.engine.spi.SessionFactoryImplementor;
56
import org.hibernate.engine.spi.SessionImplementor;
57
import org.hibernate.engine.spi.Status;
58
import org.hibernate.engine.spi.TypedValue;
59
import org.hibernate.internal.CoreLogging;
60
import org.hibernate.internal.CoreMessageLogger;
61
import org.hibernate.internal.SessionFactoryRegistry;
62
import org.hibernate.internal.util.MarkerObject;
63
import org.hibernate.internal.util.collections.EmptyIterator;
64
import org.hibernate.internal.util.collections.IdentitySet;
65
import org.hibernate.persister.collection.CollectionPersister;
66
import org.hibernate.persister.entity.EntityPersister;
67
import org.hibernate.pretty.MessageHelper;
68
import org.hibernate.type.CompositeType;
69
import org.hibernate.type.IntegerType;
70
import org.hibernate.type.LongType;
71
import org.hibernate.type.PostgresUUIDType;
72
import org.hibernate.type.StringType;
73
import org.hibernate.type.Type;
74
import org.hibernate.type.UUIDBinaryType;
75
import org.hibernate.type.UUIDCharType;
76
import org.jboss.logging.Logger;
77

    
78
import eu.etaxonomy.cdm.api.application.CdmApplicationRemoteConfiguration;
79
import eu.etaxonomy.cdm.cache.ProxyUtils;
80
import eu.etaxonomy.cdm.model.common.CdmBase;
81
import eu.etaxonomy.taxeditor.remoting.CdmEagerLoadingException;
82
import eu.etaxonomy.taxeditor.service.ICachedCommonService;
83

    
84
/**
85
 * Base class implementing {@link org.hibernate.collection.spi.PersistentCollection}
86
 *
87
 * This is an extended copy of the original class from hibernate. It has been extended to
88
 * allow making remote service calls to spring httpinvoker services (see section at the bottom
89
 * of this class).
90
 *
91
 * @author Gavin King
92
 * @author Cherian Mathew
93
 */
94
public abstract class AbstractPersistentCollection implements Serializable, PersistentCollection {
95
	private static final CoreMessageLogger LOG = CoreLogging.messageLogger( AbstractPersistentCollection.class );
96

    
97
	/**
98
	 * <b>IMPORTANT:</b><br>
99
	 * This serialVersionUID must be kept in sync with the serialVersionUID which is generated
100
	 * on the fly for serialized AbstractPersistentCollection objects coming from the httpInvoker
101
	 * service.
102
	 * This is most probably necessary after updating hibernate to a newer version. In any case
103
	 * it the need for updating this <code>serialVersionUID</code> becomes obvious when the attempt
104
	 * to connect to the server side fails with an  <code>InvalidClassException</code>:
105
	 *
106
	 * <pre>
107
	 * java.io.InvalidClassException: org.hibernate.collection.internal.AbstractPersistentCollection;
108
	 * local class incompatible:
109
	 * stream classdesc serialVersionUID = 2742261122392386159,
110
	 * local class serialVersionUID = -7238232378593030571
111
	 * </pre>
112
	 * The correct <code>serialVersionUID</code> is the <code>stream classdesc serialVersionUID</code>
113
	 * from the error message.
114
	 */
115
	private static final long serialVersionUID = 7094296207968006972L;
116

    
117
	private transient SessionImplementor session;
118
	private boolean initialized;
119
	private transient List<DelayedOperation> operationQueue;
120
	private transient boolean directlyAccessible;
121
	private transient boolean initializing;
122
	private Object owner;
123
	private int cachedSize = -1;
124

    
125
	private String role;
126
	private Serializable key;
127
	// collections detect changes made via their public interface and mark
128
	// themselves as dirty as a performance optimization
129
	private boolean dirty;
130
	private Serializable storedSnapshot;
131

    
132
	private String sessionFactoryUuid;
133
	private boolean specjLazyLoad = false;
134

    
135
	/**
136
	 * Not called by Hibernate, but used by non-JDK serialization,
137
	 * eg. SOAP libraries.
138
	 */
139
	public AbstractPersistentCollection() {
140
	}
141

    
142
	protected AbstractPersistentCollection(SessionImplementor session) {
143
		this.session = session;
144
	}
145

    
146
	@Override
147
	public final String getRole() {
148
		return role;
149
	}
150

    
151
	@Override
152
	public final Serializable getKey() {
153
		return key;
154
	}
155

    
156
	@Override
157
	public final boolean isUnreferenced() {
158
		return role == null;
159
	}
160

    
161
	@Override
162
	public final boolean isDirty() {
163
		return dirty;
164
	}
165

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

    
171
	@Override
172
	public final void dirty() {
173
		dirty = true;
174
	}
175

    
176
	@Override
177
	public final Serializable getStoredSnapshot() {
178
		return storedSnapshot;
179
	}
180

    
181
	//Careful: these methods do not initialize the collection.
182

    
183
	@Override
184
	public abstract boolean empty();
185

    
186
	/**
187
	 * Called by any read-only method of the collection interface
188
	 */
189
	protected final void read() {
190
		initialize( false );
191
	}
192

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

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

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

    
258
	private <T> T withTemporarySessionIfNeeded(LazyInitializationWork<T> lazyInitializationWork) {
259
		SessionImplementor originalSession = null;
260
		boolean isTempSession = false;
261
		boolean isJTA = false;
262

    
263
		if ( session == null ) {
264
			if ( specjLazyLoad ) {
265
				session = openTemporarySessionForLoading();
266
				isTempSession = true;
267
			}
268
			else {
269
				throwLazyInitializationException( "could not initialize proxy - no Session" );
270
			}
271
		}
272
		else if ( !session.isOpen() ) {
273
			if ( specjLazyLoad ) {
274
				originalSession = session;
275
				session = openTemporarySessionForLoading();
276
				isTempSession = true;
277
			}
278
			else {
279
				throwLazyInitializationException( "could not initialize proxy - the owning Session was closed" );
280
			}
281
		}
282
		else if ( !session.isConnected() ) {
283
			if ( specjLazyLoad ) {
284
				originalSession = session;
285
				session = openTemporarySessionForLoading();
286
				isTempSession = true;
287
			}
288
			else {
289
				throwLazyInitializationException( "could not initialize proxy - the owning Session is disconnected" );
290
			}
291
		}
292

    
293
		if ( isTempSession ) {
294
			// TODO: On the next major release, add an
295
			// 'isJTA' or 'getTransactionFactory' method to Session.
296
			/*isJTA = session.getTransactionCoordinator()
297
					.getTransactionContext().getTransactionEnvironment()
298
					.getTransactionFactory()
299
					.compatibleWithJtaSynchronization();*/
300
			isJTA = session.getTransactionCoordinator().getTransactionCoordinatorBuilder().isJta();
301
			
302
			if ( !isJTA ) {
303
				// Explicitly handle the transactions only if we're not in
304
				// a JTA environment.  A lazy loading temporary session can
305
				// be created even if a current session and transaction are
306
				// open (ex: session.clear() was used).  We must prevent
307
				// multiple transactions.
308
				( (Session) session ).beginTransaction();
309
			}
310

    
311
			session.getPersistenceContext().addUninitializedDetachedCollection(
312
					session.getFactory().getCollectionPersister( getRole() ),
313
					this
314
			);
315
		}
316

    
317
		try {
318
			return lazyInitializationWork.doWork();
319
		}
320
		finally {
321
			if ( isTempSession ) {
322
				// make sure the just opened temp session gets closed!
323
				try {
324
					if ( !isJTA ) {
325
						( ( Session) session ).getTransaction().commit();
326
					}
327
					( (Session) session ).close();
328
				}
329
				catch (Exception e) {
330
					LOG.warn( "Unable to close temporary session used to load lazy collection associated to no session" );
331
				}
332
				session = originalSession;
333
			}
334
		}
335
	}
336

    
337
	private SessionImplementor openTemporarySessionForLoading() {
338
		if ( sessionFactoryUuid == null ) {
339
			throwLazyInitializationException( "SessionFactory UUID not known to create temporary Session for loading" );
340
		}
341

    
342
		SessionFactoryImplementor sf = (SessionFactoryImplementor)
343
				SessionFactoryRegistry.INSTANCE.getSessionFactory( sessionFactoryUuid );
344
		return (SessionImplementor) sf.openSession();
345
	}
346

    
347
	protected Boolean readIndexExistence(final Object index) {
348
		if ( !initialized ) {
349
			// In remoting we are sure that session is null
350
			// both when using property paths and switching off conversations
351
			if(session == null && remoting) {
352
				LOG.info("--> readIndexExistence, of " + getRole() + " with key " + getKey());
353
				read();
354
			} else {
355
				Boolean extraLazyExistenceCheck = withTemporarySessionIfNeeded(
356
						new LazyInitializationWork<Boolean>() {
357
							@Override
358
							public Boolean doWork() {
359
								CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection.this );
360
								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
			// In remoting we are sure that session is null
385
			// both when using property paths and switching off conversations
386
			if(session == null && remoting) {
387
				LOG.info("--> readElementExistence, of " + getRole() + " with key " + getKey());
388
				read();
389

    
390
			} else {
391
				Boolean extraLazyExistenceCheck = withTemporarySessionIfNeeded(
392
						new LazyInitializationWork<Boolean>() {
393
							@Override
394
							public Boolean doWork() {
395
								CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection.this );
396
								CollectionPersister persister = entry.getLoadedPersister();
397
								if ( persister.isExtraLazy() ) {
398
									if ( hasQueuedOperations() ) {
399
										session.flush();
400
									}
401
									return persister.elementExists( entry.getLoadedKey(), element, session );
402
								}
403
								else {
404
									read();
405
								}
406
								return null;
407
							}
408
						}
409
						);
410
				if ( extraLazyExistenceCheck != null ) {
411
					return extraLazyExistenceCheck;
412
				}
413
			}
414
		}
415
		return null;
416
	}
417

    
418
	protected static final Object UNKNOWN = new MarkerObject( "UNKNOWN" );
419

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

    
428
			} else {
429
				class ExtraLazyElementByIndexReader implements LazyInitializationWork {
430
					private boolean isExtraLazy;
431
					private Object element;
432

    
433
					@Override
434
					public Object doWork() {
435
						CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection.this );
436
						CollectionPersister persister = entry.getLoadedPersister();
437
						isExtraLazy = persister.isExtraLazy();
438
						if ( isExtraLazy ) {
439
							if ( hasQueuedOperations() ) {
440
								session.flush();
441
							}
442
							element = persister.getElementByIndex( entry.getLoadedKey(), index, session, owner );
443
						}
444
						else {
445
							read();
446
						}
447
						return null;
448
					}
449
				}
450

    
451
				ExtraLazyElementByIndexReader reader = new ExtraLazyElementByIndexReader();
452
				//noinspection unchecked
453
				withTemporarySessionIfNeeded( reader );
454
				if ( reader.isExtraLazy ) {
455
					return reader.element;
456
				}
457
			}
458
		}
459
		return UNKNOWN;
460

    
461
	}
462

    
463
	protected int getCachedSize() {
464
		return cachedSize;
465
	}
466

    
467
	protected boolean isConnectedToSession() {
468
		return session != null
469
				&& session.isOpen()
470
				&& session.getPersistenceContext().containsCollection( this );
471
	}
472

    
473
	protected boolean isInitialized() {
474
		return initialized;
475
	}
476

    
477
	/**
478
	 * Called by any writer method of the collection interface
479
	 */
480
	protected final void write() {
481
		initialize( true );
482
		dirty();
483
	}
484

    
485
	/**
486
	 * Is this collection in a state that would allow us to
487
	 * "queue" operations?
488
	 */
489
	@SuppressWarnings({"JavaDoc"})
490
	protected boolean isOperationQueueEnabled() {
491
		return !initialized
492
				&& isConnectedToSession()
493
				&& isInverseCollection();
494
	}
495

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

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

    
520
	/**
521
	 * Is this the "inverse" end of a bidirectional association?
522
	 */
523
	@SuppressWarnings({"JavaDoc"})
524
	protected boolean isInverseCollection() {
525
		final CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
526
		return ce != null && ce.getLoadedPersister().isInverse();
527
	}
528

    
529
	/**
530
	 * Is this the "inverse" end of a bidirectional association with
531
	 * no orphan delete enabled?
532
	 */
533
	@SuppressWarnings({"JavaDoc"})
534
	protected boolean isInverseCollectionNoOrphanDelete() {
535
		final CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
536
		return ce != null
537
				&&
538
				ce.getLoadedPersister().isInverse() &&
539
				!ce.getLoadedPersister().hasOrphanDelete();
540
	}
541

    
542
	/**
543
	 * Is this the "inverse" end of a bidirectional one-to-many, or
544
	 * of a collection with no orphan delete?
545
	 */
546
	@SuppressWarnings({"JavaDoc"})
547
	protected boolean isInverseOneToManyOrNoOrphanDelete() {
548
		final CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
549
		return ce != null
550
				&& ce.getLoadedPersister().isInverse()
551
				&& ( ce.getLoadedPersister().isOneToMany() || !ce.getLoadedPersister().hasOrphanDelete() );
552
	}
553

    
554
	/**
555
	 * Queue an addition
556
	 */
557
	@SuppressWarnings({"JavaDoc"})
558
	protected final void queueOperation(DelayedOperation operation) {
559
		if ( operationQueue == null ) {
560
			operationQueue = new ArrayList<DelayedOperation>( 10 );
561
		}
562
		operationQueue.add( operation );
563
		//needed so that we remove this collection from the second-level cache
564
		dirty = true;
565
	}
566

    
567
	/**
568
	 * Replace entity instances with copy in {@code copyCache}/.
569
	 *
570
	 * @param copyCache - mapping from entity in the process of being
571
	 *                    merged to managed copy.
572
	 */
573
	public final void replaceQueuedOperationValues(CollectionPersister persister, Map copyCache) {
574
		for ( DelayedOperation operation : operationQueue ) {
575
			if ( ValueDelayedOperation.class.isInstance( operation ) ) {
576
				( (ValueDelayedOperation) operation ).replace( persister, copyCache );
577
			}
578
		}
579
	}
580

    
581
	/**
582
	 * After reading all existing elements from the database,
583
	 * add the queued elements to the underlying collection.
584
	 */
585
	protected final void performQueuedOperations() {
586
		for ( DelayedOperation operation : operationQueue ) {
587
			operation.operate();
588
		}
589
	}
590

    
591
	@Override
592
	public void setSnapshot(Serializable key, String role, Serializable snapshot) {
593
		this.key = key;
594
		this.role = role;
595
		this.storedSnapshot = snapshot;
596
	}
597

    
598
	@Override
599
	public void postAction() {
600
		operationQueue = null;
601
		cachedSize = -1;
602
		clearDirty();
603
	}
604

    
605
	@Override
606
	public Object getValue() {
607
		return this;
608
	}
609

    
610
	@Override
611
	public void beginRead() {
612
		// override on some subclasses
613
		initializing = true;
614
	}
615

    
616
	@Override
617
	public boolean endRead() {
618
		//override on some subclasses
619
		return afterInitialize();
620
	}
621

    
622
	@Override
623
	public boolean afterInitialize() {
624
		setInitialized();
625
		//do this bit after setting initialized to true or it will recurse
626
		if ( operationQueue != null ) {
627
			performQueuedOperations();
628
			operationQueue = null;
629
			cachedSize = -1;
630
			return false;
631
		}
632
		else {
633
			return true;
634
		}
635
	}
636

    
637
	/**
638
	 * Initialize the collection, if possible, wrapping any exceptions
639
	 * in a runtime exception
640
	 *
641
	 * @param writing currently obsolete
642
	 *
643
	 * @throws LazyInitializationException if we cannot initialize
644
	 */
645
	protected final void initialize(final boolean writing) {
646
	    if ( initialized ) {
647
	        return;
648
	    }
649

    
650
	    // In remoting we are sure that session is null
651
	    // both when using property paths and switching off conversations
652
	    if(session == null && remoting) {
653
	        remoteInitialize();
654
	    } else {
655
	        withTemporarySessionIfNeeded(
656
	                new LazyInitializationWork<Object>() {
657
	                    @Override
658
	                    public Object doWork() {
659
	                        session.initializeCollection( AbstractPersistentCollection.this, writing );
660
	                        return null;
661
	                    }
662
	                }
663
	                );
664
	    }
665
	}
666

    
667
	private void throwLazyInitializationExceptionIfNotConnected() {
668
		if ( !isConnectedToSession() ) {
669
			throwLazyInitializationException( "no session or session was closed" );
670
		}
671
		if ( !session.isConnected() ) {
672
			throwLazyInitializationException( "session is disconnected" );
673
		}
674
	}
675

    
676
	private void throwLazyInitializationException(String message) {
677
		throw new LazyInitializationException(
678
				"failed to lazily initialize a collection" +
679
						(role == null ? "" : " of role: " + role) +
680
						", " + message
681
		);
682
	}
683

    
684
	protected final void setInitialized() {
685
		this.initializing = false;
686
		this.initialized = true;
687
	}
688

    
689
	protected final void setDirectlyAccessible(boolean directlyAccessible) {
690
		this.directlyAccessible = directlyAccessible;
691
	}
692

    
693
	@Override
694
	public boolean isDirectlyAccessible() {
695
		return directlyAccessible;
696
	}
697

    
698
	/**
699
	 * Disassociate this collection from the given session.
700
	 *
701
	 * @return true if this was currently associated with the given session
702
	 */
703
	@Override
704
    public final boolean unsetSession(SessionImplementor currentSession) {
705
		prepareForPossibleSpecialSpecjInitialization();
706
		if ( currentSession == this.session ) {
707
			this.session = null;
708
			return true;
709
		}
710
		else {
711
			return false;
712
		}
713
	}
714

    
715
	protected void prepareForPossibleSpecialSpecjInitialization() {
716
		if ( session != null ) {
717
			specjLazyLoad = session.getFactory().getSettings().isInitializeLazyStateOutsideTransactionsEnabled();
718

    
719
			if ( specjLazyLoad && sessionFactoryUuid == null ) {
720
				try {
721
					sessionFactoryUuid = (String) session.getFactory().getReference().get( "uuid" ).getContent();
722
				}
723
				catch (NamingException e) {
724
					//not much we can do if this fails...
725
				}
726
			}
727
		}
728
	}
729

    
730

    
731
	/**
732
	 * Associate the collection with the given session.
733
	 *
734
	 * @return false if the collection was already associated with the session
735
	 *
736
	 * @throws HibernateException if the collection was already associated
737
	 * with another open session
738
	 */
739
	@Override
740
    public final boolean setCurrentSession(SessionImplementor session) throws HibernateException {
741
		if ( session == this.session ) {
742
			return false;
743
		}
744
		else {
745
			if ( isConnectedToSession() ) {
746
				CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
747
				if ( ce == null ) {
748
					throw new HibernateException(
749
							"Illegal attempt to associate a collection with two open sessions"
750
					);
751
				}
752
				else {
753
					throw new HibernateException(
754
							"Illegal attempt to associate a collection with two open sessions: " +
755
									MessageHelper.collectionInfoString(
756
											ce.getLoadedPersister(), this,
757
											ce.getLoadedKey(), session
758
									)
759
					);
760
				}
761
			}
762
			else {
763
				this.session = session;
764
				return true;
765
			}
766
		}
767
	}
768

    
769
	/**
770
	 * Do we need to completely recreate this collection when it changes?
771
	 */
772
	@Override
773
    public boolean needsRecreate(CollectionPersister persister) {
774
		return false;
775
	}
776

    
777
	@Override
778
	public final void forceInitialization() throws HibernateException {
779
		if ( !initialized ) {
780
			if ( initializing ) {
781
				throw new AssertionFailure( "force initialize loading collection" );
782
			}
783
			if ( session == null ) {
784
				throw new HibernateException( "collection is not associated with any session" );
785
			}
786
			if ( !session.isConnected() ) {
787
				throw new HibernateException( "disconnected session" );
788
			}
789
			session.initializeCollection( this, false );
790
		}
791
	}
792

    
793

    
794
	/**
795
	 * Get the current snapshot from the session
796
	 */
797
	@SuppressWarnings({"JavaDoc"})
798
	protected final Serializable getSnapshot() {
799
		return session.getPersistenceContext().getSnapshot( this );
800
	}
801

    
802
	@Override
803
	public final boolean wasInitialized() {
804
		return initialized;
805
	}
806

    
807
	@Override
808
	public boolean isRowUpdatePossible() {
809
		return true;
810
	}
811

    
812
	@Override
813
	public final boolean hasQueuedOperations() {
814
		return operationQueue != null;
815
	}
816

    
817
	@Override
818
	public final Iterator queuedAdditionIterator() {
819
		if ( hasQueuedOperations() ) {
820
			return new Iterator() {
821
				private int index;
822

    
823
				@Override
824
				public Object next() {
825
					return operationQueue.get( index++ ).getAddedInstance();
826
				}
827

    
828
				@Override
829
				public boolean hasNext() {
830
					return index < operationQueue.size();
831
				}
832

    
833
				@Override
834
				public void remove() {
835
					throw new UnsupportedOperationException();
836
				}
837
			};
838
		}
839
		else {
840
			return EmptyIterator.INSTANCE;
841
		}
842
	}
843

    
844
	@Override
845
	@SuppressWarnings({"unchecked"})
846
	public final Collection getQueuedOrphans(String entityName) {
847
		if ( hasQueuedOperations() ) {
848
			final Collection additions = new ArrayList( operationQueue.size() );
849
			final Collection removals = new ArrayList( operationQueue.size() );
850
			for ( DelayedOperation operation : operationQueue ) {
851
				additions.add( operation.getAddedInstance() );
852
				removals.add( operation.getOrphan() );
853
			}
854
			return getOrphans( removals, additions, entityName, session );
855
		}
856
		else {
857
			return Collections.EMPTY_LIST;
858
		}
859
	}
860

    
861
	@Override
862
	public void preInsert(CollectionPersister persister) throws HibernateException {
863
	}
864

    
865
	@Override
866
	public void afterRowInsert(CollectionPersister persister, Object entry, int i) throws HibernateException {
867
	}
868

    
869
	@Override
870
	public abstract Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException;
871

    
872
	/**
873
	 * Get the session currently associated with this collection.
874
	 *
875
	 * @return The session
876
	 */
877
	public final SessionImplementor getSession() {
878
		return session;
879
	}
880

    
881
	protected final class IteratorProxy implements Iterator {
882
		protected final Iterator itr;
883

    
884
		public IteratorProxy(Iterator itr) {
885
			this.itr = itr;
886
		}
887

    
888
		@Override
889
		public boolean hasNext() {
890
			return itr.hasNext();
891
		}
892

    
893
		@Override
894
		public Object next() {
895
			return itr.next();
896
		}
897

    
898
		@Override
899
		public void remove() {
900
			write();
901
			itr.remove();
902
		}
903
	}
904

    
905
	protected final class ListIteratorProxy implements ListIterator {
906
		protected final ListIterator itr;
907

    
908
		public ListIteratorProxy(ListIterator itr) {
909
			this.itr = itr;
910
		}
911

    
912
		@Override
913
		@SuppressWarnings({"unchecked"})
914
		public void add(Object o) {
915
			write();
916
			itr.add( o );
917
		}
918

    
919
		@Override
920
		public boolean hasNext() {
921
			return itr.hasNext();
922
		}
923

    
924
		@Override
925
		public boolean hasPrevious() {
926
			return itr.hasPrevious();
927
		}
928

    
929
		@Override
930
		public Object next() {
931
			return itr.next();
932
		}
933

    
934
		@Override
935
		public int nextIndex() {
936
			return itr.nextIndex();
937
		}
938

    
939
		@Override
940
		public Object previous() {
941
			return itr.previous();
942
		}
943

    
944
		@Override
945
		public int previousIndex() {
946
			return itr.previousIndex();
947
		}
948

    
949
		@Override
950
		public void remove() {
951
			write();
952
			itr.remove();
953
		}
954

    
955
		@Override
956
		@SuppressWarnings({"unchecked"})
957
		public void set(Object o) {
958
			write();
959
			itr.set( o );
960
		}
961
	}
962

    
963
	protected class SetProxy implements java.util.Set {
964
		protected final Collection set;
965

    
966
		public SetProxy(Collection set) {
967
			this.set = set;
968
		}
969

    
970
		@Override
971
		@SuppressWarnings({"unchecked"})
972
		public boolean add(Object o) {
973
			write();
974
			return set.add( o );
975
		}
976

    
977
		@Override
978
		@SuppressWarnings({"unchecked"})
979
		public boolean addAll(Collection c) {
980
			write();
981
			return set.addAll( c );
982
		}
983

    
984
		@Override
985
		public void clear() {
986
			write();
987
			set.clear();
988
		}
989

    
990
		@Override
991
		public boolean contains(Object o) {
992
			return set.contains( o );
993
		}
994

    
995
		@Override
996
		@SuppressWarnings("unchecked")
997
		public boolean containsAll(Collection c) {
998
			return set.containsAll( c );
999
		}
1000

    
1001
		@Override
1002
		public boolean isEmpty() {
1003
			return set.isEmpty();
1004
		}
1005

    
1006
		@Override
1007
		public Iterator iterator() {
1008
			return new IteratorProxy( set.iterator() );
1009
		}
1010

    
1011
		@Override
1012
		public boolean remove(Object o) {
1013
			write();
1014
			return set.remove( o );
1015
		}
1016

    
1017
		@Override
1018
		@SuppressWarnings("unchecked")
1019
		public boolean removeAll(Collection c) {
1020
			write();
1021
			return set.removeAll( c );
1022
		}
1023

    
1024
		@Override
1025
		@SuppressWarnings("unchecked")
1026
		public boolean retainAll(Collection c) {
1027
			write();
1028
			return set.retainAll( c );
1029
		}
1030

    
1031
		@Override
1032
		public int size() {
1033
			return set.size();
1034
		}
1035

    
1036
		@Override
1037
		public Object[] toArray() {
1038
			return set.toArray();
1039
		}
1040

    
1041
		@Override
1042
		@SuppressWarnings({"unchecked"})
1043
		public Object[] toArray(Object[] array) {
1044
			return set.toArray( array );
1045
		}
1046
	}
1047

    
1048
	protected final class ListProxy implements java.util.List {
1049
		protected final List list;
1050

    
1051
		public ListProxy(List list) {
1052
			this.list = list;
1053
		}
1054

    
1055
		@Override
1056
		@SuppressWarnings({"unchecked"})
1057
		public void add(int index, Object value) {
1058
			write();
1059
			list.add( index, value );
1060
		}
1061

    
1062
		@Override
1063
		@SuppressWarnings({"unchecked"})
1064
		public boolean add(Object o) {
1065
			write();
1066
			return list.add( o );
1067
		}
1068

    
1069
		@Override
1070
		@SuppressWarnings({"unchecked"})
1071
		public boolean addAll(Collection c) {
1072
			write();
1073
			return list.addAll( c );
1074
		}
1075

    
1076
		@Override
1077
		@SuppressWarnings({"unchecked"})
1078
		public boolean addAll(int i, Collection c) {
1079
			write();
1080
			return list.addAll( i, c );
1081
		}
1082

    
1083
		@Override
1084
		public void clear() {
1085
			write();
1086
			list.clear();
1087
		}
1088

    
1089
		@Override
1090
		public boolean contains(Object o) {
1091
			return list.contains( o );
1092
		}
1093

    
1094
		@Override
1095
		@SuppressWarnings("unchecked")
1096
		public boolean containsAll(Collection c) {
1097
			return list.containsAll( c );
1098
		}
1099

    
1100
		@Override
1101
		public Object get(int i) {
1102
			return list.get( i );
1103
		}
1104

    
1105
		@Override
1106
		public int indexOf(Object o) {
1107
			return list.indexOf( o );
1108
		}
1109

    
1110
		@Override
1111
		public boolean isEmpty() {
1112
			return list.isEmpty();
1113
		}
1114

    
1115
		@Override
1116
		public Iterator iterator() {
1117
			return new IteratorProxy( list.iterator() );
1118
		}
1119

    
1120
		@Override
1121
		public int lastIndexOf(Object o) {
1122
			return list.lastIndexOf( o );
1123
		}
1124

    
1125
		@Override
1126
		public ListIterator listIterator() {
1127
			return new ListIteratorProxy( list.listIterator() );
1128
		}
1129

    
1130
		@Override
1131
		public ListIterator listIterator(int i) {
1132
			return new ListIteratorProxy( list.listIterator( i ) );
1133
		}
1134

    
1135
		@Override
1136
		public Object remove(int i) {
1137
			write();
1138
			return list.remove( i );
1139
		}
1140

    
1141
		@Override
1142
		public boolean remove(Object o) {
1143
			write();
1144
			return list.remove( o );
1145
		}
1146

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

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

    
1161
		@Override
1162
		@SuppressWarnings({"unchecked"})
1163
		public Object set(int i, Object o) {
1164
			write();
1165
			return list.set( i, o );
1166
		}
1167

    
1168
		@Override
1169
		public int size() {
1170
			return list.size();
1171
		}
1172

    
1173
		@Override
1174
		public List subList(int i, int j) {
1175
			return list.subList( i, j );
1176
		}
1177

    
1178
		@Override
1179
		public Object[] toArray() {
1180
			return list.toArray();
1181
		}
1182

    
1183
		@Override
1184
		@SuppressWarnings({"unchecked"})
1185
		public Object[] toArray(Object[] array) {
1186
			return list.toArray( array );
1187
		}
1188

    
1189
	}
1190

    
1191
	/**
1192
	 * Contract for operations which are part of a collection's operation queue.
1193
	 */
1194
	protected interface DelayedOperation {
1195
		public void operate();
1196

    
1197
		public Object getAddedInstance();
1198

    
1199
		public Object getOrphan();
1200
	}
1201

    
1202
	protected interface ValueDelayedOperation extends DelayedOperation {
1203
		void replace(CollectionPersister collectionPersister, Map copyCache);
1204
	}
1205

    
1206
	protected abstract class AbstractValueDelayedOperation implements ValueDelayedOperation {
1207
		private Object addedValue;
1208
		private Object orphan;
1209

    
1210
		protected AbstractValueDelayedOperation(Object addedValue, Object orphan) {
1211
			this.addedValue = addedValue;
1212
			this.orphan = orphan;
1213
		}
1214

    
1215
		public void replace(CollectionPersister persister, Map copyCache) {
1216
			if ( addedValue != null ) {
1217
				addedValue = getReplacement( persister.getElementType(), addedValue, copyCache );
1218
			}
1219
		}
1220

    
1221
		protected final Object getReplacement(Type type, Object current, Map copyCache) {
1222
			return type.replace( current, null, session, owner, copyCache );
1223
		}
1224

    
1225
		@Override
1226
		public final Object getAddedInstance() {
1227
			return addedValue;
1228
		}
1229

    
1230
		@Override
1231
		public final Object getOrphan() {
1232
			return orphan;
1233
		}
1234
	}
1235

    
1236
	/**
1237
	 * Given a collection of entity instances that used to
1238
	 * belong to the collection, and a collection of instances
1239
	 * that currently belong, return a collection of orphans
1240
	 */
1241
	@SuppressWarnings({"JavaDoc", "unchecked"})
1242
	protected static Collection getOrphans(
1243
			Collection oldElements,
1244
			Collection currentElements,
1245
			String entityName,
1246
			SessionImplementor session) throws HibernateException {
1247

    
1248
		// short-circuit(s)
1249
		if ( currentElements.size() == 0 ) {
1250
			// no new elements, the old list contains only Orphans
1251
			return oldElements;
1252
		}
1253
		if ( oldElements.size() == 0 ) {
1254
			// no old elements, so no Orphans neither
1255
			return oldElements;
1256
		}
1257

    
1258
		final EntityPersister entityPersister = session.getFactory().getEntityPersister( entityName );
1259
		final Type idType = entityPersister.getIdentifierType();
1260

    
1261
		// create the collection holding the Orphans
1262
		final Collection res = new ArrayList();
1263

    
1264
		// collect EntityIdentifier(s) of the *current* elements - add them into a HashSet for fast access
1265
		final java.util.Set currentIds = new HashSet();
1266
		final java.util.Set currentSaving = new IdentitySet();
1267
		for ( Object current : currentElements ) {
1268
			if ( current != null && ForeignKeys.isNotTransient( entityName, current, null, session ) ) {
1269
				final EntityEntry ee = session.getPersistenceContext().getEntry( current );
1270
				if ( ee != null && ee.getStatus() == Status.SAVING ) {
1271
					currentSaving.add( current );
1272
				}
1273
				else {
1274
					final Serializable currentId = ForeignKeys.getEntityIdentifierIfNotUnsaved(
1275
							entityName,
1276
							current,
1277
							session
1278
					);
1279
					currentIds.add( new TypedValue( idType, currentId, entityPersister.getEntityMode() ) );
1280
				}
1281
			}
1282
		}
1283

    
1284
		// iterate over the *old* list
1285
		for ( Object old : oldElements ) {
1286
			if ( !currentSaving.contains( old ) ) {
1287
				Serializable oldId = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, old, session );
1288
				if ( !currentIds.contains( new TypedValue( idType, oldId, entityPersister.getEntityMode() ) ) ) {
1289
					res.add( old );
1290
				}
1291
			}
1292
		}
1293

    
1294
		return res;
1295
	}
1296

    
1297
	private static boolean mayUseIdDirect(Type idType) {
1298
		return idType == StringType.INSTANCE
1299
			|| idType == IntegerType.INSTANCE
1300
			|| idType == LongType.INSTANCE
1301
			|| idType == UUIDBinaryType.INSTANCE
1302
			|| idType == UUIDCharType.INSTANCE
1303
			|| idType == PostgresUUIDType.INSTANCE;
1304
	}
1305

    
1306
	/**
1307
	 * Removes entity entries that have an equal identifier with the incoming entity instance
1308
	 *
1309
	 * @param list The list containing the entity instances
1310
	 * @param entityInstance The entity instance to match elements.
1311
	 * @param entityName The entity name
1312
	 * @param session The session
1313
	 */
1314
	public static void identityRemove(
1315
			Collection list,
1316
			Object entityInstance,
1317
			String entityName,
1318
			SessionImplementor session) {
1319

    
1320
		if ( entityInstance != null && ForeignKeys.isNotTransient( entityName, entityInstance, null, session ) ) {
1321
			final EntityPersister entityPersister = session.getFactory().getEntityPersister( entityName );
1322
			final Type idType = entityPersister.getIdentifierType();
1323

    
1324
			final Serializable idOfCurrent = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, entityInstance, session );
1325
			final Iterator itr = list.iterator();
1326
			while ( itr.hasNext() ) {
1327
				final Serializable idOfOld = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, itr.next(), session );
1328
				if ( idType.isEqual( idOfCurrent, idOfOld, session.getFactory() ) ) {
1329
					itr.remove();
1330
					break;
1331
				}
1332
			}
1333

    
1334
		}
1335
	}
1336

    
1337
	@Override
1338
	public Object getIdentifier(Object entry, int i) {
1339
		throw new UnsupportedOperationException();
1340
	}
1341

    
1342
	@Override
1343
	public Object getOwner() {
1344
		return owner;
1345
	}
1346

    
1347
	@Override
1348
	public void setOwner(Object owner) {
1349
		this.owner = owner;
1350
	}
1351

    
1352
/** #################################################################### 
1353
    
1354
    ADDED PART: Below is section of code which makes remote service calls 
1355
    
1356
    #################################################################### */
1357
    
1358
	
1359
	// The affected methods are :
1360
	// initialize(final boolean writing)
1361
	// readSize()
1362
	// readIndexExistence(final Object index)
1363
	// readElementExistence(final Object element)
1364
	// readElementByIndex(final Object index)
1365

    
1366
	private static CdmApplicationRemoteConfiguration configuration;
1367
	private static boolean remoting = false;
1368

    
1369
	public static void setConfiguration(CdmApplicationRemoteConfiguration conf) {
1370
	    remoting = true;
1371
		configuration = conf;
1372
	}
1373

    
1374
	private void remoteInitialize() {
1375

    
1376
		if (getOwner() != null && !initialized) {
1377

    
1378
			try {
1379
				String role = getRole();
1380
				String fieldName = role.substring(role.lastIndexOf(".") + 1);
1381
				LOG.info("--> Remote Lazy Initializing Collection " + getRole() + " , owner : " + getOwner().getClass() + "/" + getKey() + " , field : " + fieldName);
1382
				Object owner = getOwner();
1383
				CdmBase cdmBase;
1384
				if(owner instanceof CdmBase) {
1385
				    cdmBase = (CdmBase)owner;
1386
				} else {
1387
				    throw new HibernateException("Owner of persistent collection is not a cdm entity");
1388
				}
1389
				if(configuration == null) {
1390
					throw new HibernateException("CdmApplicationRemoteConfiguration not initialized (null)");
1391
				}
1392
				ICachedCommonService cachedCommonService = configuration.getCachedCommonService();
1393
				if(cachedCommonService == null) {
1394
					throw new HibernateException("commonService not initialized (null)");
1395
				}
1396

    
1397
				//Object obj = ProxyUtils.deproxyIfInitialized(cachedCommonService.initializeCollection(this));
1398
				Object obj = ProxyUtils.deproxyIfInitialized(cachedCommonService.initializeCollection(cdmBase.getUuid(), fieldName));
1399
				if(ProxyUtils.isUninitializedProxy(obj)) {
1400
				    throw new HibernateException("Persistent Collection initialized but is still a proxy");
1401
				}
1402
				afterInitialize();
1403

    
1404
				Class<?> clazz = getClass();
1405
				if (clazz != null) {
1406
					//CollectionField cf = cachedCommonService.getCollectionField(col);
1407
					//cachedCommonService.updatePersistentCollection(cf);
1408
				    Object collectionType = ProxyUtils.getCollectionType(obj, clazz);
1409
					Field field = clazz.getDeclaredField(collectionType.toString());
1410
					field.setAccessible(true);
1411
					field.set(this, obj);
1412
					ProxyUtils.setRoleValueInOwner(owner, role, obj);
1413

    
1414
				}
1415
			} catch (Exception ex) {
1416
				throw new CdmEagerLoadingException(ex);
1417
			}
1418
		}
1419
	}
1420
}
    (1-1/1)