ICachedCommonService, CachedCommonServiceImpl : moved class to service package
[taxeditor.git] / eu.etaxonomy.taxeditor.cdmlib / src / main / java / org / hibernate / collection / internal / AbstractPersistentCollection.java
1
2
3 /*
4 * Hibernate, Relational Persistence for Idiomatic Java
5 *
6 * Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
7 * indicated by the @author tags or express copyright attribution
8 * statements applied by the authors. All third-party contributions are
9 * distributed under license by Red Hat Inc.
10 *
11 * This copyrighted material is made available to anyone wishing to use, modify,
12 * copy, or redistribute it subject to the terms and conditions of the GNU
13 * Lesser General Public License, as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
18 * for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this distribution; if not, write to:
22 * Free Software Foundation, Inc.
23 * 51 Franklin Street, Fifth Floor
24 * Boston, MA 02110-1301 USA
25 */
26 package org.hibernate.collection.internal;
27
28 import java.io.Serializable;
29 import java.lang.reflect.Field;
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.Collections;
33 import java.util.HashSet;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.ListIterator;
37
38 import javax.naming.NamingException;
39
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;
61
62 import eu.etaxonomy.cdm.api.application.CdmApplicationRemoteConfiguration;
63 import eu.etaxonomy.taxeditor.remoting.CdmEagerLoadingException;
64 import eu.etaxonomy.taxeditor.service.ICachedCommonService;
65 import eu.etaxonomy.taxeditor.service.CachedCommonServiceImpl.CollectionField;
66
67 /**
68 * Base class implementing {@link org.hibernate.collection.spi.PersistentCollection}
69 *
70 * @author Gavin King
71 */
72 public abstract class AbstractPersistentCollection implements Serializable, PersistentCollection {
73 private static final Logger log = Logger.getLogger( AbstractPersistentCollection.class );
74
75 private static final long serialVersionUID = -7238232378593030571L;
76
77 private transient SessionImplementor session;
78 private boolean initialized;
79 private transient List<DelayedOperation> operationQueue;
80 private transient boolean directlyAccessible;
81 private transient boolean initializing;
82 private Object owner;
83 private int cachedSize = -1;
84
85 private String role;
86 private Serializable key;
87 // collections detect changes made via their public interface and mark
88 // themselves as dirty as a performance optimization
89 private boolean dirty;
90 private Serializable storedSnapshot;
91
92 private String sessionFactoryUuid;
93 private boolean specjLazyLoad = false;
94
95 @Override
96 public final String getRole() {
97 return role;
98 }
99
100 @Override
101 public final Serializable getKey() {
102 return key;
103 }
104
105 @Override
106 public final boolean isUnreferenced() {
107 return role == null;
108 }
109
110 @Override
111 public final boolean isDirty() {
112 return dirty;
113 }
114
115 @Override
116 public final void clearDirty() {
117 dirty = false;
118 }
119
120 @Override
121 public final void dirty() {
122 dirty = true;
123 }
124
125 @Override
126 public final Serializable getStoredSnapshot() {
127 return storedSnapshot;
128 }
129
130 //Careful: these methods do not initialize the collection.
131
132 /**
133 * Is the initialized collection empty?
134 */
135 @Override
136 public abstract boolean empty();
137
138 /**
139 * Called by any read-only method of the collection interface
140 */
141 protected final void read() {
142 initialize( false );
143 }
144
145 /**
146 * Called by the {@link Collection#size} method
147 */
148 @SuppressWarnings({"JavaDoc"})
149 protected boolean readSize() {
150 if ( !initialized ) {
151 if ( cachedSize != -1 && !hasQueuedOperations() ) {
152 return true;
153 }
154 else {
155 // In remoting we are sure that session is null
156 // both when using property paths and switching off conversations
157 if(session == null && remoting) {
158 log.info("--> readSize, of " + getRole() + " with key " + getKey());
159 read();
160 } else {
161 boolean isExtraLazy = withTemporarySessionIfNeeded(
162 new LazyInitializationWork<Boolean>() {
163 @Override
164 public Boolean doWork() {
165 CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection.this );
166
167 if ( entry != null ) {
168 CollectionPersister persister = entry.getLoadedPersister();
169 if ( persister.isExtraLazy() ) {
170 if ( hasQueuedOperations() ) {
171 session.flush();
172 }
173 cachedSize = persister.getSize( entry.getLoadedKey(), session );
174 return true;
175 }
176 else {
177 read();
178 }
179 }
180 else{
181 throwLazyInitializationExceptionIfNotConnected();
182 }
183 return false;
184 }
185 }
186 );
187 if ( isExtraLazy ) {
188 return true;
189 }
190 }
191 }
192 }
193 return false;
194 }
195
196 public static interface LazyInitializationWork<T> {
197 public T doWork();
198 }
199
200 private <T> T withTemporarySessionIfNeeded(LazyInitializationWork<T> lazyInitializationWork) {
201 SessionImplementor originalSession = null;
202 boolean isTempSession = false;
203 boolean isJTA = false;
204
205 if ( session == null ) {
206 if ( specjLazyLoad ) {
207 session = openTemporarySessionForLoading();
208 isTempSession = true;
209 }
210 else {
211 throwLazyInitializationException( "could not initialize proxy - no Session" );
212 }
213 }
214 else if ( !session.isOpen() ) {
215 if ( specjLazyLoad ) {
216 originalSession = session;
217 session = openTemporarySessionForLoading();
218 isTempSession = true;
219 }
220 else {
221 throwLazyInitializationException( "could not initialize proxy - the owning Session was closed" );
222 }
223 }
224 else if ( !session.isConnected() ) {
225 if ( specjLazyLoad ) {
226 originalSession = session;
227 session = openTemporarySessionForLoading();
228 isTempSession = true;
229 }
230 else {
231 throwLazyInitializationException( "could not initialize proxy - the owning Session is disconnected" );
232 }
233 }
234
235 if ( isTempSession ) {
236 // TODO: On the next major release, add an
237 // 'isJTA' or 'getTransactionFactory' method to Session.
238 isJTA = session.getTransactionCoordinator()
239 .getTransactionContext().getTransactionEnvironment()
240 .getTransactionFactory()
241 .compatibleWithJtaSynchronization();
242
243 if ( !isJTA ) {
244 // Explicitly handle the transactions only if we're not in
245 // a JTA environment. A lazy loading temporary session can
246 // be created even if a current session and transaction are
247 // open (ex: session.clear() was used). We must prevent
248 // multiple transactions.
249 ( ( Session) session ).beginTransaction();
250 }
251
252 session.getPersistenceContext().addUninitializedDetachedCollection(
253 session.getFactory().getCollectionPersister( getRole() ),
254 this
255 );
256 }
257
258 try {
259 return lazyInitializationWork.doWork();
260 }
261 finally {
262 if ( isTempSession ) {
263 // make sure the just opened temp session gets closed!
264 try {
265 if ( !isJTA ) {
266 ( ( Session) session ).getTransaction().commit();
267 }
268 ( (Session) session ).close();
269 }
270 catch (Exception e) {
271 log.warn( "Unable to close temporary session used to load lazy collection associated to no session" );
272 }
273 session = originalSession;
274 }
275 }
276 }
277
278 private SessionImplementor openTemporarySessionForLoading() {
279 if ( sessionFactoryUuid == null ) {
280 throwLazyInitializationException( "SessionFactory UUID not known to create temporary Session for loading" );
281 }
282
283 SessionFactoryImplementor sf = (SessionFactoryImplementor)
284 SessionFactoryRegistry.INSTANCE.getSessionFactory( sessionFactoryUuid );
285 return (SessionImplementor) sf.openSession();
286 }
287
288 protected Boolean readIndexExistence(final Object index) {
289 if ( !initialized ) {
290 // In remoting we are sure that session is null
291 // both when using property paths and switching off conversations
292 if(session == null && remoting) {
293 log.info("--> readIndexExistence, of " + getRole() + " with key " + getKey());
294 read();
295 } else {
296 Boolean extraLazyExistenceCheck = withTemporarySessionIfNeeded(
297 new LazyInitializationWork<Boolean>() {
298 @Override
299 public Boolean doWork() {
300 CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection.this );
301 CollectionPersister persister = entry.getLoadedPersister();
302 if ( persister.isExtraLazy() ) {
303 if ( hasQueuedOperations() ) {
304 session.flush();
305 }
306 return persister.indexExists( entry.getLoadedKey(), index, session );
307 }
308 else {
309 read();
310 }
311 return null;
312 }
313 }
314 );
315 if ( extraLazyExistenceCheck != null ) {
316 return extraLazyExistenceCheck;
317 }
318 }
319 }
320 return null;
321 }
322
323 protected Boolean readElementExistence(final Object element) {
324 if ( !initialized ) {
325 // In remoting we are sure that session is null
326 // both when using property paths and switching off conversations
327 if(session == null && remoting) {
328 log.info("--> readElementExistence, of " + getRole() + " with key " + getKey());
329 read();
330
331 } else {
332 Boolean extraLazyExistenceCheck = withTemporarySessionIfNeeded(
333 new LazyInitializationWork<Boolean>() {
334 @Override
335 public Boolean doWork() {
336 CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection.this );
337 CollectionPersister persister = entry.getLoadedPersister();
338 if ( persister.isExtraLazy() ) {
339 if ( hasQueuedOperations() ) {
340 session.flush();
341 }
342 return persister.elementExists( entry.getLoadedKey(), element, session );
343 }
344 else {
345 read();
346 }
347 return null;
348 }
349 }
350 );
351 if ( extraLazyExistenceCheck != null ) {
352 return extraLazyExistenceCheck;
353 }
354 }
355 }
356 return null;
357 }
358
359 protected static final Object UNKNOWN = new MarkerObject( "UNKNOWN" );
360
361 protected Object readElementByIndex(final Object index) {
362 if ( !initialized ) {
363 // In remoting we are sure that session is null
364 // both when using property paths and switching off conversations
365 if(session == null && remoting) {
366 log.info("--> readElementByIndex, of " + getRole() + " with key " + getKey());
367 read();
368
369 } else {
370 class ExtraLazyElementByIndexReader implements LazyInitializationWork {
371 private boolean isExtraLazy;
372 private Object element;
373
374 @Override
375 public Object doWork() {
376 CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( AbstractPersistentCollection.this );
377 CollectionPersister persister = entry.getLoadedPersister();
378 isExtraLazy = persister.isExtraLazy();
379 if ( isExtraLazy ) {
380 if ( hasQueuedOperations() ) {
381 session.flush();
382 }
383 element = persister.getElementByIndex( entry.getLoadedKey(), index, session, owner );
384 }
385 else {
386 read();
387 }
388 return null;
389 }
390 }
391
392 ExtraLazyElementByIndexReader reader = new ExtraLazyElementByIndexReader();
393 //noinspection unchecked
394 withTemporarySessionIfNeeded( reader );
395 if ( reader.isExtraLazy ) {
396 return reader.element;
397 }
398 }
399 }
400 return UNKNOWN;
401
402 }
403
404 protected int getCachedSize() {
405 return cachedSize;
406 }
407
408 private boolean isConnectedToSession() {
409 return session != null &&
410 session.isOpen() &&
411 session.getPersistenceContext().containsCollection( this );
412 }
413
414 /**
415 * Called by any writer method of the collection interface
416 */
417 protected final void write() {
418 initialize( true );
419 dirty();
420 }
421
422 /**
423 * Is this collection in a state that would allow us to
424 * "queue" operations?
425 */
426 @SuppressWarnings({"JavaDoc"})
427 protected boolean isOperationQueueEnabled() {
428 return !initialized &&
429 isConnectedToSession() &&
430 isInverseCollection();
431 }
432
433 /**
434 * Is this collection in a state that would allow us to
435 * "queue" puts? This is a special case, because of orphan
436 * delete.
437 */
438 @SuppressWarnings({"JavaDoc"})
439 protected boolean isPutQueueEnabled() {
440 return !initialized &&
441 isConnectedToSession() &&
442 isInverseOneToManyOrNoOrphanDelete();
443 }
444
445 /**
446 * Is this collection in a state that would allow us to
447 * "queue" clear? This is a special case, because of orphan
448 * delete.
449 */
450 @SuppressWarnings({"JavaDoc"})
451 protected boolean isClearQueueEnabled() {
452 return !initialized &&
453 isConnectedToSession() &&
454 isInverseCollectionNoOrphanDelete();
455 }
456
457 /**
458 * Is this the "inverse" end of a bidirectional association?
459 */
460 @SuppressWarnings({"JavaDoc"})
461 private boolean isInverseCollection() {
462 CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
463 return ce != null && ce.getLoadedPersister().isInverse();
464 }
465
466 /**
467 * Is this the "inverse" end of a bidirectional association with
468 * no orphan delete enabled?
469 */
470 @SuppressWarnings({"JavaDoc"})
471 private boolean isInverseCollectionNoOrphanDelete() {
472 CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
473 return ce != null &&
474 ce.getLoadedPersister().isInverse() &&
475 !ce.getLoadedPersister().hasOrphanDelete();
476 }
477
478 /**
479 * Is this the "inverse" end of a bidirectional one-to-many, or
480 * of a collection with no orphan delete?
481 */
482 @SuppressWarnings({"JavaDoc"})
483 private boolean isInverseOneToManyOrNoOrphanDelete() {
484 CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
485 return ce != null && ce.getLoadedPersister().isInverse() && (
486 ce.getLoadedPersister().isOneToMany() ||
487 !ce.getLoadedPersister().hasOrphanDelete()
488 );
489 }
490
491 /**
492 * Queue an addition
493 */
494 @SuppressWarnings({"JavaDoc"})
495 protected final void queueOperation(DelayedOperation operation) {
496 if ( operationQueue == null ) {
497 operationQueue = new ArrayList<DelayedOperation>( 10 );
498 }
499 operationQueue.add( operation );
500 dirty = true; //needed so that we remove this collection from the second-level cache
501 }
502
503 /**
504 * After reading all existing elements from the database,
505 * add the queued elements to the underlying collection.
506 */
507 protected final void performQueuedOperations() {
508 for ( DelayedOperation operation : operationQueue ) {
509 operation.operate();
510 }
511 }
512
513 /**
514 * After flushing, re-init snapshot state.
515 */
516 @Override
517 public void setSnapshot(Serializable key, String role, Serializable snapshot) {
518 this.key = key;
519 this.role = role;
520 this.storedSnapshot = snapshot;
521 }
522
523 /**
524 * After flushing, clear any "queued" additions, since the
525 * database state is now synchronized with the memory state.
526 */
527 @Override
528 public void postAction() {
529 operationQueue = null;
530 cachedSize = -1;
531 clearDirty();
532 }
533
534 /**
535 * Not called by Hibernate, but used by non-JDK serialization,
536 * eg. SOAP libraries.
537 */
538 public AbstractPersistentCollection() {
539 }
540
541 protected AbstractPersistentCollection(SessionImplementor session) {
542 this.session = session;
543 }
544
545 /**
546 * return the user-visible collection (or array) instance
547 */
548 @Override
549 public Object getValue() {
550 return this;
551 }
552
553 /**
554 * Called just before reading any rows from the JDBC result set
555 */
556 @Override
557 public void beginRead() {
558 // override on some subclasses
559 initializing = true;
560 }
561
562 /**
563 * Called after reading all rows from the JDBC result set
564 */
565 @Override
566 public boolean endRead() {
567 //override on some subclasses
568 return afterInitialize();
569 }
570
571 @Override
572 public boolean afterInitialize() {
573 setInitialized();
574 //do this bit after setting initialized to true or it will recurse
575 if ( operationQueue != null ) {
576 performQueuedOperations();
577 operationQueue = null;
578 cachedSize = -1;
579 return false;
580 }
581 else {
582 return true;
583 }
584 }
585
586 /**
587 * Initialize the collection, if possible, wrapping any exceptions
588 * in a runtime exception
589 *
590 * @param writing currently obsolete
591 *
592 * @throws LazyInitializationException if we cannot initialize
593 */
594 protected final void initialize(final boolean writing) {
595 // In remoting we are sure that session is null
596 // both when using property paths and switching off conversations
597 if(session == null && remoting) {
598 remoteInitialize();
599 }
600
601 if ( initialized ) {
602 return;
603 }
604
605
606 withTemporarySessionIfNeeded(
607 new LazyInitializationWork<Object>() {
608 @Override
609 public Object doWork() {
610 session.initializeCollection( AbstractPersistentCollection.this, writing );
611 return null;
612 }
613 }
614 );
615 }
616
617 private void throwLazyInitializationExceptionIfNotConnected() {
618 if ( !isConnectedToSession() ) {
619 throwLazyInitializationException( "no session or session was closed" );
620 }
621 if ( !session.isConnected() ) {
622 throwLazyInitializationException( "session is disconnected" );
623 }
624 }
625
626 private void throwLazyInitializationException(String message) {
627 throw new LazyInitializationException(
628 "failed to lazily initialize a collection" +
629 (role == null ? "" : " of role: " + role) +
630 ", " + message
631 );
632 }
633
634 protected final void setInitialized() {
635 this.initializing = false;
636 this.initialized = true;
637 }
638
639 protected final void setDirectlyAccessible(boolean directlyAccessible) {
640 this.directlyAccessible = directlyAccessible;
641 }
642
643 /**
644 * Could the application possibly have a direct reference to
645 * the underlying collection implementation?
646 */
647 @Override
648 public boolean isDirectlyAccessible() {
649 return directlyAccessible;
650 }
651
652 /**
653 * Disassociate this collection from the given session.
654 *
655 * @return true if this was currently associated with the given session
656 */
657 @Override
658 public final boolean unsetSession(SessionImplementor currentSession) {
659 prepareForPossibleSpecialSpecjInitialization();
660 if ( currentSession == this.session ) {
661 this.session = null;
662 return true;
663 }
664 else {
665 return false;
666 }
667 }
668
669 protected void prepareForPossibleSpecialSpecjInitialization() {
670 if ( session != null ) {
671 specjLazyLoad = session.getFactory().getSettings().isInitializeLazyStateOutsideTransactionsEnabled();
672
673 if ( specjLazyLoad && sessionFactoryUuid == null ) {
674 try {
675 sessionFactoryUuid = (String) session.getFactory().getReference().get( "uuid" ).getContent();
676 }
677 catch (NamingException e) {
678 //not much we can do if this fails...
679 }
680 }
681 }
682 }
683
684
685 /**
686 * Associate the collection with the given session.
687 *
688 * @return false if the collection was already associated with the session
689 *
690 * @throws HibernateException if the collection was already associated
691 * with another open session
692 */
693 @Override
694 public final boolean setCurrentSession(SessionImplementor session) throws HibernateException {
695 if ( session == this.session ) {
696 return false;
697 }
698 else {
699 if ( isConnectedToSession() ) {
700 CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
701 if ( ce == null ) {
702 throw new HibernateException(
703 "Illegal attempt to associate a collection with two open sessions"
704 );
705 }
706 else {
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
712 )
713 );
714 }
715 }
716 else {
717 this.session = session;
718 return true;
719 }
720 }
721 }
722
723 /**
724 * Do we need to completely recreate this collection when it changes?
725 */
726 @Override
727 public boolean needsRecreate(CollectionPersister persister) {
728 return false;
729 }
730
731 /**
732 * To be called internally by the session, forcing
733 * immediate initialization.
734 */
735 @Override
736 public final void forceInitialization() throws HibernateException {
737 if ( !initialized ) {
738 if ( initializing ) {
739 throw new AssertionFailure( "force initialize loading collection" );
740 }
741 if ( session == null ) {
742 throw new HibernateException( "collection is not associated with any session" );
743 }
744 if ( !session.isConnected() ) {
745 throw new HibernateException( "disconnected session" );
746 }
747 session.initializeCollection( this, false );
748 }
749 }
750
751
752 /**
753 * Get the current snapshot from the session
754 */
755 @SuppressWarnings({"JavaDoc"})
756 protected final Serializable getSnapshot() {
757 return session.getPersistenceContext().getSnapshot( this );
758 }
759
760 /**
761 * Is this instance initialized?
762 */
763 @Override
764 public final boolean wasInitialized() {
765 return initialized;
766 }
767
768 @Override
769 public boolean isRowUpdatePossible() {
770 return true;
771 }
772
773 /**
774 * Does this instance have any "queued" additions?
775 */
776 @Override
777 public final boolean hasQueuedOperations() {
778 return operationQueue != null;
779 }
780
781 /**
782 * Iterate the "queued" additions
783 */
784 @Override
785 public final Iterator queuedAdditionIterator() {
786 if ( hasQueuedOperations() ) {
787 return new Iterator() {
788 int i = 0;
789
790 @Override
791 public Object next() {
792 return operationQueue.get( i++ ).getAddedInstance();
793 }
794
795 @Override
796 public boolean hasNext() {
797 return i < operationQueue.size();
798 }
799
800 @Override
801 public void remove() {
802 throw new UnsupportedOperationException();
803 }
804 };
805 }
806 else {
807 return EmptyIterator.INSTANCE;
808 }
809 }
810
811 /**
812 * Iterate the "queued" additions
813 */
814 @Override
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() );
823 }
824 return getOrphans( removals, additions, entityName, session );
825 }
826 else {
827 return Collections.EMPTY_LIST;
828 }
829 }
830
831 /**
832 * Called before inserting rows, to ensure that any surrogate keys
833 * are fully generated
834 */
835 @Override
836 public void preInsert(CollectionPersister persister) throws HibernateException {
837 }
838
839 /**
840 * Called after inserting a row, to fetch the natively generated id
841 */
842 @Override
843 public void afterRowInsert(CollectionPersister persister, Object entry, int i) throws HibernateException {
844 }
845
846 /**
847 * get all "orphaned" elements
848 */
849 @Override
850 public abstract Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException;
851
852 /**
853 * Get the current session
854 */
855 @SuppressWarnings({"JavaDoc"})
856 public final SessionImplementor getSession() {
857 return session;
858 }
859
860 protected final class IteratorProxy implements Iterator {
861 protected final Iterator itr;
862
863 public IteratorProxy(Iterator itr) {
864 this.itr = itr;
865 }
866
867 @Override
868 public boolean hasNext() {
869 return itr.hasNext();
870 }
871
872 @Override
873 public Object next() {
874 return itr.next();
875 }
876
877 @Override
878 public void remove() {
879 write();
880 itr.remove();
881 }
882
883 }
884
885 protected final class ListIteratorProxy implements ListIterator {
886 protected final ListIterator itr;
887
888 public ListIteratorProxy(ListIterator itr) {
889 this.itr = itr;
890 }
891
892 @Override
893 @SuppressWarnings({"unchecked"})
894 public void add(Object o) {
895 write();
896 itr.add( o );
897 }
898
899 @Override
900 public boolean hasNext() {
901 return itr.hasNext();
902 }
903
904 @Override
905 public boolean hasPrevious() {
906 return itr.hasPrevious();
907 }
908
909 @Override
910 public Object next() {
911 return itr.next();
912 }
913
914 @Override
915 public int nextIndex() {
916 return itr.nextIndex();
917 }
918
919 @Override
920 public Object previous() {
921 return itr.previous();
922 }
923
924 @Override
925 public int previousIndex() {
926 return itr.previousIndex();
927 }
928
929 @Override
930 public void remove() {
931 write();
932 itr.remove();
933 }
934
935 @Override
936 @SuppressWarnings({"unchecked"})
937 public void set(Object o) {
938 write();
939 itr.set( o );
940 }
941
942 }
943
944 protected class SetProxy implements java.util.Set {
945 protected final Collection set;
946
947 public SetProxy(Collection set) {
948 this.set = set;
949 }
950
951 @Override
952 @SuppressWarnings({"unchecked"})
953 public boolean add(Object o) {
954 write();
955 return set.add( o );
956 }
957
958 @Override
959 @SuppressWarnings({"unchecked"})
960 public boolean addAll(Collection c) {
961 write();
962 return set.addAll( c );
963 }
964
965 @Override
966 public void clear() {
967 write();
968 set.clear();
969 }
970
971 @Override
972 public boolean contains(Object o) {
973 return set.contains( o );
974 }
975
976 @Override
977 public boolean containsAll(Collection c) {
978 return set.containsAll( c );
979 }
980
981 @Override
982 public boolean isEmpty() {
983 return set.isEmpty();
984 }
985
986 @Override
987 public Iterator iterator() {
988 return new IteratorProxy( set.iterator() );
989 }
990
991 @Override
992 public boolean remove(Object o) {
993 write();
994 return set.remove( o );
995 }
996
997 @Override
998 public boolean removeAll(Collection c) {
999 write();
1000 return set.removeAll( c );
1001 }
1002
1003 @Override
1004 public boolean retainAll(Collection c) {
1005 write();
1006 return set.retainAll( c );
1007 }
1008
1009 @Override
1010 public int size() {
1011 return set.size();
1012 }
1013
1014 @Override
1015 public Object[] toArray() {
1016 return set.toArray();
1017 }
1018
1019 @Override
1020 @SuppressWarnings({"unchecked"})
1021 public Object[] toArray(Object[] array) {
1022 return set.toArray( array );
1023 }
1024
1025 }
1026
1027 protected final class ListProxy implements java.util.List {
1028 protected final List list;
1029
1030 public ListProxy(List list) {
1031 this.list = list;
1032 }
1033
1034 @Override
1035 @SuppressWarnings({"unchecked"})
1036 public void add(int index, Object value) {
1037 write();
1038 list.add( index, value );
1039 }
1040
1041 @Override
1042 @SuppressWarnings({"unchecked"})
1043 public boolean add(Object o) {
1044 write();
1045 return list.add( o );
1046 }
1047
1048 @Override
1049 @SuppressWarnings({"unchecked"})
1050 public boolean addAll(Collection c) {
1051 write();
1052 return list.addAll( c );
1053 }
1054
1055 @Override
1056 @SuppressWarnings({"unchecked"})
1057 public boolean addAll(int i, Collection c) {
1058 write();
1059 return list.addAll( i, c );
1060 }
1061
1062 @Override
1063 public void clear() {
1064 write();
1065 list.clear();
1066 }
1067
1068 @Override
1069 public boolean contains(Object o) {
1070 return list.contains( o );
1071 }
1072
1073 @Override
1074 public boolean containsAll(Collection c) {
1075 return list.containsAll( c );
1076 }
1077
1078 @Override
1079 public Object get(int i) {
1080 return list.get( i );
1081 }
1082
1083 @Override
1084 public int indexOf(Object o) {
1085 return list.indexOf( o );
1086 }
1087
1088 @Override
1089 public boolean isEmpty() {
1090 return list.isEmpty();
1091 }
1092
1093 @Override
1094 public Iterator iterator() {
1095 return new IteratorProxy( list.iterator() );
1096 }
1097
1098 @Override
1099 public int lastIndexOf(Object o) {
1100 return list.lastIndexOf( o );
1101 }
1102
1103 @Override
1104 public ListIterator listIterator() {
1105 return new ListIteratorProxy( list.listIterator() );
1106 }
1107
1108 @Override
1109 public ListIterator listIterator(int i) {
1110 return new ListIteratorProxy( list.listIterator( i ) );
1111 }
1112
1113 @Override
1114 public Object remove(int i) {
1115 write();
1116 return list.remove( i );
1117 }
1118
1119 @Override
1120 public boolean remove(Object o) {
1121 write();
1122 return list.remove( o );
1123 }
1124
1125 @Override
1126 public boolean removeAll(Collection c) {
1127 write();
1128 return list.removeAll( c );
1129 }
1130
1131 @Override
1132 public boolean retainAll(Collection c) {
1133 write();
1134 return list.retainAll( c );
1135 }
1136
1137 @Override
1138 @SuppressWarnings({"unchecked"})
1139 public Object set(int i, Object o) {
1140 write();
1141 return list.set( i, o );
1142 }
1143
1144 @Override
1145 public int size() {
1146 return list.size();
1147 }
1148
1149 @Override
1150 public List subList(int i, int j) {
1151 return list.subList( i, j );
1152 }
1153
1154 @Override
1155 public Object[] toArray() {
1156 return list.toArray();
1157 }
1158
1159 @Override
1160 @SuppressWarnings({"unchecked"})
1161 public Object[] toArray(Object[] array) {
1162 return list.toArray( array );
1163 }
1164
1165 }
1166
1167 /**
1168 * Contract for operations which are part of a collection's operation queue.
1169 */
1170 protected interface DelayedOperation {
1171 public void operate();
1172
1173 public Object getAddedInstance();
1174
1175 public Object getOrphan();
1176 }
1177
1178 /**
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
1182 */
1183 @SuppressWarnings({"JavaDoc", "unchecked"})
1184 protected static Collection getOrphans(
1185 Collection oldElements,
1186 Collection currentElements,
1187 String entityName,
1188 SessionImplementor session) throws HibernateException {
1189
1190 // short-circuit(s)
1191 if ( currentElements.size() == 0 ) {
1192 return oldElements; // no new elements, the old list contains only Orphans
1193 }
1194 if ( oldElements.size() == 0 ) {
1195 return oldElements; // no old elements, so no Orphans neither
1196 }
1197
1198 final EntityPersister entityPersister = session.getFactory().getEntityPersister( entityName );
1199 final Type idType = entityPersister.getIdentifierType();
1200
1201 // create the collection holding the Orphans
1202 Collection res = new ArrayList();
1203
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 );
1212 }
1213 else {
1214 Serializable currentId = ForeignKeys.getEntityIdentifierIfNotUnsaved(
1215 entityName,
1216 current,
1217 session
1218 );
1219 currentIds.add( new TypedValue( idType, currentId, entityPersister.getEntityMode() ) );
1220 }
1221 }
1222 }
1223
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() ) ) ) {
1229 res.add( old );
1230 }
1231 }
1232 }
1233
1234 return res;
1235 }
1236
1237 public static void identityRemove(
1238 Collection list,
1239 Object object,
1240 String entityName,
1241 SessionImplementor session) throws HibernateException {
1242
1243 if ( object != null && ForeignKeys.isNotTransient( entityName, object, null, session ) ) {
1244 final EntityPersister entityPersister = session.getFactory().getEntityPersister( entityName );
1245 Type idType = entityPersister.getIdentifierType();
1246
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() ) ) {
1252 itr.remove();
1253 break;
1254 }
1255 }
1256
1257 }
1258 }
1259
1260 @Override
1261 public Object getIdentifier(Object entry, int i) {
1262 throw new UnsupportedOperationException();
1263 }
1264
1265 @Override
1266 public Object getOwner() {
1267 return owner;
1268 }
1269
1270 @Override
1271 public void setOwner(Object owner) {
1272 this.owner = owner;
1273 }
1274
1275 /** ------ Below is section of code which makes remote service calls ----- */
1276 // The affected methods are :
1277 // initialize(final boolean writing)
1278 // readSize()
1279 // readIndexExistence(final Object index)
1280 // readElementExistence(final Object element)
1281 // readElementByIndex(final Object index)
1282
1283 private static CdmApplicationRemoteConfiguration configuration;
1284 private static boolean remoting = false;
1285
1286 public static void setConfiguration(CdmApplicationRemoteConfiguration conf) {
1287 remoting = true;
1288 configuration = conf;
1289 }
1290
1291
1292 private void remoteInitialize() {
1293
1294 if (getOwner() != null && !initialized) {
1295
1296 try {
1297 String role = getRole();
1298 String fieldName = role.substring(role.lastIndexOf(".") + 1);
1299 log.info("--> Remote Lazy Initializing Collection " + getRole() + " , key : " + getKey() + " , field : " + fieldName);
1300 Object owner = getOwner();
1301
1302 if(configuration == null) {
1303 throw new HibernateException("CdmApplicationRemoteConfiguration not initialized (null)");
1304 }
1305 ICachedCommonService cachedCommonService = configuration.getCachedCommonService();
1306 if(cachedCommonService == null) {
1307 throw new HibernateException("commonService not initialized (null)");
1308 }
1309
1310 PersistentCollection col = cachedCommonService.initializeCollection(this);
1311 afterInitialize();
1312
1313 Class<?> clazz = getClass();
1314 if (clazz != null) {
1315 CollectionField cf = cachedCommonService.getCollectionField(col);
1316 cachedCommonService.updatePersistentCollection(cf);
1317 Field field = clazz.getDeclaredField(cf.getType().toString());
1318 field.setAccessible(true);
1319 field.set(this, cf.getCollection());
1320 }
1321 } catch (Exception ex) {
1322 throw new CdmEagerLoadingException(ex);
1323 }
1324 }
1325 }
1326
1327
1328
1329 }
1330