KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hibernate > engine > Collections


1 //$Id: Collections.java,v 1.18 2005/06/19 03:48:48 oneovthafew Exp $
2
package org.hibernate.engine;
3
4 import org.apache.commons.logging.Log;
5 import org.apache.commons.logging.LogFactory;
6 import org.hibernate.AssertionFailure;
7 import org.hibernate.EntityMode;
8 import org.hibernate.HibernateException;
9 import org.hibernate.collection.PersistentCollection;
10 import org.hibernate.persister.collection.CollectionPersister;
11 import org.hibernate.pretty.MessageHelper;
12 import org.hibernate.type.CollectionType;
13 import org.hibernate.type.Type;
14
15 /**
16  * Implements book-keeping for the collection persistence by reachability algorithm
17  * @author Gavin King
18  */

19 public final class Collections {
20     
21     private Collections() {}
22     
23     private static final Log log = LogFactory.getLog(Collections.class);
24     
25     /**
26      * record the fact that this collection was dereferenced
27      *
28      * @param coll The collection to be updated by unreachability.
29      * @throws HibernateException
30      */

31     public static void processUnreachableCollection(PersistentCollection coll, SessionImplementor session)
32     throws HibernateException {
33         
34         if ( coll.getOwner()==null ) {
35             processNeverReferencedCollection(coll, session);
36         }
37         else {
38             processDereferencedCollection(coll, session);
39         }
40
41     }
42
43     private static void processDereferencedCollection(PersistentCollection coll, SessionImplementor session)
44     throws HibernateException {
45         
46         final PersistenceContext persistenceContext = session.getPersistenceContext();
47         CollectionEntry entry = persistenceContext.getCollectionEntry(coll);
48
49         if ( log.isDebugEnabled() && entry.getLoadedPersister() != null )
50             log.debug(
51                     "Collection dereferenced: " +
52                     MessageHelper.collectionInfoString(
53                             entry.getLoadedPersister(),
54                             entry.getLoadedKey(),
55                             session.getFactory()
56                         )
57                 );
58
59         // do a check
60
boolean hasOrphanDelete = entry.getLoadedPersister() != null &&
61                 entry.getLoadedPersister().hasOrphanDelete();
62         if (hasOrphanDelete) {
63             EntityKey key = new EntityKey(
64                     entry.getLoadedPersister().getOwnerEntityPersister()
65                             .getIdentifier( coll.getOwner(), session.getEntityMode() ),
66                     entry.getLoadedPersister().getOwnerEntityPersister(),
67                     session.getEntityMode()
68                 );
69             Object JavaDoc owner = persistenceContext.getEntity(key);
70             if ( owner == null ) throw new AssertionFailure( "owner not associated with session" );
71             EntityEntry e = persistenceContext.getEntry(owner);
72             //only collections belonging to deleted entities are allowed to be dereferenced in the case of orphan delete
73
if ( e != null && e.getStatus() != Status.DELETED && e.getStatus() != Status.GONE ) {
74                 throw new HibernateException(
75                         "Don't dereference a collection with cascade=\"all-delete-orphan\": " +
76                         coll.getRole()
77                     );
78             }
79         }
80
81         // do the work
82
entry.setCurrentPersister(null);
83         entry.setCurrentKey(null);
84         prepareCollectionForUpdate( coll, entry, session.getEntityMode(), session.getFactory() );
85         
86     }
87     
88     private static void processNeverReferencedCollection(PersistentCollection coll, SessionImplementor session)
89     throws HibernateException {
90         
91         final PersistenceContext persistenceContext = session.getPersistenceContext();
92         CollectionEntry entry = persistenceContext.getCollectionEntry(coll);
93
94         log.debug(
95                 "Found collection with unloaded owner: " +
96                 MessageHelper.collectionInfoString(
97                         entry.getLoadedPersister(),
98                         entry.getLoadedKey(),
99                         session.getFactory()
100                     )
101             );
102         
103         entry.setCurrentPersister( entry.getLoadedPersister() );
104         entry.setCurrentKey( entry.getLoadedKey() );
105         
106         prepareCollectionForUpdate( coll, entry, session.getEntityMode(), session.getFactory() );
107         
108     }
109     
110     /**
111      * Initialize the role of the collection.
112      *
113      * @param collection The collection to be updated by reachibility.
114      * @param type The type of the collection.
115      * @param entity The owner of the collection.
116      * @throws HibernateException
117      */

118     public static void processReachableCollection(
119             PersistentCollection collection,
120             Type type,
121             Object JavaDoc entity,
122             SessionImplementor session)
123     throws HibernateException {
124         
125         collection.setOwner(entity);
126         
127         CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(collection);
128
129         if ( ce == null ) {
130             // refer to comment in SessionImpl.addCollection()
131
throw new HibernateException( "Found two representations of same collection" );
132         }
133
134         // The CollectionEntry.isReached() stuff is just to detect any silly users
135
// who set up circular or shared references between/to collections.
136
if ( ce.isReached() ) {
137             // We've been here before
138
throw new HibernateException( "Found shared references to a collection" );
139         }
140         ce.setReached(true);
141         
142         CollectionType pctype = (CollectionType) type;
143         CollectionPersister persister = session.getFactory().getCollectionPersister( pctype.getRole() );
144         ce.setCurrentPersister(persister);
145         ce.setCurrentKey( pctype.getKeyOfOwner(entity, session) ); //TODO: better to pass the id in as an argument?
146

147         if ( log.isDebugEnabled() ) {
148             log.debug(
149                     "Collection found: " +
150                     MessageHelper.collectionInfoString( persister, ce.getCurrentKey(), session.getFactory() ) +
151                     ", was: " +
152                     MessageHelper.collectionInfoString( ce.getLoadedPersister(), ce.getLoadedKey(), session.getFactory() ) +
153                     ( collection.wasInitialized() ? " (initialized)" : " (uninitialized)" )
154                 );
155         }
156
157         prepareCollectionForUpdate( collection, ce, session.getEntityMode(), session.getFactory() );
158
159     }
160     
161     /**
162      * 1. record the collection role that this collection is referenced by
163      * 2. decide if the collection needs deleting/creating/updating (but
164      * don't actually schedule the action yet)
165      */

166     private static void prepareCollectionForUpdate(
167             PersistentCollection collection,
168             CollectionEntry entry,
169             EntityMode entityMode,
170             SessionFactoryImplementor factory)
171     throws HibernateException {
172
173         if ( entry.isProcessed() ) {
174             throw new AssertionFailure( "collection was processed twice by flush()" );
175         }
176         entry.setProcessed(true);
177
178         if ( entry.getLoadedPersister() != null || entry.getCurrentPersister() != null ) { // it is or was referenced _somewhere_
179

180             boolean ownerChanged = entry.getLoadedPersister() != entry.getCurrentPersister() || // if either its role changed,
181
!entry.getCurrentPersister()
182                         .getKeyType().isEqual( // or its key changed
183
entry.getLoadedKey(),
184                                 entry.getCurrentKey(),
185                                 entityMode, factory
186                             );
187
188             if (ownerChanged) {
189
190                 // do a check
191
if (
192                         entry.getLoadedPersister() != null &&
193                         entry.getCurrentPersister() != null &&
194                         entry.getLoadedPersister().hasOrphanDelete()
195                 ) {
196                     throw new HibernateException(
197                             "Don't change the reference to a collection with cascade=\"all-delete-orphan\": " +
198                             collection.getRole()
199                     );
200                 }
201
202                 // do the work
203
if ( entry.getCurrentPersister() != null ) entry.setDorecreate(true); // we will need to create new entries
204

205                 if ( entry.getLoadedPersister() != null ) {
206                     entry.setDoremove(true); // we will need to remove ye olde entries
207
if ( entry.isDorecreate() ) {
208                         log.trace( "Forcing collection initialization" );
209                         collection.forceInitialization(); // force initialize!
210
}
211                 }
212
213             }
214             else if ( collection.isDirty() ) { // else if it's elements changed
215
entry.setDoupdate(true);
216             }
217
218         }
219
220     }
221
222 }
223
Popular Tags