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}
71 * This a extended copy of the original class from hibernate. It has been extended to
72 * allow making remote service calls to spring httpinvoker services (see section at the bottom
77 * @author Cherian Mathew
79 public abstract class AbstractPersistentCollection
implements Serializable
, PersistentCollection
{
80 private static final Logger log
= Logger
.getLogger( AbstractPersistentCollection
.class );
83 * <b>IMPORTANT:</b><br>
84 * This serialVersionUID must be kept in sync with the serialVersionUID which is generated
85 * on the fly for serialized AbstractPersistentCollection objects coming from the httpInvoker
87 * This is most probably necessary after updating hibernate to a newer version. In any case
88 * it the need for updating this <code>serialVersionUID</code> becomes obvious when the attempt
89 * to connect to the server side fails with an <code>InvalidClassException</code>:
92 * java.io.InvalidClassException: org.hibernate.collection.internal.AbstractPersistentCollection;
93 * local class incompatible:
94 * stream classdesc serialVersionUID = 2742261122392386159,
95 * local class serialVersionUID = -7238232378593030571
97 * The correct <code>serialVersionUID</code> is the <code>stream classdesc serialVersionUID</code>
98 * from the error message.
100 private static final long serialVersionUID
= 2742261122392386159L;
102 private transient SessionImplementor session
;
103 private boolean initialized
;
104 private transient List
<DelayedOperation
> operationQueue
;
105 private transient boolean directlyAccessible
;
106 private transient boolean initializing
;
107 private Object owner
;
108 private int cachedSize
= -1;
111 private Serializable key
;
112 // collections detect changes made via their public interface and mark
113 // themselves as dirty as a performance optimization
114 private boolean dirty
;
115 private Serializable storedSnapshot
;
117 private String sessionFactoryUuid
;
118 private boolean specjLazyLoad
= false;
121 public final String
getRole() {
126 public final Serializable
getKey() {
131 public final boolean isUnreferenced() {
136 public final boolean isDirty() {
141 public final void clearDirty() {
146 public final void dirty() {
151 public final Serializable
getStoredSnapshot() {
152 return storedSnapshot
;
155 //Careful: these methods do not initialize the collection.
158 * Is the initialized collection empty?
161 public abstract boolean empty();
164 * Called by any read-only method of the collection interface
166 protected final void read() {
171 * Called by the {@link Collection#size} method
173 @SuppressWarnings({"JavaDoc"})
174 protected boolean readSize() {
175 if ( !initialized
) {
176 if ( cachedSize
!= -1 && !hasQueuedOperations() ) {
180 // In remoting we are sure that session is null
181 // both when using property paths and switching off conversations
182 if(session
== null && remoting
) {
183 log
.info("--> readSize, of " + getRole() + " with key " + getKey());
186 boolean isExtraLazy
= withTemporarySessionIfNeeded(
187 new LazyInitializationWork
<Boolean
>() {
189 public Boolean
doWork() {
190 CollectionEntry entry
= session
.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection
.this );
192 if ( entry
!= null ) {
193 CollectionPersister persister
= entry
.getLoadedPersister();
194 if ( persister
.isExtraLazy() ) {
195 if ( hasQueuedOperations() ) {
198 cachedSize
= persister
.getSize( entry
.getLoadedKey(), session
);
206 throwLazyInitializationExceptionIfNotConnected();
221 public static interface LazyInitializationWork
<T
> {
225 private <T
> T
withTemporarySessionIfNeeded(LazyInitializationWork
<T
> lazyInitializationWork
) {
226 SessionImplementor originalSession
= null;
227 boolean isTempSession
= false;
228 boolean isJTA
= false;
230 if ( session
== null ) {
231 if ( specjLazyLoad
) {
232 session
= openTemporarySessionForLoading();
233 isTempSession
= true;
236 throwLazyInitializationException( "could not initialize proxy - no Session" );
239 else if ( !session
.isOpen() ) {
240 if ( specjLazyLoad
) {
241 originalSession
= session
;
242 session
= openTemporarySessionForLoading();
243 isTempSession
= true;
246 throwLazyInitializationException( "could not initialize proxy - the owning Session was closed" );
249 else if ( !session
.isConnected() ) {
250 if ( specjLazyLoad
) {
251 originalSession
= session
;
252 session
= openTemporarySessionForLoading();
253 isTempSession
= true;
256 throwLazyInitializationException( "could not initialize proxy - the owning Session is disconnected" );
260 if ( isTempSession
) {
261 // TODO: On the next major release, add an
262 // 'isJTA' or 'getTransactionFactory' method to Session.
263 /*isJTA = session.getTransactionCoordinator()
264 .getTransactionContext().getTransactionEnvironment()
265 .getTransactionFactory()
266 .compatibleWithJtaSynchronization();*/
267 isJTA
= session
.getTransactionCoordinator().getTransactionCoordinatorBuilder().isJta();
269 // Explicitly handle the transactions only if we're not in
270 // a JTA environment. A lazy loading temporary session can
271 // be created even if a current session and transaction are
272 // open (ex: session.clear() was used). We must prevent
273 // multiple transactions.
274 ( ( Session
) session
).beginTransaction();
277 session
.getPersistenceContext().addUninitializedDetachedCollection(
278 session
.getFactory().getCollectionPersister( getRole() ),
284 return lazyInitializationWork
.doWork();
287 if ( isTempSession
) {
288 // make sure the just opened temp session gets closed!
291 ( ( Session
) session
).getTransaction().commit();
293 ( (Session
) session
).close();
295 catch (Exception e
) {
296 log
.warn( "Unable to close temporary session used to load lazy collection associated to no session" );
298 session
= originalSession
;
303 private SessionImplementor
openTemporarySessionForLoading() {
304 if ( sessionFactoryUuid
== null ) {
305 throwLazyInitializationException( "SessionFactory UUID not known to create temporary Session for loading" );
308 SessionFactoryImplementor sf
= (SessionFactoryImplementor
)
309 SessionFactoryRegistry
.INSTANCE
.getSessionFactory( sessionFactoryUuid
);
310 return (SessionImplementor
) sf
.openSession();
313 protected Boolean
readIndexExistence(final Object index
) {
314 if ( !initialized
) {
315 // In remoting we are sure that session is null
316 // both when using property paths and switching off conversations
317 if(session
== null && remoting
) {
318 log
.info("--> readIndexExistence, of " + getRole() + " with key " + getKey());
321 Boolean extraLazyExistenceCheck
= withTemporarySessionIfNeeded(
322 new LazyInitializationWork
<Boolean
>() {
324 public Boolean
doWork() {
325 CollectionEntry entry
= session
.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection
.this );
326 CollectionPersister persister
= entry
.getLoadedPersister();
327 if ( persister
.isExtraLazy() ) {
328 if ( hasQueuedOperations() ) {
331 return persister
.indexExists( entry
.getLoadedKey(), index
, session
);
340 if ( extraLazyExistenceCheck
!= null ) {
341 return extraLazyExistenceCheck
;
348 protected Boolean
readElementExistence(final Object element
) {
349 if ( !initialized
) {
350 // In remoting we are sure that session is null
351 // both when using property paths and switching off conversations
352 if(session
== null && remoting
) {
353 log
.info("--> readElementExistence, of " + getRole() + " with key " + getKey());
357 Boolean extraLazyExistenceCheck
= withTemporarySessionIfNeeded(
358 new LazyInitializationWork
<Boolean
>() {
360 public Boolean
doWork() {
361 CollectionEntry entry
= session
.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection
.this );
362 CollectionPersister persister
= entry
.getLoadedPersister();
363 if ( persister
.isExtraLazy() ) {
364 if ( hasQueuedOperations() ) {
367 return persister
.elementExists( entry
.getLoadedKey(), element
, session
);
376 if ( extraLazyExistenceCheck
!= null ) {
377 return extraLazyExistenceCheck
;
384 protected static final Object UNKNOWN
= new MarkerObject( "UNKNOWN" );
386 protected Object
readElementByIndex(final Object index
) {
387 if ( !initialized
) {
388 // In remoting we are sure that session is null
389 // both when using property paths and switching off conversations
390 if(session
== null && remoting
) {
391 log
.info("--> readElementByIndex, of " + getRole() + " with key " + getKey());
395 class ExtraLazyElementByIndexReader
implements LazyInitializationWork
{
396 private boolean isExtraLazy
;
397 private Object element
;
400 public Object
doWork() {
401 CollectionEntry entry
= session
.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection
.this );
402 CollectionPersister persister
= entry
.getLoadedPersister();
403 isExtraLazy
= persister
.isExtraLazy();
405 if ( hasQueuedOperations() ) {
408 element
= persister
.getElementByIndex( entry
.getLoadedKey(), index
, session
, owner
);
417 ExtraLazyElementByIndexReader reader
= new ExtraLazyElementByIndexReader();
418 //noinspection unchecked
419 withTemporarySessionIfNeeded( reader
);
420 if ( reader
.isExtraLazy
) {
421 return reader
.element
;
429 protected int getCachedSize() {
433 private boolean isConnectedToSession() {
434 return session
!= null &&
436 session
.getPersistenceContext().containsCollection( this );
440 * Called by any writer method of the collection interface
442 protected final void write() {
448 * Is this collection in a state that would allow us to
449 * "queue" operations?
451 @SuppressWarnings({"JavaDoc"})
452 protected boolean isOperationQueueEnabled() {
453 return !initialized
&&
454 isConnectedToSession() &&
455 isInverseCollection();
459 * Is this collection in a state that would allow us to
460 * "queue" puts? This is a special case, because of orphan
463 @SuppressWarnings({"JavaDoc"})
464 protected boolean isPutQueueEnabled() {
465 return !initialized
&&
466 isConnectedToSession() &&
467 isInverseOneToManyOrNoOrphanDelete();
471 * Is this collection in a state that would allow us to
472 * "queue" clear? This is a special case, because of orphan
475 @SuppressWarnings({"JavaDoc"})
476 protected boolean isClearQueueEnabled() {
477 return !initialized
&&
478 isConnectedToSession() &&
479 isInverseCollectionNoOrphanDelete();
483 * Is this the "inverse" end of a bidirectional association?
485 @SuppressWarnings({"JavaDoc"})
486 private boolean isInverseCollection() {
487 CollectionEntry ce
= session
.getPersistenceContext().getCollectionEntry( this );
488 return ce
!= null && ce
.getLoadedPersister().isInverse();
492 * Is this the "inverse" end of a bidirectional association with
493 * no orphan delete enabled?
495 @SuppressWarnings({"JavaDoc"})
496 private boolean isInverseCollectionNoOrphanDelete() {
497 CollectionEntry ce
= session
.getPersistenceContext().getCollectionEntry( this );
499 ce
.getLoadedPersister().isInverse() &&
500 !ce
.getLoadedPersister().hasOrphanDelete();
504 * Is this the "inverse" end of a bidirectional one-to-many, or
505 * of a collection with no orphan delete?
507 @SuppressWarnings({"JavaDoc"})
508 private boolean isInverseOneToManyOrNoOrphanDelete() {
509 CollectionEntry ce
= session
.getPersistenceContext().getCollectionEntry( this );
510 return ce
!= null && ce
.getLoadedPersister().isInverse() && (
511 ce
.getLoadedPersister().isOneToMany() ||
512 !ce
.getLoadedPersister().hasOrphanDelete()
519 @SuppressWarnings({"JavaDoc"})
520 protected final void queueOperation(DelayedOperation operation
) {
521 if ( operationQueue
== null ) {
522 operationQueue
= new ArrayList
<DelayedOperation
>( 10 );
524 operationQueue
.add( operation
);
525 dirty
= true; //needed so that we remove this collection from the second-level cache
529 * After reading all existing elements from the database,
530 * add the queued elements to the underlying collection.
532 protected final void performQueuedOperations() {
533 for ( DelayedOperation operation
: operationQueue
) {
539 * After flushing, re-init snapshot state.
542 public void setSnapshot(Serializable key
, String role
, Serializable snapshot
) {
545 this.storedSnapshot
= snapshot
;
549 * After flushing, clear any "queued" additions, since the
550 * database state is now synchronized with the memory state.
553 public void postAction() {
554 operationQueue
= null;
560 * Not called by Hibernate, but used by non-JDK serialization,
561 * eg. SOAP libraries.
563 public AbstractPersistentCollection() {
566 protected AbstractPersistentCollection(SessionImplementor session
) {
567 this.session
= session
;
571 * return the user-visible collection (or array) instance
574 public Object
getValue() {
579 * Called just before reading any rows from the JDBC result set
582 public void beginRead() {
583 // override on some subclasses
588 * Called after reading all rows from the JDBC result set
591 public boolean endRead() {
592 //override on some subclasses
593 return afterInitialize();
597 public boolean afterInitialize() {
599 //do this bit after setting initialized to true or it will recurse
600 if ( operationQueue
!= null ) {
601 performQueuedOperations();
602 operationQueue
= null;
612 * Initialize the collection, if possible, wrapping any exceptions
613 * in a runtime exception
615 * @param writing currently obsolete
617 * @throws LazyInitializationException if we cannot initialize
619 protected final void initialize(final boolean writing
) {
624 // In remoting we are sure that session is null
625 // both when using property paths and switching off conversations
626 if(session
== null && remoting
) {
629 withTemporarySessionIfNeeded(
630 new LazyInitializationWork
<Object
>() {
632 public Object
doWork() {
633 session
.initializeCollection( AbstractPersistentCollection
.this, writing
);
641 private void throwLazyInitializationExceptionIfNotConnected() {
642 if ( !isConnectedToSession() ) {
643 throwLazyInitializationException( "no session or session was closed" );
645 if ( !session
.isConnected() ) {
646 throwLazyInitializationException( "session is disconnected" );
650 private void throwLazyInitializationException(String message
) {
651 throw new LazyInitializationException(
652 "failed to lazily initialize a collection" +
653 (role
== null ?
"" : " of role: " + role
) +
658 protected final void setInitialized() {
659 this.initializing
= false;
660 this.initialized
= true;
663 protected final void setDirectlyAccessible(boolean directlyAccessible
) {
664 this.directlyAccessible
= directlyAccessible
;
668 * Could the application possibly have a direct reference to
669 * the underlying collection implementation?
672 public boolean isDirectlyAccessible() {
673 return directlyAccessible
;
677 * Disassociate this collection from the given session.
679 * @return true if this was currently associated with the given session
682 public final boolean unsetSession(SessionImplementor currentSession
) {
683 prepareForPossibleSpecialSpecjInitialization();
684 if ( currentSession
== this.session
) {
693 protected void prepareForPossibleSpecialSpecjInitialization() {
694 if ( session
!= null ) {
695 specjLazyLoad
= session
.getFactory().getSettings().isInitializeLazyStateOutsideTransactionsEnabled();
697 if ( specjLazyLoad
&& sessionFactoryUuid
== null ) {
699 sessionFactoryUuid
= (String
) session
.getFactory().getReference().get( "uuid" ).getContent();
701 catch (NamingException e
) {
702 //not much we can do if this fails...
710 * Associate the collection with the given session.
712 * @return false if the collection was already associated with the session
714 * @throws HibernateException if the collection was already associated
715 * with another open session
718 public final boolean setCurrentSession(SessionImplementor session
) throws HibernateException
{
719 if ( session
== this.session
) {
723 if ( isConnectedToSession() ) {
724 CollectionEntry ce
= session
.getPersistenceContext().getCollectionEntry( this );
726 throw new HibernateException(
727 "Illegal attempt to associate a collection with two open sessions"
731 throw new HibernateException(
732 "Illegal attempt to associate a collection with two open sessions: " +
733 MessageHelper
.collectionInfoString(
734 ce
.getLoadedPersister(), this,
735 ce
.getLoadedKey(), session
741 this.session
= session
;
748 * Do we need to completely recreate this collection when it changes?
751 public boolean needsRecreate(CollectionPersister persister
) {
756 * To be called internally by the session, forcing
757 * immediate initialization.
760 public final void forceInitialization() throws HibernateException
{
761 if ( !initialized
) {
762 if ( initializing
) {
763 throw new AssertionFailure( "force initialize loading collection" );
765 if ( session
== null ) {
766 throw new HibernateException( "collection is not associated with any session" );
768 if ( !session
.isConnected() ) {
769 throw new HibernateException( "disconnected session" );
771 session
.initializeCollection( this, false );
777 * Get the current snapshot from the session
779 @SuppressWarnings({"JavaDoc"})
780 protected final Serializable
getSnapshot() {
781 return session
.getPersistenceContext().getSnapshot( this );
785 * Is this instance initialized?
788 public final boolean wasInitialized() {
793 public boolean isRowUpdatePossible() {
798 * Does this instance have any "queued" additions?
801 public final boolean hasQueuedOperations() {
802 return operationQueue
!= null;
806 * Iterate the "queued" additions
809 public final Iterator
queuedAdditionIterator() {
810 if ( hasQueuedOperations() ) {
811 return new Iterator() {
815 public Object
next() {
816 return operationQueue
.get( i
++ ).getAddedInstance();
820 public boolean hasNext() {
821 return i
< operationQueue
.size();
825 public void remove() {
826 throw new UnsupportedOperationException();
831 return EmptyIterator
.INSTANCE
;
836 * Iterate the "queued" additions
839 @SuppressWarnings({"unchecked"})
840 public final Collection
getQueuedOrphans(String entityName
) {
841 if ( hasQueuedOperations() ) {
842 Collection additions
= new ArrayList( operationQueue
.size() );
843 Collection removals
= new ArrayList( operationQueue
.size() );
844 for ( DelayedOperation operation
: operationQueue
) {
845 additions
.add( operation
.getAddedInstance() );
846 removals
.add( operation
.getOrphan() );
848 return getOrphans( removals
, additions
, entityName
, session
);
851 return Collections
.EMPTY_LIST
;
856 * Called before inserting rows, to ensure that any surrogate keys
857 * are fully generated
860 public void preInsert(CollectionPersister persister
) throws HibernateException
{
864 * Called after inserting a row, to fetch the natively generated id
867 public void afterRowInsert(CollectionPersister persister
, Object entry
, int i
) throws HibernateException
{
871 * get all "orphaned" elements
874 public abstract Collection
getOrphans(Serializable snapshot
, String entityName
) throws HibernateException
;
877 * Get the current session
879 @SuppressWarnings({"JavaDoc"})
880 public final SessionImplementor
getSession() {
884 protected final class IteratorProxy
implements Iterator
{
885 protected final Iterator itr
;
887 public IteratorProxy(Iterator itr
) {
892 public boolean hasNext() {
893 return itr
.hasNext();
897 public Object
next() {
902 public void remove() {
909 protected final class ListIteratorProxy
implements ListIterator
{
910 protected final ListIterator itr
;
912 public ListIteratorProxy(ListIterator itr
) {
917 @SuppressWarnings({"unchecked"})
918 public void add(Object o
) {
924 public boolean hasNext() {
925 return itr
.hasNext();
929 public boolean hasPrevious() {
930 return itr
.hasPrevious();
934 public Object
next() {
939 public int nextIndex() {
940 return itr
.nextIndex();
944 public Object
previous() {
945 return itr
.previous();
949 public int previousIndex() {
950 return itr
.previousIndex();
954 public void remove() {
960 @SuppressWarnings({"unchecked"})
961 public void set(Object o
) {
968 protected class SetProxy
implements java
.util
.Set
{
969 protected final Collection set
;
971 public SetProxy(Collection set
) {
976 @SuppressWarnings({"unchecked"})
977 public boolean add(Object o
) {
983 @SuppressWarnings({"unchecked"})
984 public boolean addAll(Collection c
) {
986 return set
.addAll( c
);
990 public void clear() {
996 public boolean contains(Object o
) {
997 return set
.contains( o
);
1001 public boolean containsAll(Collection c
) {
1002 return set
.containsAll( c
);
1006 public boolean isEmpty() {
1007 return set
.isEmpty();
1011 public Iterator
iterator() {
1012 return new IteratorProxy( set
.iterator() );
1016 public boolean remove(Object o
) {
1018 return set
.remove( o
);
1022 public boolean removeAll(Collection c
) {
1024 return set
.removeAll( c
);
1028 public boolean retainAll(Collection c
) {
1030 return set
.retainAll( c
);
1039 public Object
[] toArray() {
1040 return set
.toArray();
1044 @SuppressWarnings({"unchecked"})
1045 public Object
[] toArray(Object
[] array
) {
1046 return set
.toArray( array
);
1051 protected final class ListProxy
implements java
.util
.List
{
1052 protected final List list
;
1054 public ListProxy(List list
) {
1059 @SuppressWarnings({"unchecked"})
1060 public void add(int index
, Object value
) {
1062 list
.add( index
, value
);
1066 @SuppressWarnings({"unchecked"})
1067 public boolean add(Object o
) {
1069 return list
.add( o
);
1073 @SuppressWarnings({"unchecked"})
1074 public boolean addAll(Collection c
) {
1076 return list
.addAll( c
);
1080 @SuppressWarnings({"unchecked"})
1081 public boolean addAll(int i
, Collection c
) {
1083 return list
.addAll( i
, c
);
1087 public void clear() {
1093 public boolean contains(Object o
) {
1094 return list
.contains( o
);
1098 public boolean containsAll(Collection c
) {
1099 return list
.containsAll( c
);
1103 public Object
get(int i
) {
1104 return list
.get( i
);
1108 public int indexOf(Object o
) {
1109 return list
.indexOf( o
);
1113 public boolean isEmpty() {
1114 return list
.isEmpty();
1118 public Iterator
iterator() {
1119 return new IteratorProxy( list
.iterator() );
1123 public int lastIndexOf(Object o
) {
1124 return list
.lastIndexOf( o
);
1128 public ListIterator
listIterator() {
1129 return new ListIteratorProxy( list
.listIterator() );
1133 public ListIterator
listIterator(int i
) {
1134 return new ListIteratorProxy( list
.listIterator( i
) );
1138 public Object
remove(int i
) {
1140 return list
.remove( i
);
1144 public boolean remove(Object o
) {
1146 return list
.remove( o
);
1150 public boolean removeAll(Collection c
) {
1152 return list
.removeAll( c
);
1156 public boolean retainAll(Collection c
) {
1158 return list
.retainAll( c
);
1162 @SuppressWarnings({"unchecked"})
1163 public Object
set(int i
, Object o
) {
1165 return list
.set( i
, o
);
1174 public List
subList(int i
, int j
) {
1175 return list
.subList( i
, j
);
1179 public Object
[] toArray() {
1180 return list
.toArray();
1184 @SuppressWarnings({"unchecked"})
1185 public Object
[] toArray(Object
[] array
) {
1186 return list
.toArray( array
);
1192 * Contract for operations which are part of a collection's operation queue.
1194 protected interface DelayedOperation
{
1195 public void operate();
1197 public Object
getAddedInstance();
1199 public Object
getOrphan();
1203 * Given a collection of entity instances that used to
1204 * belong to the collection, and a collection of instances
1205 * that currently belong, return a collection of orphans
1207 @SuppressWarnings({"JavaDoc", "unchecked"})
1208 protected static Collection
getOrphans(
1209 Collection oldElements
,
1210 Collection currentElements
,
1212 SessionImplementor session
) throws HibernateException
{
1215 if ( currentElements
.size() == 0 ) {
1216 return oldElements
; // no new elements, the old list contains only Orphans
1218 if ( oldElements
.size() == 0 ) {
1219 return oldElements
; // no old elements, so no Orphans neither
1222 final EntityPersister entityPersister
= session
.getFactory().getEntityPersister( entityName
);
1223 final Type idType
= entityPersister
.getIdentifierType();
1225 // create the collection holding the Orphans
1226 Collection res
= new ArrayList();
1228 // collect EntityIdentifier(s) of the *current* elements - add them into a HashSet for fast access
1229 java
.util
.Set currentIds
= new HashSet();
1230 java
.util
.Set currentSaving
= new IdentitySet();
1231 for ( Object current
: currentElements
) {
1232 if ( current
!= null && ForeignKeys
.isNotTransient( entityName
, current
, null, session
) ) {
1233 EntityEntry ee
= session
.getPersistenceContext().getEntry( current
);
1234 if ( ee
!= null && ee
.getStatus() == Status
.SAVING
) {
1235 currentSaving
.add( current
);
1238 Serializable currentId
= ForeignKeys
.getEntityIdentifierIfNotUnsaved(
1243 currentIds
.add( new TypedValue( idType
, currentId
, entityPersister
.getEntityMode() ) );
1248 // iterate over the *old* list
1249 for ( Object old
: oldElements
) {
1250 if ( !currentSaving
.contains( old
) ) {
1251 Serializable oldId
= ForeignKeys
.getEntityIdentifierIfNotUnsaved( entityName
, old
, session
);
1252 if ( !currentIds
.contains( new TypedValue( idType
, oldId
, entityPersister
.getEntityMode() ) ) ) {
1261 public static void identityRemove(
1265 SessionImplementor session
) throws HibernateException
{
1267 if ( object
!= null && ForeignKeys
.isNotTransient( entityName
, object
, null, session
) ) {
1268 final EntityPersister entityPersister
= session
.getFactory().getEntityPersister( entityName
);
1269 Type idType
= entityPersister
.getIdentifierType();
1271 Serializable idOfCurrent
= ForeignKeys
.getEntityIdentifierIfNotUnsaved( entityName
, object
, session
);
1272 Iterator itr
= list
.iterator();
1273 while ( itr
.hasNext() ) {
1274 Serializable idOfOld
= ForeignKeys
.getEntityIdentifierIfNotUnsaved( entityName
, itr
.next(), session
);
1275 if ( idType
.isEqual( idOfCurrent
, idOfOld
, session
.getFactory() ) ) {
1285 public Object
getIdentifier(Object entry
, int i
) {
1286 throw new UnsupportedOperationException();
1290 public Object
getOwner() {
1295 public void setOwner(Object owner
) {
1299 /** ------ Below is section of code which makes remote service calls ----- */
1300 // The affected methods are :
1301 // initialize(final boolean writing)
1303 // readIndexExistence(final Object index)
1304 // readElementExistence(final Object element)
1305 // readElementByIndex(final Object index)
1307 private static CdmApplicationRemoteConfiguration configuration
;
1308 private static boolean remoting
= false;
1310 public static void setConfiguration(CdmApplicationRemoteConfiguration conf
) {
1312 configuration
= conf
;
1316 private void remoteInitialize() {
1318 if (getOwner() != null && !initialized
) {
1321 String role
= getRole();
1322 String fieldName
= role
.substring(role
.lastIndexOf(".") + 1);
1323 log
.info("--> Remote Lazy Initializing Collection " + getRole() + " , owner : " + getOwner().getClass() + "/" + getKey() + " , field : " + fieldName
);
1324 Object owner
= getOwner();
1326 if(owner
instanceof CdmBase
) {
1327 cdmBase
= (CdmBase
)owner
;
1329 throw new HibernateException("Owner of persistent collection is not a cdm entity");
1331 if(configuration
== null) {
1332 throw new HibernateException("CdmApplicationRemoteConfiguration not initialized (null)");
1334 ICachedCommonService cachedCommonService
= configuration
.getCachedCommonService();
1335 if(cachedCommonService
== null) {
1336 throw new HibernateException("commonService not initialized (null)");
1339 //Object obj = ProxyUtils.deproxy(cachedCommonService.initializeCollection(this));
1340 Object obj
= ProxyUtils
.deproxy(cachedCommonService
.initializeCollection(cdmBase
.getUuid(), fieldName
));
1341 if(ProxyUtils
.isProxy(obj
)) {
1342 throw new HibernateException("Persistent Collection initialized but is still a proxy");
1346 Class
<?
> clazz
= getClass();
1347 if (clazz
!= null) {
1348 //CollectionField cf = cachedCommonService.getCollectionField(col);
1349 //cachedCommonService.updatePersistentCollection(cf);
1350 Object collectionType
= ProxyUtils
.getCollectionType(obj
, clazz
);
1351 Field field
= clazz
.getDeclaredField(collectionType
.toString());
1352 field
.setAccessible(true);
1353 field
.set(this, obj
);
1354 ProxyUtils
.setRoleValueInOwner(owner
, role
, obj
);
1357 } catch (Exception ex
) {
1358 throw new CdmEagerLoadingException(ex
);