Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/hibernate/collection/AbstractPersistentCollection.java


1   //$Id: AbstractPersistentCollection.java,v 1.17 2005/04/02 20:33:53 oneovthafew Exp $
2   package org.hibernate.collection;
3   
4   import java.io.Serializable;
5   import java.util.ArrayList;
6   import java.util.Collection;
7   import java.util.HashSet;
8   import java.util.Iterator;
9   import java.util.List;
10  import java.util.ListIterator;
11  
12  import org.hibernate.AssertionFailure;
13  import org.hibernate.HibernateException;
14  import org.hibernate.LazyInitializationException;
15  import org.hibernate.engine.CollectionSnapshot;
16  import org.hibernate.engine.ForeignKeys;
17  import org.hibernate.engine.SessionImplementor;
18  import org.hibernate.engine.TypedValue;
19  import org.hibernate.persister.collection.CollectionPersister;
20  import org.hibernate.type.Type;
21  import org.hibernate.util.EmptyIterator;
22  
23  /**
24   * Base class implementing <tt>PersistentCollection</tt>
25   * @see PersistentCollection
26   * @author Gavin King
27   */
28  public abstract class AbstractPersistentCollection 
29    implements Serializable, PersistentCollection {
30  
31    private transient SessionImplementor session;
32    private boolean initialized;
33    private transient List additions;
34    private CollectionSnapshot collectionSnapshot;
35    private transient boolean directlyAccessible;
36    private transient boolean initializing;
37    private Object owner;
38  
39    //Careful: these methods do not initialize the collection.
40    /**
41     * Is the initialized collection empty?
42     */
43    public abstract boolean empty();
44    /**
45     * Called by any read-only method of the collection interface
46     */
47    protected final void read() {
48      initialize(false);
49    }
50    /**
51     * Is the collection currently connected to an open session?
52     */
53    private final boolean isConnectedToSession() {
54      return session!=null && session.isOpen();
55    }
56  
57    /**
58     * Called by any writer method of the collection interface
59     */
60    protected final void write() {
61      initialize(true);
62      collectionSnapshot.setDirty();
63    }
64    /**
65     * Is this collection in a state that would allow us to
66     * "queue" additions?
67     */
68    private boolean isQueueAdditionEnabled() {
69      return !initialized &&
70        isConnectedToSession() &&
71        session.getPersistenceContext().isInverseCollection(this);
72    }
73    /**
74     * Queue an addition
75     */
76    protected final boolean queueAdd(Object element) {
77      if ( isQueueAdditionEnabled() ) {
78        if (additions==null) additions = new ArrayList(10);
79        additions.add(element);
80        collectionSnapshot.setDirty(); //needed so that we remove this collection from the second-level cache
81        return true;
82      }
83      else {
84        return false;
85      }
86    }
87    /**
88     * Queue additions
89     */
90    protected final boolean queueAddAll(Collection coll) {
91      if ( isQueueAdditionEnabled() ) {
92        if (additions==null) additions = new ArrayList(20);
93        additions.addAll(coll);
94        return true;
95      }
96      else {
97        return false;
98      }
99    }
100 
101   /**
102    * After reading all existing elements from the database,
103    * add the queued elements to the underlying collection.
104    */
105   public void delayedAddAll(Collection coll) {
106     throw new AssertionFailure("Collection does not support delayed initialization");
107   }
108 
109   /**
110    * After flushing, clear any "queued" additions, since the
111    * database state is now synchronized with the memory state.
112    */
113   public void postFlush() {
114     if (additions!=null) additions=null;
115   }
116 
117   /**
118    * Not called by Hibernate, but used by non-JDK serialization,
119    * eg. SOAP libraries.
120    */
121   public AbstractPersistentCollection() {}
122 
123   protected AbstractPersistentCollection(SessionImplementor session) {
124     this.session = session;
125   }
126 
127   /**
128    * return the user-visible collection (or array) instance
129    */
130   public Object getValue() {
131     return this;
132   }
133 
134   /**
135    * Called just before reading any rows from the JDBC result set
136    */
137   public void beginRead() {
138     // override on some subclasses
139     initializing = true;
140   }
141 
142   /**
143    * Called after reading all rows from the JDBC result set
144    */
145   public boolean endRead() {
146     //override on some subclasses
147 
148     setInitialized();
149     //do this bit after setting initialized to true or it will recurse
150     if (additions!=null) {
151       delayedAddAll(additions);
152       additions=null;
153       return false;
154     }
155     else {
156       return true;
157     }
158   }
159 
160   /**
161    * Initialize the collection, if possible, wrapping any exceptions
162    * in a runtime exception
163    * @param writing currently obsolete
164    * @throws LazyInitializationException if we cannot initialize
165    */
166   protected final void initialize(boolean writing) {
167     if (!initialized) {
168       if (initializing) throw new LazyInitializationException("cannot access loading collection");
169       if ( isConnectedToSession() )  {
170         if ( session.isConnected() ) {
171           session.initializeCollection(this, writing);
172         }
173         else {
174                     String name = (getCollectionSnapshot()!=null)?"("+getCollectionSnapshot().getRole()+")":"";
175           throw new LazyInitializationException("failed to lazily initialize a collection " + name + " - session is disconnected");
176         }
177       }
178       else {
179                 String name = (getCollectionSnapshot()!=null)?"("+getCollectionSnapshot().getRole()+")":"";
180         throw new LazyInitializationException("failed to lazily initialize a collection " + name + " - no session or session was closed");
181       }
182     }
183   }
184 
185   protected final void setInitialized() {
186     this.initializing = false;
187     this.initialized = true;
188   }
189 
190   protected final void setDirectlyAccessible(boolean directlyAccessible) {
191     this.directlyAccessible = directlyAccessible;
192   }
193 
194   /**
195    * Could the application possibly have a direct reference to
196    * the underlying collection implementation?
197    */
198   public boolean isDirectlyAccessible() {
199     return directlyAccessible;
200   }
201 
202   /**
203    * Disassociate this collection from the given session.
204    * @return true if this was currently associated with the given session
205    */
206   public final boolean unsetSession(SessionImplementor currentSession) {
207     if (currentSession==this.session) {
208       this.session=null;
209       return true;
210     }
211     else {
212       return false;
213     }
214   }
215 
216   /**
217    * Associate the collection with the given session.
218    * @return false if the collection was already associated with the session
219    * @throws HibernateException if the collection was already associated
220    * with another open session
221    */
222   public final boolean setCurrentSession(SessionImplementor session) throws HibernateException {
223     if (session==this.session) {
224       return false;
225     }
226     else {
227       if ( isConnectedToSession() ) {
228         throw new HibernateException("Illegal attempt to associate a collection with two open sessions");
229       }
230       else {
231         this.session = session;
232         return true;
233       }
234     }
235   }
236 
237   /**
238    * Do we need to completely recreate this collection when it changes?
239    */
240   public boolean needsRecreate(CollectionPersister persister) {
241     return false;
242   }
243   /**
244    * Return a new snapshot of the current state of the collection,
245    * or null if no persister is passed
246    */
247   public final Serializable getSnapshot(CollectionPersister persister) throws HibernateException {
248     return (persister==null) ? null : snapshot(persister);
249   }
250 
251   /**
252    * Return a new snapshot of the current state
253    */
254   protected abstract Serializable snapshot(CollectionPersister persister) throws HibernateException;
255   
256   /**
257    * To be called internally by the session, forcing
258    * immediate initialization.
259    */
260   public final void forceInitialization() throws HibernateException {
261     if (!initialized) {
262       if (initializing) {
263         throw new AssertionFailure("force initialize loading collection");
264       }
265       if (session==null) {
266         throw new HibernateException("collection is not associated with any session");
267       }
268       if ( !session.isConnected() ) {
269         throw new HibernateException("disconnected session");
270       }
271       session.initializeCollection(this, false);
272     }
273   }
274 
275 
276   /**
277    * Get the current snapshot from the session
278    */
279   protected final Serializable getSnapshot() {
280     return session.getPersistenceContext().getSnapshot(this);
281   }
282 
283   /**
284    * Is this instance initialized?
285    */
286   public final boolean wasInitialized() {
287     return initialized;
288   }
289   
290   public boolean isRowUpdatePossible() {
291     return true;
292   }
293 
294   /**
295    * Does this instance have any "queued" additions?
296    */
297   public final boolean hasQueuedAdditions() {
298     return additions!=null;
299   }
300   /**
301    * Iterate the "queued" additions
302    */
303   public final Iterator queuedAdditionIterator() {
304     return hasQueuedAdditions() ?
305       additions.iterator() :
306       EmptyIterator.INSTANCE;
307   }
308 
309   /**
310    * Returns the collectionSnapshot.
311    * @return CollectionSnapshot
312    */
313   public CollectionSnapshot getCollectionSnapshot() {
314     return collectionSnapshot;
315   }
316 
317   /**
318    * Sets the collectionSnapshot.
319    * @param collectionSnapshot The collectionSnapshot to set
320    */
321   public void setCollectionSnapshot(CollectionSnapshot collectionSnapshot) {
322     this.collectionSnapshot = collectionSnapshot;
323   }
324 
325   /**
326    * Called before inserting rows, to ensure that any surrogate keys
327    * are fully generated
328    */
329   public void preInsert(CollectionPersister persister) throws HibernateException {}
330   /**
331    * Called after inserting a row, to fetch the natively generated id
332    */
333   public void afterRowInsert(CollectionPersister persister, Object entry, int i) throws HibernateException {}
334   /**
335    * get all "orphaned" elements
336    * @param entityName TODO
337    */
338   public abstract Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException;
339 
340   /**
341    * Get the current session
342    */
343   protected final SessionImplementor getSession() {
344     return session;
345   }
346 
347   final class IteratorProxy implements Iterator {
348     private final Iterator iter;
349     IteratorProxy(Iterator iter) {
350       this.iter=iter;
351     }
352     public boolean hasNext() {
353       return iter.hasNext();
354     }
355 
356     public Object next() {
357       return iter.next();
358     }
359 
360     public void remove() {
361       write();
362       iter.remove();
363     }
364 
365   }
366 
367   final class ListIteratorProxy implements ListIterator {
368     private final ListIterator iter;
369     ListIteratorProxy(ListIterator iter) {
370       this.iter = iter;
371     }
372     public void add(Object o) {
373       write();
374       iter.add(o);
375     }
376 
377     public boolean hasNext() {
378       return iter.hasNext();
379     }
380 
381     public boolean hasPrevious() {
382       return iter.hasPrevious();
383     }
384 
385     public Object next() {
386       return iter.next();
387     }
388 
389     public int nextIndex() {
390       return iter.nextIndex();
391     }
392 
393     public Object previous() {
394       return iter.previous();
395     }
396 
397     public int previousIndex() {
398       return iter.previousIndex();
399     }
400 
401     public void remove() {
402       write();
403       iter.remove();
404     }
405 
406     public void set(Object o) {
407       write();
408       iter.set(o);
409     }
410 
411   }
412 
413   class SetProxy implements java.util.Set {
414 
415     final Collection set;
416 
417     SetProxy(Collection set) {
418       this.set=set;
419     }
420     public boolean add(Object o) {
421       write();
422       return set.add(o);
423     }
424 
425     public boolean addAll(Collection c) {
426       write();
427       return set.addAll(c);
428     }
429 
430     public void clear() {
431       write();
432       set.clear();
433     }
434 
435     public boolean contains(Object o) {
436       return set.contains(o);
437     }
438 
439     public boolean containsAll(Collection c) {
440       return set.containsAll(c);
441     }
442 
443     public boolean isEmpty() {
444       return set.isEmpty();
445     }
446 
447     public Iterator iterator() {
448       return new IteratorProxy( set.iterator() );
449     }
450 
451     public boolean remove(Object o) {
452       write();
453       return set.remove(o);
454     }
455 
456     public boolean removeAll(Collection c) {
457       write();
458       return set.removeAll(c);
459     }
460 
461     public boolean retainAll(Collection c) {
462       write();
463       return set.retainAll(c);
464     }
465 
466     public int size() {
467       return set.size();
468     }
469 
470     public Object[] toArray() {
471       return set.toArray();
472     }
473 
474     public Object[] toArray(Object[] array) {
475       return set.toArray(array);
476     }
477 
478   }
479 
480   final class ListProxy implements java.util.List {
481 
482     private final java.util.List list;
483 
484     ListProxy(java.util.List list) {
485       this.list = list;
486     }
487 
488     public void add(int index, Object value) {
489       write();
490       list.add(index, value);
491     }
492 
493     /**
494      * @see java.util.Collection#add(Object)
495      */
496     public boolean add(Object o) {
497       write();
498       return list.add(o);
499     }
500 
501     /**
502      * @see java.util.Collection#addAll(Collection)
503      */
504     public boolean addAll(Collection c) {
505       write();
506       return list.addAll(c);
507     }
508 
509     /**
510      * @see java.util.List#addAll(int, Collection)
511      */
512     public boolean addAll(int i, Collection c) {
513       write();
514       return list.addAll(i, c);
515     }
516 
517     /**
518      * @see java.util.Collection#clear()
519      */
520     public void clear() {
521       write();
522       list.clear();
523     }
524 
525     /**
526      * @see java.util.Collection#contains(Object)
527      */
528     public boolean contains(Object o) {
529       return list.contains(o);
530     }
531 
532     /**
533      * @see java.util.Collection#containsAll(Collection)
534      */
535     public boolean containsAll(Collection c) {
536       return list.containsAll(c);
537     }
538 
539     /**
540      * @see java.util.List#get(int)
541      */
542     public Object get(int i) {
543       return list.get(i);
544     }
545 
546     /**
547      * @see java.util.List#indexOf(Object)
548      */
549     public int indexOf(Object o) {
550       return list.indexOf(o);
551     }
552 
553     /**
554      * @see java.util.Collection#isEmpty()
555      */
556     public boolean isEmpty() {
557       return list.isEmpty();
558     }
559 
560     /**
561      * @see java.util.Collection#iterator()
562      */
563     public Iterator iterator() {
564       return new IteratorProxy( list.iterator() );
565     }
566 
567     /**
568      * @see java.util.List#lastIndexOf(Object)
569      */
570     public int lastIndexOf(Object o) {
571       return list.lastIndexOf(o);
572     }
573 
574     /**
575      * @see java.util.List#listIterator()
576      */
577     public ListIterator listIterator() {
578       return new ListIteratorProxy( list.listIterator() );
579     }
580 
581     /**
582      * @see java.util.List#listIterator(int)
583      */
584     public ListIterator listIterator(int i) {
585       return new ListIteratorProxy( list.listIterator(i) );
586     }
587 
588     /**
589      * @see java.util.List#remove(int)
590      */
591     public Object remove(int i) {
592       write();
593       return list.remove(i);
594     }
595 
596     /**
597      * @see java.util.Collection#remove(Object)
598      */
599     public boolean remove(Object o) {
600       write();
601       return list.remove(o);
602     }
603 
604     /**
605      * @see java.util.Collection#removeAll(Collection)
606      */
607     public boolean removeAll(Collection c) {
608       write();
609       return list.removeAll(c);
610     }
611 
612     /**
613      * @see java.util.Collection#retainAll(Collection)
614      */
615     public boolean retainAll(Collection c) {
616       write();
617       return list.retainAll(c);
618     }
619 
620     /**
621      * @see java.util.List#set(int, Object)
622      */
623     public Object set(int i, Object o) {
624       write();
625       return list.set(i, o);
626     }
627 
628     /**
629      * @see java.util.Collection#size()
630      */
631     public int size() {
632       return list.size();
633     }
634 
635     /**
636      * @see java.util.List#subList(int, int)
637      */
638     public List subList(int i, int j) {
639       return list.subList(i, j);
640     }
641 
642     /**
643      * @see java.util.Collection#toArray()
644      */
645     public Object[] toArray() {
646       return list.toArray();
647     }
648 
649     /**
650      * @see java.util.Collection#toArray(Object[])
651      */
652     public Object[] toArray(Object[] array) {
653       return list.toArray(array);
654     }
655 
656   }
657 
658 
659   protected static Collection getOrphans(
660       Collection oldElements, 
661       Collection currentElements, 
662       String entityName, 
663       SessionImplementor session)
664   throws HibernateException {
665 
666     // short-circuit(s)
667     if ( currentElements.size()==0 ) return oldElements; // no new elements, the old list contains only Orphans
668     if ( oldElements.size()==0) return oldElements; // no old elements, so no Orphans neither
669     
670     Type idType = session.getFactory().getEntityPersister(entityName).getIdentifierType();
671 
672     // create the collection holding the Orphans
673     Collection res = new ArrayList();
674 
675     // collect EntityIdentifier(s) of the *current* elements - add them into a HashSet for fast access
676     java.util.Set currentIds = new HashSet();
677     for ( Iterator it=currentElements.iterator(); it.hasNext(); ) {
678       Object current = it.next();
679       if ( current!=null && ForeignKeys.isNotTransient(entityName, current, null, session) ) {
680         Serializable currentId = ForeignKeys.getEntityIdentifierIfNotUnsaved(entityName, current, session);
681         currentIds.add( new TypedValue( idType, currentId, session.getEntityMode() ) );
682       }
683     }
684 
685     // iterate over the *old* list
686     for ( Iterator it=oldElements.iterator(); it.hasNext(); ) {
687       Object old = it.next();
688       Serializable oldId = ForeignKeys.getEntityIdentifierIfNotUnsaved(entityName, old, session);
689       if ( !currentIds.contains( new TypedValue( idType, oldId, session.getEntityMode() ) ) ) res.add(old);
690     }
691 
692     return res;
693   }
694 
695   static void identityRemove(
696       Collection list, 
697       Object object, 
698       String entityName, 
699       SessionImplementor session)
700   throws HibernateException {
701 
702     if ( object!=null && ForeignKeys.isNotTransient(entityName, object, null, session) ) {
703       
704       Type idType = session.getFactory().getEntityPersister(entityName).getIdentifierType();
705 
706       Serializable idOfCurrent = ForeignKeys.getEntityIdentifierIfNotUnsaved(entityName, object, session);
707       Iterator iter = list.iterator();
708       while ( iter.hasNext() ) {
709         Serializable idOfOld = ForeignKeys.getEntityIdentifierIfNotUnsaved(entityName, iter.next(), session);
710         if ( idType.isEqual( idOfCurrent, idOfOld, session.getEntityMode(), session.getFactory() ) ) {
711           iter.remove();
712           break;
713         }
714       }
715 
716     }
717   }
718   
719   public Object getIdentifier(Object entry, int i) {
720     throw new UnsupportedOperationException();
721   }
722   
723   public Object getOwner() {
724     return owner;
725   }
726   
727   public void setOwner(Object owner) {
728     this.owner = owner;
729   }
730   
731   
732 }