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
.HashMap
;
34 import java
.util
.HashSet
;
35 import java
.util
.Iterator
;
36 import java
.util
.List
;
37 import java
.util
.ListIterator
;
40 import java
.util
.TreeMap
;
41 import java
.util
.TreeSet
;
43 import javax
.naming
.NamingException
;
45 import org
.hibernate
.AssertionFailure
;
46 import org
.hibernate
.HibernateException
;
47 import org
.hibernate
.LazyInitializationException
;
48 import org
.hibernate
.Session
;
49 import org
.hibernate
.collection
.spi
.PersistentCollection
;
50 import org
.hibernate
.engine
.internal
.ForeignKeys
;
51 import org
.hibernate
.engine
.spi
.CollectionEntry
;
52 import org
.hibernate
.engine
.spi
.EntityEntry
;
53 import org
.hibernate
.engine
.spi
.SessionFactoryImplementor
;
54 import org
.hibernate
.engine
.spi
.SessionImplementor
;
55 import org
.hibernate
.engine
.spi
.Status
;
56 import org
.hibernate
.engine
.spi
.TypedValue
;
57 import org
.hibernate
.internal
.SessionFactoryRegistry
;
58 import org
.hibernate
.internal
.util
.MarkerObject
;
59 import org
.hibernate
.internal
.util
.collections
.EmptyIterator
;
60 import org
.hibernate
.internal
.util
.collections
.IdentitySet
;
61 import org
.hibernate
.persister
.collection
.CollectionPersister
;
62 import org
.hibernate
.persister
.entity
.EntityPersister
;
63 import org
.hibernate
.pretty
.MessageHelper
;
64 import org
.hibernate
.type
.Type
;
65 import org
.jboss
.logging
.Logger
;
67 import eu
.etaxonomy
.cdm
.api
.application
.ICdmApplicationConfiguration
;
68 import eu
.etaxonomy
.cdm
.api
.service
.ICommonService
;
69 import eu
.etaxonomy
.cdm
.model
.common
.PersistentMultiLanguageText
;
72 * Base class implementing {@link org.hibernate.collection.spi.PersistentCollection}
76 public abstract class AbstractPersistentCollection
implements Serializable
, PersistentCollection
{
77 private static final Logger log
= Logger
.getLogger( AbstractPersistentCollection
.class );
79 private static final long serialVersionUID
= -7238232378593030571L;
81 private transient SessionImplementor session
;
82 private boolean initialized
;
83 private transient List
<DelayedOperation
> operationQueue
;
84 private transient boolean directlyAccessible
;
85 private transient boolean initializing
;
87 private int cachedSize
= -1;
90 private Serializable key
;
91 // collections detect changes made via their public interface and mark
92 // themselves as dirty as a performance optimization
93 private boolean dirty
;
94 private Serializable storedSnapshot
;
96 private String sessionFactoryUuid
;
97 private boolean specjLazyLoad
= false;
99 public final String
getRole() {
103 public final Serializable
getKey() {
107 public final boolean isUnreferenced() {
111 public final boolean isDirty() {
115 public final void clearDirty() {
119 public final void dirty() {
123 public final Serializable
getStoredSnapshot() {
124 return storedSnapshot
;
127 //Careful: these methods do not initialize the collection.
130 * Is the initialized collection empty?
132 public abstract boolean empty();
135 * Called by any read-only method of the collection interface
137 protected final void read() {
142 * Called by the {@link Collection#size} method
144 @SuppressWarnings({"JavaDoc"})
145 protected boolean readSize() {
146 if ( !initialized
) {
147 if ( cachedSize
!= -1 && !hasQueuedOperations() ) {
151 // In remoting we are sure that session is null
152 // both when using property paths and switching off conversations
153 if(session
== null && remoting
) {
154 log
.info("--> readSize, of " + getRole() + " with key " + getKey());
157 boolean isExtraLazy
= withTemporarySessionIfNeeded(
158 new LazyInitializationWork
<Boolean
>() {
160 public Boolean
doWork() {
161 CollectionEntry entry
= session
.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection
.this );
163 if ( entry
!= null ) {
164 CollectionPersister persister
= entry
.getLoadedPersister();
165 if ( persister
.isExtraLazy() ) {
166 if ( hasQueuedOperations() ) {
169 cachedSize
= persister
.getSize( entry
.getLoadedKey(), session
);
177 throwLazyInitializationExceptionIfNotConnected();
192 public static interface LazyInitializationWork
<T
> {
196 private <T
> T
withTemporarySessionIfNeeded(LazyInitializationWork
<T
> lazyInitializationWork
) {
197 SessionImplementor originalSession
= null;
198 boolean isTempSession
= false;
199 boolean isJTA
= false;
201 if ( session
== null ) {
202 if ( specjLazyLoad
) {
203 session
= openTemporarySessionForLoading();
204 isTempSession
= true;
207 throwLazyInitializationException( "could not initialize proxy - no Session" );
210 else if ( !session
.isOpen() ) {
211 if ( specjLazyLoad
) {
212 originalSession
= session
;
213 session
= openTemporarySessionForLoading();
214 isTempSession
= true;
217 throwLazyInitializationException( "could not initialize proxy - the owning Session was closed" );
220 else if ( !session
.isConnected() ) {
221 if ( specjLazyLoad
) {
222 originalSession
= session
;
223 session
= openTemporarySessionForLoading();
224 isTempSession
= true;
227 throwLazyInitializationException( "could not initialize proxy - the owning Session is disconnected" );
231 if ( isTempSession
) {
232 // TODO: On the next major release, add an
233 // 'isJTA' or 'getTransactionFactory' method to Session.
234 isJTA
= session
.getTransactionCoordinator()
235 .getTransactionContext().getTransactionEnvironment()
236 .getTransactionFactory()
237 .compatibleWithJtaSynchronization();
240 // Explicitly handle the transactions only if we're not in
241 // a JTA environment. A lazy loading temporary session can
242 // be created even if a current session and transaction are
243 // open (ex: session.clear() was used). We must prevent
244 // multiple transactions.
245 ( ( Session
) session
).beginTransaction();
248 session
.getPersistenceContext().addUninitializedDetachedCollection(
249 session
.getFactory().getCollectionPersister( getRole() ),
255 return lazyInitializationWork
.doWork();
258 if ( isTempSession
) {
259 // make sure the just opened temp session gets closed!
262 ( ( Session
) session
).getTransaction().commit();
264 ( (Session
) session
).close();
266 catch (Exception e
) {
267 log
.warn( "Unable to close temporary session used to load lazy collection associated to no session" );
269 session
= originalSession
;
274 private SessionImplementor
openTemporarySessionForLoading() {
275 if ( sessionFactoryUuid
== null ) {
276 throwLazyInitializationException( "SessionFactory UUID not known to create temporary Session for loading" );
279 SessionFactoryImplementor sf
= (SessionFactoryImplementor
)
280 SessionFactoryRegistry
.INSTANCE
.getSessionFactory( sessionFactoryUuid
);
281 return (SessionImplementor
) sf
.openSession();
284 protected Boolean
readIndexExistence(final Object index
) {
285 if ( !initialized
) {
286 // In remoting we are sure that session is null
287 // both when using property paths and switching off conversations
288 if(session
== null && remoting
) {
289 log
.info("--> readIndexExistence, of " + getRole() + " with key " + getKey());
292 Boolean extraLazyExistenceCheck
= withTemporarySessionIfNeeded(
293 new LazyInitializationWork
<Boolean
>() {
295 public Boolean
doWork() {
296 CollectionEntry entry
= session
.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection
.this );
297 CollectionPersister persister
= entry
.getLoadedPersister();
298 if ( persister
.isExtraLazy() ) {
299 if ( hasQueuedOperations() ) {
302 return persister
.indexExists( entry
.getLoadedKey(), index
, session
);
311 if ( extraLazyExistenceCheck
!= null ) {
312 return extraLazyExistenceCheck
;
319 protected Boolean
readElementExistence(final Object element
) {
320 if ( !initialized
) {
321 // In remoting we are sure that session is null
322 // both when using property paths and switching off conversations
323 if(session
== null && remoting
) {
324 log
.info("--> readElementExistence, of " + getRole() + " with key " + getKey());
328 Boolean extraLazyExistenceCheck
= withTemporarySessionIfNeeded(
329 new LazyInitializationWork
<Boolean
>() {
331 public Boolean
doWork() {
332 CollectionEntry entry
= session
.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection
.this );
333 CollectionPersister persister
= entry
.getLoadedPersister();
334 if ( persister
.isExtraLazy() ) {
335 if ( hasQueuedOperations() ) {
338 return persister
.elementExists( entry
.getLoadedKey(), element
, session
);
347 if ( extraLazyExistenceCheck
!= null ) {
348 return extraLazyExistenceCheck
;
355 protected static final Object UNKNOWN
= new MarkerObject( "UNKNOWN" );
357 protected Object
readElementByIndex(final Object index
) {
358 if ( !initialized
) {
359 // In remoting we are sure that session is null
360 // both when using property paths and switching off conversations
361 if(session
== null && remoting
) {
362 log
.info("--> readElementByIndex, of " + getRole() + " with key " + getKey());
366 class ExtraLazyElementByIndexReader
implements LazyInitializationWork
{
367 private boolean isExtraLazy
;
368 private Object element
;
371 public Object
doWork() {
372 CollectionEntry entry
= session
.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection
.this );
373 CollectionPersister persister
= entry
.getLoadedPersister();
374 isExtraLazy
= persister
.isExtraLazy();
376 if ( hasQueuedOperations() ) {
379 element
= persister
.getElementByIndex( entry
.getLoadedKey(), index
, session
, owner
);
388 ExtraLazyElementByIndexReader reader
= new ExtraLazyElementByIndexReader();
389 //noinspection unchecked
390 withTemporarySessionIfNeeded( reader
);
391 if ( reader
.isExtraLazy
) {
392 return reader
.element
;
400 protected int getCachedSize() {
404 private boolean isConnectedToSession() {
405 return session
!= null &&
407 session
.getPersistenceContext().containsCollection( this );
411 * Called by any writer method of the collection interface
413 protected final void write() {
419 * Is this collection in a state that would allow us to
420 * "queue" operations?
422 @SuppressWarnings({"JavaDoc"})
423 protected boolean isOperationQueueEnabled() {
424 return !initialized
&&
425 isConnectedToSession() &&
426 isInverseCollection();
430 * Is this collection in a state that would allow us to
431 * "queue" puts? This is a special case, because of orphan
434 @SuppressWarnings({"JavaDoc"})
435 protected boolean isPutQueueEnabled() {
436 return !initialized
&&
437 isConnectedToSession() &&
438 isInverseOneToManyOrNoOrphanDelete();
442 * Is this collection in a state that would allow us to
443 * "queue" clear? This is a special case, because of orphan
446 @SuppressWarnings({"JavaDoc"})
447 protected boolean isClearQueueEnabled() {
448 return !initialized
&&
449 isConnectedToSession() &&
450 isInverseCollectionNoOrphanDelete();
454 * Is this the "inverse" end of a bidirectional association?
456 @SuppressWarnings({"JavaDoc"})
457 private boolean isInverseCollection() {
458 CollectionEntry ce
= session
.getPersistenceContext().getCollectionEntry( this );
459 return ce
!= null && ce
.getLoadedPersister().isInverse();
463 * Is this the "inverse" end of a bidirectional association with
464 * no orphan delete enabled?
466 @SuppressWarnings({"JavaDoc"})
467 private boolean isInverseCollectionNoOrphanDelete() {
468 CollectionEntry ce
= session
.getPersistenceContext().getCollectionEntry( this );
470 ce
.getLoadedPersister().isInverse() &&
471 !ce
.getLoadedPersister().hasOrphanDelete();
475 * Is this the "inverse" end of a bidirectional one-to-many, or
476 * of a collection with no orphan delete?
478 @SuppressWarnings({"JavaDoc"})
479 private boolean isInverseOneToManyOrNoOrphanDelete() {
480 CollectionEntry ce
= session
.getPersistenceContext().getCollectionEntry( this );
481 return ce
!= null && ce
.getLoadedPersister().isInverse() && (
482 ce
.getLoadedPersister().isOneToMany() ||
483 !ce
.getLoadedPersister().hasOrphanDelete()
490 @SuppressWarnings({"JavaDoc"})
491 protected final void queueOperation(DelayedOperation operation
) {
492 if ( operationQueue
== null ) {
493 operationQueue
= new ArrayList
<DelayedOperation
>( 10 );
495 operationQueue
.add( operation
);
496 dirty
= true; //needed so that we remove this collection from the second-level cache
500 * After reading all existing elements from the database,
501 * add the queued elements to the underlying collection.
503 protected final void performQueuedOperations() {
504 for ( DelayedOperation operation
: operationQueue
) {
510 * After flushing, re-init snapshot state.
512 public void setSnapshot(Serializable key
, String role
, Serializable snapshot
) {
515 this.storedSnapshot
= snapshot
;
519 * After flushing, clear any "queued" additions, since the
520 * database state is now synchronized with the memory state.
522 public void postAction() {
523 operationQueue
= null;
529 * Not called by Hibernate, but used by non-JDK serialization,
530 * eg. SOAP libraries.
532 public AbstractPersistentCollection() {
535 protected AbstractPersistentCollection(SessionImplementor session
) {
536 this.session
= session
;
540 * return the user-visible collection (or array) instance
542 public Object
getValue() {
547 * Called just before reading any rows from the JDBC result set
549 public void beginRead() {
550 // override on some subclasses
555 * Called after reading all rows from the JDBC result set
557 public boolean endRead() {
558 //override on some subclasses
559 return afterInitialize();
562 public boolean afterInitialize() {
564 //do this bit after setting initialized to true or it will recurse
565 if ( operationQueue
!= null ) {
566 performQueuedOperations();
567 operationQueue
= null;
577 * Initialize the collection, if possible, wrapping any exceptions
578 * in a runtime exception
580 * @param writing currently obsolete
582 * @throws LazyInitializationException if we cannot initialize
584 protected final void initialize(final boolean writing
) {
585 // In remoting we are sure that session is null
586 // both when using property paths and switching off conversations
587 if(session
== null && remoting
) {
596 withTemporarySessionIfNeeded(
597 new LazyInitializationWork
<Object
>() {
599 public Object
doWork() {
600 session
.initializeCollection( AbstractPersistentCollection
.this, writing
);
607 private void throwLazyInitializationExceptionIfNotConnected() {
608 if ( !isConnectedToSession() ) {
609 throwLazyInitializationException( "no session or session was closed" );
611 if ( !session
.isConnected() ) {
612 throwLazyInitializationException( "session is disconnected" );
616 private void throwLazyInitializationException(String message
) {
617 throw new LazyInitializationException(
618 "failed to lazily initialize a collection" +
619 (role
== null ?
"" : " of role: " + role
) +
624 protected final void setInitialized() {
625 this.initializing
= false;
626 this.initialized
= true;
629 protected final void setDirectlyAccessible(boolean directlyAccessible
) {
630 this.directlyAccessible
= directlyAccessible
;
634 * Could the application possibly have a direct reference to
635 * the underlying collection implementation?
637 public boolean isDirectlyAccessible() {
638 return directlyAccessible
;
642 * Disassociate this collection from the given session.
644 * @return true if this was currently associated with the given session
646 public final boolean unsetSession(SessionImplementor currentSession
) {
647 prepareForPossibleSpecialSpecjInitialization();
648 if ( currentSession
== this.session
) {
657 protected void prepareForPossibleSpecialSpecjInitialization() {
658 if ( session
!= null ) {
659 specjLazyLoad
= session
.getFactory().getSettings().isInitializeLazyStateOutsideTransactionsEnabled();
661 if ( specjLazyLoad
&& sessionFactoryUuid
== null ) {
663 sessionFactoryUuid
= (String
) session
.getFactory().getReference().get( "uuid" ).getContent();
665 catch (NamingException e
) {
666 //not much we can do if this fails...
674 * Associate the collection with the given session.
676 * @return false if the collection was already associated with the session
678 * @throws HibernateException if the collection was already associated
679 * with another open session
681 public final boolean setCurrentSession(SessionImplementor session
) throws HibernateException
{
682 if ( session
== this.session
) {
686 if ( isConnectedToSession() ) {
687 CollectionEntry ce
= session
.getPersistenceContext().getCollectionEntry( this );
689 throw new HibernateException(
690 "Illegal attempt to associate a collection with two open sessions"
694 throw new HibernateException(
695 "Illegal attempt to associate a collection with two open sessions: " +
696 MessageHelper
.collectionInfoString(
697 ce
.getLoadedPersister(), this,
698 ce
.getLoadedKey(), session
704 this.session
= session
;
711 * Do we need to completely recreate this collection when it changes?
713 public boolean needsRecreate(CollectionPersister persister
) {
718 * To be called internally by the session, forcing
719 * immediate initialization.
721 public final void forceInitialization() throws HibernateException
{
722 if ( !initialized
) {
723 if ( initializing
) {
724 throw new AssertionFailure( "force initialize loading collection" );
726 if ( session
== null ) {
727 throw new HibernateException( "collection is not associated with any session" );
729 if ( !session
.isConnected() ) {
730 throw new HibernateException( "disconnected session" );
732 session
.initializeCollection( this, false );
738 * Get the current snapshot from the session
740 @SuppressWarnings({"JavaDoc"})
741 protected final Serializable
getSnapshot() {
742 return session
.getPersistenceContext().getSnapshot( this );
746 * Is this instance initialized?
748 public final boolean wasInitialized() {
752 public boolean isRowUpdatePossible() {
757 * Does this instance have any "queued" additions?
759 public final boolean hasQueuedOperations() {
760 return operationQueue
!= null;
764 * Iterate the "queued" additions
766 public final Iterator
queuedAdditionIterator() {
767 if ( hasQueuedOperations() ) {
768 return new Iterator() {
771 public Object
next() {
772 return operationQueue
.get( i
++ ).getAddedInstance();
775 public boolean hasNext() {
776 return i
< operationQueue
.size();
779 public void remove() {
780 throw new UnsupportedOperationException();
785 return EmptyIterator
.INSTANCE
;
790 * Iterate the "queued" additions
792 @SuppressWarnings({"unchecked"})
793 public final Collection
getQueuedOrphans(String entityName
) {
794 if ( hasQueuedOperations() ) {
795 Collection additions
= new ArrayList( operationQueue
.size() );
796 Collection removals
= new ArrayList( operationQueue
.size() );
797 for ( DelayedOperation operation
: operationQueue
) {
798 additions
.add( operation
.getAddedInstance() );
799 removals
.add( operation
.getOrphan() );
801 return getOrphans( removals
, additions
, entityName
, session
);
804 return Collections
.EMPTY_LIST
;
809 * Called before inserting rows, to ensure that any surrogate keys
810 * are fully generated
812 public void preInsert(CollectionPersister persister
) throws HibernateException
{
816 * Called after inserting a row, to fetch the natively generated id
818 public void afterRowInsert(CollectionPersister persister
, Object entry
, int i
) throws HibernateException
{
822 * get all "orphaned" elements
824 public abstract Collection
getOrphans(Serializable snapshot
, String entityName
) throws HibernateException
;
827 * Get the current session
829 @SuppressWarnings({"JavaDoc"})
830 public final SessionImplementor
getSession() {
834 protected final class IteratorProxy
implements Iterator
{
835 protected final Iterator itr
;
837 public IteratorProxy(Iterator itr
) {
841 public boolean hasNext() {
842 return itr
.hasNext();
845 public Object
next() {
849 public void remove() {
856 protected final class ListIteratorProxy
implements ListIterator
{
857 protected final ListIterator itr
;
859 public ListIteratorProxy(ListIterator itr
) {
863 @SuppressWarnings({"unchecked"})
864 public void add(Object o
) {
869 public boolean hasNext() {
870 return itr
.hasNext();
873 public boolean hasPrevious() {
874 return itr
.hasPrevious();
877 public Object
next() {
881 public int nextIndex() {
882 return itr
.nextIndex();
885 public Object
previous() {
886 return itr
.previous();
889 public int previousIndex() {
890 return itr
.previousIndex();
893 public void remove() {
898 @SuppressWarnings({"unchecked"})
899 public void set(Object o
) {
906 protected class SetProxy
implements java
.util
.Set
{
907 protected final Collection set
;
909 public SetProxy(Collection set
) {
913 @SuppressWarnings({"unchecked"})
914 public boolean add(Object o
) {
919 @SuppressWarnings({"unchecked"})
920 public boolean addAll(Collection c
) {
922 return set
.addAll( c
);
925 public void clear() {
930 public boolean contains(Object o
) {
931 return set
.contains( o
);
934 public boolean containsAll(Collection c
) {
935 return set
.containsAll( c
);
938 public boolean isEmpty() {
939 return set
.isEmpty();
942 public Iterator
iterator() {
943 return new IteratorProxy( set
.iterator() );
946 public boolean remove(Object o
) {
948 return set
.remove( o
);
951 public boolean removeAll(Collection c
) {
953 return set
.removeAll( c
);
956 public boolean retainAll(Collection c
) {
958 return set
.retainAll( c
);
965 public Object
[] toArray() {
966 return set
.toArray();
969 @SuppressWarnings({"unchecked"})
970 public Object
[] toArray(Object
[] array
) {
971 return set
.toArray( array
);
976 protected final class ListProxy
implements java
.util
.List
{
977 protected final List list
;
979 public ListProxy(List list
) {
984 @SuppressWarnings({"unchecked"})
985 public void add(int index
, Object value
) {
987 list
.add( index
, value
);
991 @SuppressWarnings({"unchecked"})
992 public boolean add(Object o
) {
994 return list
.add( o
);
998 @SuppressWarnings({"unchecked"})
999 public boolean addAll(Collection c
) {
1001 return list
.addAll( c
);
1005 @SuppressWarnings({"unchecked"})
1006 public boolean addAll(int i
, Collection c
) {
1008 return list
.addAll( i
, c
);
1012 public void clear() {
1018 public boolean contains(Object o
) {
1019 return list
.contains( o
);
1023 public boolean containsAll(Collection c
) {
1024 return list
.containsAll( c
);
1028 public Object
get(int i
) {
1029 return list
.get( i
);
1033 public int indexOf(Object o
) {
1034 return list
.indexOf( o
);
1038 public boolean isEmpty() {
1039 return list
.isEmpty();
1043 public Iterator
iterator() {
1044 return new IteratorProxy( list
.iterator() );
1048 public int lastIndexOf(Object o
) {
1049 return list
.lastIndexOf( o
);
1053 public ListIterator
listIterator() {
1054 return new ListIteratorProxy( list
.listIterator() );
1058 public ListIterator
listIterator(int i
) {
1059 return new ListIteratorProxy( list
.listIterator( i
) );
1063 public Object
remove(int i
) {
1065 return list
.remove( i
);
1069 public boolean remove(Object o
) {
1071 return list
.remove( o
);
1075 public boolean removeAll(Collection c
) {
1077 return list
.removeAll( c
);
1081 public boolean retainAll(Collection c
) {
1083 return list
.retainAll( c
);
1087 @SuppressWarnings({"unchecked"})
1088 public Object
set(int i
, Object o
) {
1090 return list
.set( i
, o
);
1099 public List
subList(int i
, int j
) {
1100 return list
.subList( i
, j
);
1104 public Object
[] toArray() {
1105 return list
.toArray();
1109 @SuppressWarnings({"unchecked"})
1110 public Object
[] toArray(Object
[] array
) {
1111 return list
.toArray( array
);
1117 * Contract for operations which are part of a collection's operation queue.
1119 protected interface DelayedOperation
{
1120 public void operate();
1122 public Object
getAddedInstance();
1124 public Object
getOrphan();
1128 * Given a collection of entity instances that used to
1129 * belong to the collection, and a collection of instances
1130 * that currently belong, return a collection of orphans
1132 @SuppressWarnings({"JavaDoc", "unchecked"})
1133 protected static Collection
getOrphans(
1134 Collection oldElements
,
1135 Collection currentElements
,
1137 SessionImplementor session
) throws HibernateException
{
1140 if ( currentElements
.size() == 0 ) {
1141 return oldElements
; // no new elements, the old list contains only Orphans
1143 if ( oldElements
.size() == 0 ) {
1144 return oldElements
; // no old elements, so no Orphans neither
1147 final EntityPersister entityPersister
= session
.getFactory().getEntityPersister( entityName
);
1148 final Type idType
= entityPersister
.getIdentifierType();
1150 // create the collection holding the Orphans
1151 Collection res
= new ArrayList();
1153 // collect EntityIdentifier(s) of the *current* elements - add them into a HashSet for fast access
1154 java
.util
.Set currentIds
= new HashSet();
1155 java
.util
.Set currentSaving
= new IdentitySet();
1156 for ( Object current
: currentElements
) {
1157 if ( current
!= null && ForeignKeys
.isNotTransient( entityName
, current
, null, session
) ) {
1158 EntityEntry ee
= session
.getPersistenceContext().getEntry( current
);
1159 if ( ee
!= null && ee
.getStatus() == Status
.SAVING
) {
1160 currentSaving
.add( current
);
1163 Serializable currentId
= ForeignKeys
.getEntityIdentifierIfNotUnsaved(
1168 currentIds
.add( new TypedValue( idType
, currentId
, entityPersister
.getEntityMode() ) );
1173 // iterate over the *old* list
1174 for ( Object old
: oldElements
) {
1175 if ( !currentSaving
.contains( old
) ) {
1176 Serializable oldId
= ForeignKeys
.getEntityIdentifierIfNotUnsaved( entityName
, old
, session
);
1177 if ( !currentIds
.contains( new TypedValue( idType
, oldId
, entityPersister
.getEntityMode() ) ) ) {
1186 public static void identityRemove(
1190 SessionImplementor session
) throws HibernateException
{
1192 if ( object
!= null && ForeignKeys
.isNotTransient( entityName
, object
, null, session
) ) {
1193 final EntityPersister entityPersister
= session
.getFactory().getEntityPersister( entityName
);
1194 Type idType
= entityPersister
.getIdentifierType();
1196 Serializable idOfCurrent
= ForeignKeys
.getEntityIdentifierIfNotUnsaved( entityName
, object
, session
);
1197 Iterator itr
= list
.iterator();
1198 while ( itr
.hasNext() ) {
1199 Serializable idOfOld
= ForeignKeys
.getEntityIdentifierIfNotUnsaved( entityName
, itr
.next(), session
);
1200 if ( idType
.isEqual( idOfCurrent
, idOfOld
, session
.getFactory() ) ) {
1209 public Object
getIdentifier(Object entry
, int i
) {
1210 throw new UnsupportedOperationException();
1213 public Object
getOwner() {
1217 public void setOwner(Object owner
) {
1221 /** ------ Below is section of code which makes remote service calls ----- */
1222 // The affected methods are :
1223 // initialize(final boolean writing)
1225 // readIndexExistence(final Object index)
1226 // readElementExistence(final Object element)
1227 // readElementByIndex(final Object index)
1229 private static ICdmApplicationConfiguration configuration
;
1230 private static boolean remoting
= false;
1232 public static void setConfiguration(ICdmApplicationConfiguration conf
) {
1233 configuration
= conf
;
1234 Boolean isRemoting
= (Boolean
)configuration
.getBean("isRemoting");
1235 if(isRemoting
!= null) {
1236 remoting
= isRemoting
.booleanValue();
1243 private void remoteInitialize() {
1245 if (getOwner() != null && !initialized
) {
1248 String role
= getRole();
1249 String fieldName
= role
.substring(role
.lastIndexOf(".") + 1);
1250 log
.info("--> Remote Lazy Initializing " + getRole() + " , key : " + getKey() + " , field : " + fieldName
);
1251 Object owner
= getOwner();
1253 if(configuration
== null) {
1254 throw new HibernateException("CdmApplicationRemoteConfiguration not initialized (null)");
1256 ICommonService commonService
= configuration
.getCommonService();
1257 if(commonService
== null) {
1258 throw new HibernateException("commonService not initialized (null)");
1261 PersistentCollection col
= commonService
.initializeCollection(this);
1264 Class
<?
> clazz
= getClass();
1265 if (clazz
!= null) {
1266 CollectionField cf
= getCollectionField(col
);
1267 Field field
= clazz
.getDeclaredField(cf
.getFieldName());
1268 field
.setAccessible(true);
1269 field
.set(this, cf
.getCollection());
1271 } catch (Exception ex
) {
1272 log
.warn(ex
.getMessage());
1278 private CollectionField
getCollectionField(PersistentCollection pc
) {
1280 if(pc
instanceof PersistentSet
) {
1281 return new CollectionField(new HashSet((Set
)pc
), "set");
1283 if(pc
instanceof PersistentSortedSet
) {
1284 return new CollectionField(new TreeSet((Set
)pc
), "set");
1286 if(pc
instanceof PersistentList
) {
1287 return new CollectionField(new ArrayList((List
)pc
), "list");
1289 if(pc
instanceof PersistentMap
|| pc
instanceof PersistentMultiLanguageText
) {
1290 return new CollectionField(new HashMap((Map
)pc
), "map");
1292 if(pc
instanceof PersistentSortedMap
) {
1293 return new CollectionField(new TreeMap((Map
)pc
), "map");
1299 private String
getCollectionFieldName(PersistentCollection pc
) {
1301 if(pc
instanceof PersistentSet
|| pc
instanceof PersistentSortedSet
) {
1304 if(pc
instanceof PersistentList
) {
1307 if(pc
instanceof PersistentMap
|| pc
instanceof PersistentMultiLanguageText
) {
1314 private class CollectionField
{
1316 private String fieldName
;
1317 public CollectionField(Object col
, String fieldName
) {
1319 this.fieldName
= fieldName
;
1322 public Object
getCollection() {
1326 public String
getFieldName() {
1327 return this.fieldName
;
1331 public static boolean isInitialized(List list
) {
1332 return ((AbstractPersistentCollection
)list
).initialized
;
1335 public static boolean isInitialized(Map map
) {
1336 return ((AbstractPersistentCollection
)map
).initialized
;
1339 public static boolean isInitialized(Set set
) {
1340 return ((AbstractPersistentCollection
)set
).initialized
;
1343 //FIXME:Remoting These methods may no longer be required since we are
1344 // initialising collections as default behaviour
1345 private int remoteSize() {
1346 int size
= configuration
.getCommonService().size(this);
1347 log
.debug("--> Remote Lazy Initializing size of " + getRole() + " to " + size
);
1349 throw new HibernateException("size of " + getClass() + " could not be retrieved from remote service");
1354 private Object
remoteReadElementByIndex(int index
) {
1355 Object element
= configuration
.getCommonService().get(this,index
);
1356 log
.debug("--> Remote Lazy Initializing element from " + getRole() + " at index " + index
);
1360 private boolean remoteReadElementExistence(Object element
) {
1361 return configuration
.getCommonService().contains(this,element
);
1364 private boolean remoteReadIndexExistence(Object index
) {