4 * Hibernate, Relational Persistence for Idiomatic Java
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.
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.
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
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
26 package org
.hibernate
.collection
.internal
;
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
;
38 import javax
.naming
.NamingException
;
40 import org
.hibernate
.AssertionFailure
;
41 import org
.hibernate
.HibernateException
;
42 import org
.hibernate
.LazyInitializationException
;
43 import org
.hibernate
.Session
;
44 import org
.hibernate
.collection
.spi
.PersistentCollection
;
45 import org
.hibernate
.engine
.internal
.ForeignKeys
;
46 import org
.hibernate
.engine
.spi
.CollectionEntry
;
47 import org
.hibernate
.engine
.spi
.EntityEntry
;
48 import org
.hibernate
.engine
.spi
.SessionFactoryImplementor
;
49 import org
.hibernate
.engine
.spi
.SessionImplementor
;
50 import org
.hibernate
.engine
.spi
.Status
;
51 import org
.hibernate
.engine
.spi
.TypedValue
;
52 import org
.hibernate
.internal
.SessionFactoryRegistry
;
53 import org
.hibernate
.internal
.util
.MarkerObject
;
54 import org
.hibernate
.internal
.util
.collections
.EmptyIterator
;
55 import org
.hibernate
.internal
.util
.collections
.IdentitySet
;
56 import org
.hibernate
.persister
.collection
.CollectionPersister
;
57 import org
.hibernate
.persister
.entity
.EntityPersister
;
58 import org
.hibernate
.pretty
.MessageHelper
;
59 import org
.hibernate
.type
.Type
;
60 import org
.jboss
.logging
.Logger
;
62 import eu
.etaxonomy
.cdm
.api
.application
.CdmApplicationRemoteConfiguration
;
63 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
64 import eu
.etaxonomy
.taxeditor
.remoting
.CdmEagerLoadingException
;
65 import eu
.etaxonomy
.taxeditor
.remoting
.cache
.ProxyUtils
;
66 import eu
.etaxonomy
.taxeditor
.service
.ICachedCommonService
;
69 * Base class implementing {@link org.hibernate.collection.spi.PersistentCollection}
73 public abstract class AbstractPersistentCollection
implements Serializable
, PersistentCollection
{
74 private static final Logger log
= Logger
.getLogger( AbstractPersistentCollection
.class );
76 private static final long serialVersionUID
= -7238232378593030571L;
78 private transient SessionImplementor session
;
79 private boolean initialized
;
80 private transient List
<DelayedOperation
> operationQueue
;
81 private transient boolean directlyAccessible
;
82 private transient boolean initializing
;
84 private int cachedSize
= -1;
87 private Serializable key
;
88 // collections detect changes made via their public interface and mark
89 // themselves as dirty as a performance optimization
90 private boolean dirty
;
91 private Serializable storedSnapshot
;
93 private String sessionFactoryUuid
;
94 private boolean specjLazyLoad
= false;
97 public final String
getRole() {
102 public final Serializable
getKey() {
107 public final boolean isUnreferenced() {
112 public final boolean isDirty() {
117 public final void clearDirty() {
122 public final void dirty() {
127 public final Serializable
getStoredSnapshot() {
128 return storedSnapshot
;
131 //Careful: these methods do not initialize the collection.
134 * Is the initialized collection empty?
137 public abstract boolean empty();
140 * Called by any read-only method of the collection interface
142 protected final void read() {
147 * Called by the {@link Collection#size} method
149 @SuppressWarnings({"JavaDoc"})
150 protected boolean readSize() {
151 if ( !initialized
) {
152 if ( cachedSize
!= -1 && !hasQueuedOperations() ) {
156 // In remoting we are sure that session is null
157 // both when using property paths and switching off conversations
158 if(session
== null && remoting
) {
159 log
.info("--> readSize, of " + getRole() + " with key " + getKey());
162 boolean isExtraLazy
= withTemporarySessionIfNeeded(
163 new LazyInitializationWork
<Boolean
>() {
165 public Boolean
doWork() {
166 CollectionEntry entry
= session
.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection
.this );
168 if ( entry
!= null ) {
169 CollectionPersister persister
= entry
.getLoadedPersister();
170 if ( persister
.isExtraLazy() ) {
171 if ( hasQueuedOperations() ) {
174 cachedSize
= persister
.getSize( entry
.getLoadedKey(), session
);
182 throwLazyInitializationExceptionIfNotConnected();
197 public static interface LazyInitializationWork
<T
> {
201 private <T
> T
withTemporarySessionIfNeeded(LazyInitializationWork
<T
> lazyInitializationWork
) {
202 SessionImplementor originalSession
= null;
203 boolean isTempSession
= false;
204 boolean isJTA
= false;
206 if ( session
== null ) {
207 if ( specjLazyLoad
) {
208 session
= openTemporarySessionForLoading();
209 isTempSession
= true;
212 throwLazyInitializationException( "could not initialize proxy - no Session" );
215 else if ( !session
.isOpen() ) {
216 if ( specjLazyLoad
) {
217 originalSession
= session
;
218 session
= openTemporarySessionForLoading();
219 isTempSession
= true;
222 throwLazyInitializationException( "could not initialize proxy - the owning Session was closed" );
225 else if ( !session
.isConnected() ) {
226 if ( specjLazyLoad
) {
227 originalSession
= session
;
228 session
= openTemporarySessionForLoading();
229 isTempSession
= true;
232 throwLazyInitializationException( "could not initialize proxy - the owning Session is disconnected" );
236 if ( isTempSession
) {
237 // TODO: On the next major release, add an
238 // 'isJTA' or 'getTransactionFactory' method to Session.
239 /*isJTA = session.getTransactionCoordinator()
240 .getTransactionContext().getTransactionEnvironment()
241 .getTransactionFactory()
242 .compatibleWithJtaSynchronization();*/
243 isJTA
= session
.getTransactionCoordinator().getTransactionCoordinatorBuilder().isJta();
245 // Explicitly handle the transactions only if we're not in
246 // a JTA environment. A lazy loading temporary session can
247 // be created even if a current session and transaction are
248 // open (ex: session.clear() was used). We must prevent
249 // multiple transactions.
250 ( ( Session
) session
).beginTransaction();
253 session
.getPersistenceContext().addUninitializedDetachedCollection(
254 session
.getFactory().getCollectionPersister( getRole() ),
260 return lazyInitializationWork
.doWork();
263 if ( isTempSession
) {
264 // make sure the just opened temp session gets closed!
267 ( ( Session
) session
).getTransaction().commit();
269 ( (Session
) session
).close();
271 catch (Exception e
) {
272 log
.warn( "Unable to close temporary session used to load lazy collection associated to no session" );
274 session
= originalSession
;
279 private SessionImplementor
openTemporarySessionForLoading() {
280 if ( sessionFactoryUuid
== null ) {
281 throwLazyInitializationException( "SessionFactory UUID not known to create temporary Session for loading" );
284 SessionFactoryImplementor sf
= (SessionFactoryImplementor
)
285 SessionFactoryRegistry
.INSTANCE
.getSessionFactory( sessionFactoryUuid
);
286 return (SessionImplementor
) sf
.openSession();
289 protected Boolean
readIndexExistence(final Object index
) {
290 if ( !initialized
) {
291 // In remoting we are sure that session is null
292 // both when using property paths and switching off conversations
293 if(session
== null && remoting
) {
294 log
.info("--> readIndexExistence, of " + getRole() + " with key " + getKey());
297 Boolean extraLazyExistenceCheck
= withTemporarySessionIfNeeded(
298 new LazyInitializationWork
<Boolean
>() {
300 public Boolean
doWork() {
301 CollectionEntry entry
= session
.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection
.this );
302 CollectionPersister persister
= entry
.getLoadedPersister();
303 if ( persister
.isExtraLazy() ) {
304 if ( hasQueuedOperations() ) {
307 return persister
.indexExists( entry
.getLoadedKey(), index
, session
);
316 if ( extraLazyExistenceCheck
!= null ) {
317 return extraLazyExistenceCheck
;
324 protected Boolean
readElementExistence(final Object element
) {
325 if ( !initialized
) {
326 // In remoting we are sure that session is null
327 // both when using property paths and switching off conversations
328 if(session
== null && remoting
) {
329 log
.info("--> readElementExistence, of " + getRole() + " with key " + getKey());
333 Boolean extraLazyExistenceCheck
= withTemporarySessionIfNeeded(
334 new LazyInitializationWork
<Boolean
>() {
336 public Boolean
doWork() {
337 CollectionEntry entry
= session
.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection
.this );
338 CollectionPersister persister
= entry
.getLoadedPersister();
339 if ( persister
.isExtraLazy() ) {
340 if ( hasQueuedOperations() ) {
343 return persister
.elementExists( entry
.getLoadedKey(), element
, session
);
352 if ( extraLazyExistenceCheck
!= null ) {
353 return extraLazyExistenceCheck
;
360 protected static final Object UNKNOWN
= new MarkerObject( "UNKNOWN" );
362 protected Object
readElementByIndex(final Object index
) {
363 if ( !initialized
) {
364 // In remoting we are sure that session is null
365 // both when using property paths and switching off conversations
366 if(session
== null && remoting
) {
367 log
.info("--> readElementByIndex, of " + getRole() + " with key " + getKey());
371 class ExtraLazyElementByIndexReader
implements LazyInitializationWork
{
372 private boolean isExtraLazy
;
373 private Object element
;
376 public Object
doWork() {
377 CollectionEntry entry
= session
.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection
.this );
378 CollectionPersister persister
= entry
.getLoadedPersister();
379 isExtraLazy
= persister
.isExtraLazy();
381 if ( hasQueuedOperations() ) {
384 element
= persister
.getElementByIndex( entry
.getLoadedKey(), index
, session
, owner
);
393 ExtraLazyElementByIndexReader reader
= new ExtraLazyElementByIndexReader();
394 //noinspection unchecked
395 withTemporarySessionIfNeeded( reader
);
396 if ( reader
.isExtraLazy
) {
397 return reader
.element
;
405 protected int getCachedSize() {
409 private boolean isConnectedToSession() {
410 return session
!= null &&
412 session
.getPersistenceContext().containsCollection( this );
416 * Called by any writer method of the collection interface
418 protected final void write() {
424 * Is this collection in a state that would allow us to
425 * "queue" operations?
427 @SuppressWarnings({"JavaDoc"})
428 protected boolean isOperationQueueEnabled() {
429 return !initialized
&&
430 isConnectedToSession() &&
431 isInverseCollection();
435 * Is this collection in a state that would allow us to
436 * "queue" puts? This is a special case, because of orphan
439 @SuppressWarnings({"JavaDoc"})
440 protected boolean isPutQueueEnabled() {
441 return !initialized
&&
442 isConnectedToSession() &&
443 isInverseOneToManyOrNoOrphanDelete();
447 * Is this collection in a state that would allow us to
448 * "queue" clear? This is a special case, because of orphan
451 @SuppressWarnings({"JavaDoc"})
452 protected boolean isClearQueueEnabled() {
453 return !initialized
&&
454 isConnectedToSession() &&
455 isInverseCollectionNoOrphanDelete();
459 * Is this the "inverse" end of a bidirectional association?
461 @SuppressWarnings({"JavaDoc"})
462 private boolean isInverseCollection() {
463 CollectionEntry ce
= session
.getPersistenceContext().getCollectionEntry( this );
464 return ce
!= null && ce
.getLoadedPersister().isInverse();
468 * Is this the "inverse" end of a bidirectional association with
469 * no orphan delete enabled?
471 @SuppressWarnings({"JavaDoc"})
472 private boolean isInverseCollectionNoOrphanDelete() {
473 CollectionEntry ce
= session
.getPersistenceContext().getCollectionEntry( this );
475 ce
.getLoadedPersister().isInverse() &&
476 !ce
.getLoadedPersister().hasOrphanDelete();
480 * Is this the "inverse" end of a bidirectional one-to-many, or
481 * of a collection with no orphan delete?
483 @SuppressWarnings({"JavaDoc"})
484 private boolean isInverseOneToManyOrNoOrphanDelete() {
485 CollectionEntry ce
= session
.getPersistenceContext().getCollectionEntry( this );
486 return ce
!= null && ce
.getLoadedPersister().isInverse() && (
487 ce
.getLoadedPersister().isOneToMany() ||
488 !ce
.getLoadedPersister().hasOrphanDelete()
495 @SuppressWarnings({"JavaDoc"})
496 protected final void queueOperation(DelayedOperation operation
) {
497 if ( operationQueue
== null ) {
498 operationQueue
= new ArrayList
<DelayedOperation
>( 10 );
500 operationQueue
.add( operation
);
501 dirty
= true; //needed so that we remove this collection from the second-level cache
505 * After reading all existing elements from the database,
506 * add the queued elements to the underlying collection.
508 protected final void performQueuedOperations() {
509 for ( DelayedOperation operation
: operationQueue
) {
515 * After flushing, re-init snapshot state.
518 public void setSnapshot(Serializable key
, String role
, Serializable snapshot
) {
521 this.storedSnapshot
= snapshot
;
525 * After flushing, clear any "queued" additions, since the
526 * database state is now synchronized with the memory state.
529 public void postAction() {
530 operationQueue
= null;
536 * Not called by Hibernate, but used by non-JDK serialization,
537 * eg. SOAP libraries.
539 public AbstractPersistentCollection() {
542 protected AbstractPersistentCollection(SessionImplementor session
) {
543 this.session
= session
;
547 * return the user-visible collection (or array) instance
550 public Object
getValue() {
555 * Called just before reading any rows from the JDBC result set
558 public void beginRead() {
559 // override on some subclasses
564 * Called after reading all rows from the JDBC result set
567 public boolean endRead() {
568 //override on some subclasses
569 return afterInitialize();
573 public boolean afterInitialize() {
575 //do this bit after setting initialized to true or it will recurse
576 if ( operationQueue
!= null ) {
577 performQueuedOperations();
578 operationQueue
= null;
588 * Initialize the collection, if possible, wrapping any exceptions
589 * in a runtime exception
591 * @param writing currently obsolete
593 * @throws LazyInitializationException if we cannot initialize
595 protected final void initialize(final boolean writing
) {
600 // In remoting we are sure that session is null
601 // both when using property paths and switching off conversations
602 if(session
== null && remoting
) {
605 withTemporarySessionIfNeeded(
606 new LazyInitializationWork
<Object
>() {
608 public Object
doWork() {
609 session
.initializeCollection( AbstractPersistentCollection
.this, writing
);
617 private void throwLazyInitializationExceptionIfNotConnected() {
618 if ( !isConnectedToSession() ) {
619 throwLazyInitializationException( "no session or session was closed" );
621 if ( !session
.isConnected() ) {
622 throwLazyInitializationException( "session is disconnected" );
626 private void throwLazyInitializationException(String message
) {
627 throw new LazyInitializationException(
628 "failed to lazily initialize a collection" +
629 (role
== null ?
"" : " of role: " + role
) +
634 protected final void setInitialized() {
635 this.initializing
= false;
636 this.initialized
= true;
639 protected final void setDirectlyAccessible(boolean directlyAccessible
) {
640 this.directlyAccessible
= directlyAccessible
;
644 * Could the application possibly have a direct reference to
645 * the underlying collection implementation?
648 public boolean isDirectlyAccessible() {
649 return directlyAccessible
;
653 * Disassociate this collection from the given session.
655 * @return true if this was currently associated with the given session
658 public final boolean unsetSession(SessionImplementor currentSession
) {
659 prepareForPossibleSpecialSpecjInitialization();
660 if ( currentSession
== this.session
) {
669 protected void prepareForPossibleSpecialSpecjInitialization() {
670 if ( session
!= null ) {
671 specjLazyLoad
= session
.getFactory().getSettings().isInitializeLazyStateOutsideTransactionsEnabled();
673 if ( specjLazyLoad
&& sessionFactoryUuid
== null ) {
675 sessionFactoryUuid
= (String
) session
.getFactory().getReference().get( "uuid" ).getContent();
677 catch (NamingException e
) {
678 //not much we can do if this fails...
686 * Associate the collection with the given session.
688 * @return false if the collection was already associated with the session
690 * @throws HibernateException if the collection was already associated
691 * with another open session
694 public final boolean setCurrentSession(SessionImplementor session
) throws HibernateException
{
695 if ( session
== this.session
) {
699 if ( isConnectedToSession() ) {
700 CollectionEntry ce
= session
.getPersistenceContext().getCollectionEntry( this );
702 throw new HibernateException(
703 "Illegal attempt to associate a collection with two open sessions"
707 throw new HibernateException(
708 "Illegal attempt to associate a collection with two open sessions: " +
709 MessageHelper
.collectionInfoString(
710 ce
.getLoadedPersister(), this,
711 ce
.getLoadedKey(), session
717 this.session
= session
;
724 * Do we need to completely recreate this collection when it changes?
727 public boolean needsRecreate(CollectionPersister persister
) {
732 * To be called internally by the session, forcing
733 * immediate initialization.
736 public final void forceInitialization() throws HibernateException
{
737 if ( !initialized
) {
738 if ( initializing
) {
739 throw new AssertionFailure( "force initialize loading collection" );
741 if ( session
== null ) {
742 throw new HibernateException( "collection is not associated with any session" );
744 if ( !session
.isConnected() ) {
745 throw new HibernateException( "disconnected session" );
747 session
.initializeCollection( this, false );
753 * Get the current snapshot from the session
755 @SuppressWarnings({"JavaDoc"})
756 protected final Serializable
getSnapshot() {
757 return session
.getPersistenceContext().getSnapshot( this );
761 * Is this instance initialized?
764 public final boolean wasInitialized() {
769 public boolean isRowUpdatePossible() {
774 * Does this instance have any "queued" additions?
777 public final boolean hasQueuedOperations() {
778 return operationQueue
!= null;
782 * Iterate the "queued" additions
785 public final Iterator
queuedAdditionIterator() {
786 if ( hasQueuedOperations() ) {
787 return new Iterator() {
791 public Object
next() {
792 return operationQueue
.get( i
++ ).getAddedInstance();
796 public boolean hasNext() {
797 return i
< operationQueue
.size();
801 public void remove() {
802 throw new UnsupportedOperationException();
807 return EmptyIterator
.INSTANCE
;
812 * Iterate the "queued" additions
815 @SuppressWarnings({"unchecked"})
816 public final Collection
getQueuedOrphans(String entityName
) {
817 if ( hasQueuedOperations() ) {
818 Collection additions
= new ArrayList( operationQueue
.size() );
819 Collection removals
= new ArrayList( operationQueue
.size() );
820 for ( DelayedOperation operation
: operationQueue
) {
821 additions
.add( operation
.getAddedInstance() );
822 removals
.add( operation
.getOrphan() );
824 return getOrphans( removals
, additions
, entityName
, session
);
827 return Collections
.EMPTY_LIST
;
832 * Called before inserting rows, to ensure that any surrogate keys
833 * are fully generated
836 public void preInsert(CollectionPersister persister
) throws HibernateException
{
840 * Called after inserting a row, to fetch the natively generated id
843 public void afterRowInsert(CollectionPersister persister
, Object entry
, int i
) throws HibernateException
{
847 * get all "orphaned" elements
850 public abstract Collection
getOrphans(Serializable snapshot
, String entityName
) throws HibernateException
;
853 * Get the current session
855 @SuppressWarnings({"JavaDoc"})
856 public final SessionImplementor
getSession() {
860 protected final class IteratorProxy
implements Iterator
{
861 protected final Iterator itr
;
863 public IteratorProxy(Iterator itr
) {
868 public boolean hasNext() {
869 return itr
.hasNext();
873 public Object
next() {
878 public void remove() {
885 protected final class ListIteratorProxy
implements ListIterator
{
886 protected final ListIterator itr
;
888 public ListIteratorProxy(ListIterator itr
) {
893 @SuppressWarnings({"unchecked"})
894 public void add(Object o
) {
900 public boolean hasNext() {
901 return itr
.hasNext();
905 public boolean hasPrevious() {
906 return itr
.hasPrevious();
910 public Object
next() {
915 public int nextIndex() {
916 return itr
.nextIndex();
920 public Object
previous() {
921 return itr
.previous();
925 public int previousIndex() {
926 return itr
.previousIndex();
930 public void remove() {
936 @SuppressWarnings({"unchecked"})
937 public void set(Object o
) {
944 protected class SetProxy
implements java
.util
.Set
{
945 protected final Collection set
;
947 public SetProxy(Collection set
) {
952 @SuppressWarnings({"unchecked"})
953 public boolean add(Object o
) {
959 @SuppressWarnings({"unchecked"})
960 public boolean addAll(Collection c
) {
962 return set
.addAll( c
);
966 public void clear() {
972 public boolean contains(Object o
) {
973 return set
.contains( o
);
977 public boolean containsAll(Collection c
) {
978 return set
.containsAll( c
);
982 public boolean isEmpty() {
983 return set
.isEmpty();
987 public Iterator
iterator() {
988 return new IteratorProxy( set
.iterator() );
992 public boolean remove(Object o
) {
994 return set
.remove( o
);
998 public boolean removeAll(Collection c
) {
1000 return set
.removeAll( c
);
1004 public boolean retainAll(Collection c
) {
1006 return set
.retainAll( c
);
1015 public Object
[] toArray() {
1016 return set
.toArray();
1020 @SuppressWarnings({"unchecked"})
1021 public Object
[] toArray(Object
[] array
) {
1022 return set
.toArray( array
);
1027 protected final class ListProxy
implements java
.util
.List
{
1028 protected final List list
;
1030 public ListProxy(List list
) {
1035 @SuppressWarnings({"unchecked"})
1036 public void add(int index
, Object value
) {
1038 list
.add( index
, value
);
1042 @SuppressWarnings({"unchecked"})
1043 public boolean add(Object o
) {
1045 return list
.add( o
);
1049 @SuppressWarnings({"unchecked"})
1050 public boolean addAll(Collection c
) {
1052 return list
.addAll( c
);
1056 @SuppressWarnings({"unchecked"})
1057 public boolean addAll(int i
, Collection c
) {
1059 return list
.addAll( i
, c
);
1063 public void clear() {
1069 public boolean contains(Object o
) {
1070 return list
.contains( o
);
1074 public boolean containsAll(Collection c
) {
1075 return list
.containsAll( c
);
1079 public Object
get(int i
) {
1080 return list
.get( i
);
1084 public int indexOf(Object o
) {
1085 return list
.indexOf( o
);
1089 public boolean isEmpty() {
1090 return list
.isEmpty();
1094 public Iterator
iterator() {
1095 return new IteratorProxy( list
.iterator() );
1099 public int lastIndexOf(Object o
) {
1100 return list
.lastIndexOf( o
);
1104 public ListIterator
listIterator() {
1105 return new ListIteratorProxy( list
.listIterator() );
1109 public ListIterator
listIterator(int i
) {
1110 return new ListIteratorProxy( list
.listIterator( i
) );
1114 public Object
remove(int i
) {
1116 return list
.remove( i
);
1120 public boolean remove(Object o
) {
1122 return list
.remove( o
);
1126 public boolean removeAll(Collection c
) {
1128 return list
.removeAll( c
);
1132 public boolean retainAll(Collection c
) {
1134 return list
.retainAll( c
);
1138 @SuppressWarnings({"unchecked"})
1139 public Object
set(int i
, Object o
) {
1141 return list
.set( i
, o
);
1150 public List
subList(int i
, int j
) {
1151 return list
.subList( i
, j
);
1155 public Object
[] toArray() {
1156 return list
.toArray();
1160 @SuppressWarnings({"unchecked"})
1161 public Object
[] toArray(Object
[] array
) {
1162 return list
.toArray( array
);
1168 * Contract for operations which are part of a collection's operation queue.
1170 protected interface DelayedOperation
{
1171 public void operate();
1173 public Object
getAddedInstance();
1175 public Object
getOrphan();
1179 * Given a collection of entity instances that used to
1180 * belong to the collection, and a collection of instances
1181 * that currently belong, return a collection of orphans
1183 @SuppressWarnings({"JavaDoc", "unchecked"})
1184 protected static Collection
getOrphans(
1185 Collection oldElements
,
1186 Collection currentElements
,
1188 SessionImplementor session
) throws HibernateException
{
1191 if ( currentElements
.size() == 0 ) {
1192 return oldElements
; // no new elements, the old list contains only Orphans
1194 if ( oldElements
.size() == 0 ) {
1195 return oldElements
; // no old elements, so no Orphans neither
1198 final EntityPersister entityPersister
= session
.getFactory().getEntityPersister( entityName
);
1199 final Type idType
= entityPersister
.getIdentifierType();
1201 // create the collection holding the Orphans
1202 Collection res
= new ArrayList();
1204 // collect EntityIdentifier(s) of the *current* elements - add them into a HashSet for fast access
1205 java
.util
.Set currentIds
= new HashSet();
1206 java
.util
.Set currentSaving
= new IdentitySet();
1207 for ( Object current
: currentElements
) {
1208 if ( current
!= null && ForeignKeys
.isNotTransient( entityName
, current
, null, session
) ) {
1209 EntityEntry ee
= session
.getPersistenceContext().getEntry( current
);
1210 if ( ee
!= null && ee
.getStatus() == Status
.SAVING
) {
1211 currentSaving
.add( current
);
1214 Serializable currentId
= ForeignKeys
.getEntityIdentifierIfNotUnsaved(
1219 currentIds
.add( new TypedValue( idType
, currentId
, entityPersister
.getEntityMode() ) );
1224 // iterate over the *old* list
1225 for ( Object old
: oldElements
) {
1226 if ( !currentSaving
.contains( old
) ) {
1227 Serializable oldId
= ForeignKeys
.getEntityIdentifierIfNotUnsaved( entityName
, old
, session
);
1228 if ( !currentIds
.contains( new TypedValue( idType
, oldId
, entityPersister
.getEntityMode() ) ) ) {
1237 public static void identityRemove(
1241 SessionImplementor session
) throws HibernateException
{
1243 if ( object
!= null && ForeignKeys
.isNotTransient( entityName
, object
, null, session
) ) {
1244 final EntityPersister entityPersister
= session
.getFactory().getEntityPersister( entityName
);
1245 Type idType
= entityPersister
.getIdentifierType();
1247 Serializable idOfCurrent
= ForeignKeys
.getEntityIdentifierIfNotUnsaved( entityName
, object
, session
);
1248 Iterator itr
= list
.iterator();
1249 while ( itr
.hasNext() ) {
1250 Serializable idOfOld
= ForeignKeys
.getEntityIdentifierIfNotUnsaved( entityName
, itr
.next(), session
);
1251 if ( idType
.isEqual( idOfCurrent
, idOfOld
, session
.getFactory() ) ) {
1261 public Object
getIdentifier(Object entry
, int i
) {
1262 throw new UnsupportedOperationException();
1266 public Object
getOwner() {
1271 public void setOwner(Object owner
) {
1275 /** ------ Below is section of code which makes remote service calls ----- */
1276 // The affected methods are :
1277 // initialize(final boolean writing)
1279 // readIndexExistence(final Object index)
1280 // readElementExistence(final Object element)
1281 // readElementByIndex(final Object index)
1283 private static CdmApplicationRemoteConfiguration configuration
;
1284 private static boolean remoting
= false;
1286 public static void setConfiguration(CdmApplicationRemoteConfiguration conf
) {
1288 configuration
= conf
;
1292 private void remoteInitialize() {
1294 if (getOwner() != null && !initialized
) {
1297 String role
= getRole();
1298 String fieldName
= role
.substring(role
.lastIndexOf(".") + 1);
1299 log
.info("--> Remote Lazy Initializing Collection " + getRole() + " , owner : " + getOwner().getClass() + "/" + getKey() + " , field : " + fieldName
);
1300 Object owner
= getOwner();
1302 if(owner
instanceof CdmBase
) {
1303 cdmBase
= (CdmBase
)owner
;
1305 throw new HibernateException("Owner of persistent collection is not a cdm entity");
1307 if(configuration
== null) {
1308 throw new HibernateException("CdmApplicationRemoteConfiguration not initialized (null)");
1310 ICachedCommonService cachedCommonService
= configuration
.getCachedCommonService();
1311 if(cachedCommonService
== null) {
1312 throw new HibernateException("commonService not initialized (null)");
1315 //Object obj = ProxyUtils.deproxy(cachedCommonService.initializeCollection(this));
1316 Object obj
= ProxyUtils
.deproxy(cachedCommonService
.initializeCollection(cdmBase
.getUuid(), fieldName
));
1317 if(ProxyUtils
.isProxy(obj
)) {
1318 throw new HibernateException("Persistent Collection initialized but is still a proxy");
1322 Class
<?
> clazz
= getClass();
1323 if (clazz
!= null) {
1324 //CollectionField cf = cachedCommonService.getCollectionField(col);
1325 //cachedCommonService.updatePersistentCollection(cf);
1326 Object collectionType
= ProxyUtils
.getCollectionType(obj
);
1327 Field field
= clazz
.getDeclaredField(collectionType
.toString());
1328 field
.setAccessible(true);
1329 field
.set(this, obj
);
1330 ProxyUtils
.setRoleValueInOwner(owner
, role
, obj
);
1333 } catch (Exception ex
) {
1334 throw new CdmEagerLoadingException(ex
);