~ubuntu-branches/ubuntu/wily/libhibernate3-java/wily-proposed

« back to all changes in this revision

Viewing changes to src/org/hibernate/engine/CascadingAction.java

  • Committer: Bazaar Package Importer
  • Author(s): Torsten Werner
  • Date: 2007-10-14 14:43:34 UTC
  • Revision ID: james.westby@ubuntu.com-20071014144334-eamc8i0q10gs1aro
Tags: upstream-3.2.5
ImportĀ upstreamĀ versionĀ 3.2.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//$Id: CascadingAction.java 10458 2006-09-06 14:07:22Z epbernard $
 
2
package org.hibernate.engine;
 
3
 
 
4
import java.util.Iterator;
 
5
import java.util.Map;
 
6
import java.util.Set;
 
7
 
 
8
import org.apache.commons.logging.Log;
 
9
import org.apache.commons.logging.LogFactory;
 
10
import org.hibernate.HibernateException;
 
11
import org.hibernate.LockMode;
 
12
import org.hibernate.ReplicationMode;
 
13
import org.hibernate.TransientObjectException;
 
14
import org.hibernate.proxy.HibernateProxy;
 
15
import org.hibernate.persister.entity.EntityPersister;
 
16
import org.hibernate.collection.PersistentCollection;
 
17
import org.hibernate.event.EventSource;
 
18
import org.hibernate.type.CollectionType;
 
19
import org.hibernate.type.Type;
 
20
import org.hibernate.type.EntityType;
 
21
 
 
22
/**
 
23
 * A session action that may be cascaded from parent entity to its children
 
24
 *
 
25
 * @author Gavin King
 
26
 */
 
27
public abstract class CascadingAction {
 
28
 
 
29
        private static final Log log = LogFactory.getLog( CascadingAction.class );
 
30
 
 
31
 
 
32
        // the CascadingAction contract ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
33
 
 
34
        /**
 
35
         * protected constructor
 
36
         */
 
37
        CascadingAction() {
 
38
        }
 
39
 
 
40
        /**
 
41
         * Cascade the action to the child object.
 
42
         *
 
43
         * @param session The session within which the cascade is occuring.
 
44
         * @param child The child to which cascading should be performed.
 
45
         * @param entityName The child's entity name
 
46
         * @param anything Anything ;)  Typically some form of cascade-local cache
 
47
         * which is specific to each CascadingAction type
 
48
         * @param isCascadeDeleteEnabled Are cascading deletes enabled.
 
49
         * @throws HibernateException
 
50
         */
 
51
        public abstract void cascade(
 
52
                        EventSource session,
 
53
                        Object child,
 
54
                        String entityName,
 
55
                        Object anything,
 
56
                        boolean isCascadeDeleteEnabled) throws HibernateException;
 
57
 
 
58
        /**
 
59
         * Given a collection, get an iterator of the children upon which the
 
60
         * current cascading action should be visited.
 
61
         *
 
62
         * @param session The session within which the cascade is occuring.
 
63
         * @param collectionType The mapping type of the collection.
 
64
         * @param collection The collection instance.
 
65
         * @return The children iterator.
 
66
         */
 
67
        public abstract Iterator getCascadableChildrenIterator(
 
68
                        EventSource session,
 
69
                        CollectionType collectionType,
 
70
                        Object collection);
 
71
 
 
72
        /**
 
73
         * Does this action potentially extrapolate to orphan deletes?
 
74
         *
 
75
         * @return True if this action can lead to deletions of orphans.
 
76
         */
 
77
        public abstract boolean deleteOrphans();
 
78
 
 
79
 
 
80
        /**
 
81
         * Does the specified cascading action require verification of no cascade validity?
 
82
         *
 
83
         * @return True if this action requires no-cascade verification; false otherwise.
 
84
         */
 
85
        public boolean requiresNoCascadeChecking() {
 
86
                return false;
 
87
        }
 
88
 
 
89
        /**
 
90
         * Called (in the case of {@link #requiresNoCascadeChecking} returning true) to validate
 
91
         * that no cascade on the given property is considered a valid semantic.
 
92
         *
 
93
         * @param session The session witin which the cascade is occurring.
 
94
         * @param child The property value
 
95
         * @param parent The property value owner
 
96
         * @param persister The entity persister for the owner
 
97
         * @param propertyIndex The index of the property within the owner.
 
98
         */
 
99
        public void noCascade(EventSource session, Object child, Object parent, EntityPersister persister, int propertyIndex) {
 
100
        }
 
101
 
 
102
        /**
 
103
         * Should this action be performed (or noCascade consulted) in the case of lazy properties.
 
104
         */
 
105
        public boolean performOnLazyProperty() {
 
106
                return true;
 
107
        }
 
108
 
 
109
 
 
110
        // the CascadingAction implementations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
111
 
 
112
        /**
 
113
         * @see org.hibernate.Session#delete(Object)
 
114
         */
 
115
        public static final CascadingAction DELETE = new CascadingAction() {
 
116
                public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
 
117
                throws HibernateException {
 
118
                        if ( log.isTraceEnabled() ) {
 
119
                                log.trace("cascading to delete: " + entityName);
 
120
                        }
 
121
                        session.delete( entityName, child, isCascadeDeleteEnabled, ( Set ) anything );
 
122
                }
 
123
                public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
 
124
                        // delete does cascade to uninitialized collections
 
125
                        return CascadingAction.getAllElementsIterator(session, collectionType, collection);
 
126
                }
 
127
                public boolean deleteOrphans() {
 
128
                        // orphans should be deleted during delete
 
129
                        return true;
 
130
                }
 
131
                public String toString() {
 
132
                        return "ACTION_DELETE";
 
133
                }
 
134
        };
 
135
 
 
136
        /**
 
137
         * @see org.hibernate.Session#lock(Object, LockMode)
 
138
         */
 
139
        public static final CascadingAction LOCK = new CascadingAction() {
 
140
                public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
 
141
                throws HibernateException {
 
142
                        if ( log.isTraceEnabled() ) {
 
143
                                log.trace( "cascading to lock: " + entityName );
 
144
                        }
 
145
                        session.lock( entityName, child, LockMode.NONE/*(LockMode) anything*/ );
 
146
                }
 
147
                public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
 
148
                        // lock doesn't cascade to uninitialized collections
 
149
                        return getLoadedElementsIterator(session, collectionType, collection);
 
150
                }
 
151
                public boolean deleteOrphans() {
 
152
                        //TODO: should orphans really be deleted during lock???
 
153
                        return false;
 
154
                }
 
155
                public String toString() {
 
156
                        return "ACTION_LOCK";
 
157
                }
 
158
        };
 
159
 
 
160
        /**
 
161
         * @see org.hibernate.Session#refresh(Object)
 
162
         */
 
163
        public static final CascadingAction REFRESH = new CascadingAction() {
 
164
                public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
 
165
                throws HibernateException {
 
166
                        if ( log.isTraceEnabled() ) {
 
167
                                log.trace( "cascading to refresh: " + entityName );
 
168
                        }
 
169
                        session.refresh( child, (Map) anything );
 
170
                }
 
171
                public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
 
172
                        // refresh doesn't cascade to uninitialized collections
 
173
                        return getLoadedElementsIterator(session, collectionType, collection);
 
174
                }
 
175
                public boolean deleteOrphans() {
 
176
                        return false;
 
177
                }
 
178
                public String toString() {
 
179
                        return "ACTION_REFRESH";
 
180
                }
 
181
        };
 
182
 
 
183
        /**
 
184
         * @see org.hibernate.Session#evict(Object)
 
185
         */
 
186
        public static final CascadingAction EVICT = new CascadingAction() {
 
187
                public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
 
188
                throws HibernateException {
 
189
                        if ( log.isTraceEnabled() ) {
 
190
                                log.trace( "cascading to evict: " + entityName );
 
191
                        }
 
192
                        session.evict(child);
 
193
                }
 
194
                public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
 
195
                        // evicts don't cascade to uninitialized collections
 
196
                        return getLoadedElementsIterator(session, collectionType, collection);
 
197
                }
 
198
                public boolean deleteOrphans() {
 
199
                        return false;
 
200
                }
 
201
                public boolean performOnLazyProperty() {
 
202
                        return false;
 
203
                }
 
204
                public String toString() {
 
205
                        return "ACTION_EVICT";
 
206
                }
 
207
        };
 
208
 
 
209
        /**
 
210
         * @see org.hibernate.Session#saveOrUpdate(Object)
 
211
         */
 
212
        public static final CascadingAction SAVE_UPDATE = new CascadingAction() {
 
213
                public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
 
214
                throws HibernateException {
 
215
                        if ( log.isTraceEnabled() ) {
 
216
                                log.trace( "cascading to saveOrUpdate: " + entityName );
 
217
                        }
 
218
                        session.saveOrUpdate(entityName, child);
 
219
                }
 
220
                public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
 
221
                        // saves / updates don't cascade to uninitialized collections
 
222
                        return getLoadedElementsIterator(session, collectionType, collection);
 
223
                }
 
224
                public boolean deleteOrphans() {
 
225
                        // orphans should be deleted during save/update
 
226
                        return true;
 
227
                }
 
228
                public boolean performOnLazyProperty() {
 
229
                        return false;
 
230
                }
 
231
                public String toString() {
 
232
                        return "ACTION_SAVE_UPDATE";
 
233
                }
 
234
        };
 
235
 
 
236
        /**
 
237
         * @see org.hibernate.Session#merge(Object)
 
238
         */
 
239
        public static final CascadingAction MERGE = new CascadingAction() {
 
240
                public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
 
241
                throws HibernateException {
 
242
                        if ( log.isTraceEnabled() ) {
 
243
                                log.trace( "cascading to merge: " + entityName );
 
244
                        }
 
245
                        session.merge( entityName, child, (Map) anything );
 
246
                }
 
247
                public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
 
248
                        // merges don't cascade to uninitialized collections
 
249
//                      //TODO: perhaps this does need to cascade after all....
 
250
                        return getLoadedElementsIterator(session, collectionType, collection);
 
251
                }
 
252
                public boolean deleteOrphans() {
 
253
                        // orphans should not be deleted during merge??
 
254
                        return false;
 
255
                }
 
256
                public String toString() {
 
257
                        return "ACTION_MERGE";
 
258
                }
 
259
        };
 
260
 
 
261
        /**
 
262
         * @see org.hibernate.classic.Session#saveOrUpdateCopy(Object)
 
263
         */
 
264
        public static final CascadingAction SAVE_UPDATE_COPY = new CascadingAction() {
 
265
                // for deprecated saveOrUpdateCopy()
 
266
                public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
 
267
                throws HibernateException {
 
268
                        if ( log.isTraceEnabled() ) {
 
269
                                log.trace( "cascading to saveOrUpdateCopy: " + entityName );
 
270
                        }
 
271
                        session.saveOrUpdateCopy( entityName, child, (Map) anything );
 
272
                }
 
273
                public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
 
274
                        // saves / updates don't cascade to uninitialized collections
 
275
                        return getLoadedElementsIterator(session, collectionType, collection);
 
276
                }
 
277
                public boolean deleteOrphans() {
 
278
                        // orphans should not be deleted during copy??
 
279
                        return false;
 
280
                }
 
281
                public String toString() {
 
282
                        return "ACTION_SAVE_UPDATE_COPY";
 
283
                }
 
284
        };
 
285
 
 
286
        /**
 
287
         * @see org.hibernate.Session#persist(Object)
 
288
         */
 
289
        public static final CascadingAction PERSIST = new CascadingAction() {
 
290
                public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
 
291
                throws HibernateException {
 
292
                        if ( log.isTraceEnabled() ) {
 
293
                                log.trace( "cascading to persist: " + entityName );
 
294
                        }
 
295
                        session.persist( entityName, child, (Map) anything );
 
296
                }
 
297
                public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
 
298
                        // persists don't cascade to uninitialized collections
 
299
                        return CascadingAction.getAllElementsIterator(session, collectionType, collection);
 
300
                }
 
301
                public boolean deleteOrphans() {
 
302
                        return false;
 
303
                }
 
304
                public boolean performOnLazyProperty() {
 
305
                        return false;
 
306
                }
 
307
                public String toString() {
 
308
                        return "ACTION_PERSIST";
 
309
                }
 
310
        };
 
311
 
 
312
        /**
 
313
         * Execute persist during flush time
 
314
         *
 
315
         * @see org.hibernate.Session#persist(Object)
 
316
         */
 
317
        public static final CascadingAction PERSIST_ON_FLUSH = new CascadingAction() {
 
318
                public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
 
319
                throws HibernateException {
 
320
                        if ( log.isTraceEnabled() ) {
 
321
                                log.trace( "cascading to persistOnFlush: " + entityName );
 
322
                        }
 
323
                        session.persistOnFlush( entityName, child, (Map) anything );
 
324
                }
 
325
                public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
 
326
                        // persists don't cascade to uninitialized collections
 
327
                        return CascadingAction.getLoadedElementsIterator(session, collectionType, collection);
 
328
                }
 
329
                public boolean deleteOrphans() {
 
330
                        return true;
 
331
                }
 
332
                public boolean requiresNoCascadeChecking() {
 
333
                        return true;
 
334
                }
 
335
                public void noCascade(
 
336
                                EventSource session,
 
337
                                Object child,
 
338
                                Object parent,
 
339
                                EntityPersister persister,
 
340
                                int propertyIndex) {
 
341
                        if ( child == null ) {
 
342
                                return;
 
343
                        }
 
344
                        Type type = persister.getPropertyTypes()[propertyIndex];
 
345
                        if ( type.isEntityType() ) {
 
346
                                String childEntityName = ( ( EntityType ) type ).getAssociatedEntityName( session.getFactory() );
 
347
 
 
348
                                if ( ! isInManagedState( child, session )
 
349
                                                && ! ( child instanceof HibernateProxy ) //a proxy cannot be transient and it breaks ForeignKeys.isTransient
 
350
                                                && ForeignKeys.isTransient( childEntityName, child, null, session ) ) {
 
351
                                        String parentEntiytName = persister.getEntityName();
 
352
                                        String propertyName = persister.getPropertyNames()[propertyIndex];
 
353
                                        throw new TransientObjectException(
 
354
                                                        "object references an unsaved transient instance - " +
 
355
                                                        "save the transient instance before flushing: " +
 
356
                                                        parentEntiytName + "." + propertyName + " -> " + childEntityName
 
357
                                        );
 
358
 
 
359
                                }
 
360
                        }
 
361
                }
 
362
                public boolean performOnLazyProperty() {
 
363
                        return false;
 
364
                }
 
365
 
 
366
                private boolean isInManagedState(Object child, EventSource session) {
 
367
                        EntityEntry entry = session.getPersistenceContext().getEntry( child );
 
368
                        return entry != null && (entry.getStatus() == Status.MANAGED || entry.getStatus() == Status.READ_ONLY);
 
369
                }
 
370
 
 
371
                public String toString() {
 
372
                        return "ACTION_PERSIST_ON_FLUSH";
 
373
                }
 
374
        };
 
375
 
 
376
        /**
 
377
         * @see org.hibernate.Session#replicate(Object, org.hibernate.ReplicationMode)
 
378
         */
 
379
        public static final CascadingAction REPLICATE = new CascadingAction() {
 
380
                public void cascade(EventSource session, Object child, String entityName, Object anything, boolean isCascadeDeleteEnabled)
 
381
                throws HibernateException {
 
382
                        if ( log.isTraceEnabled() ) {
 
383
                                log.trace( "cascading to replicate: " + entityName );
 
384
                        }
 
385
                        session.replicate( entityName, child, (ReplicationMode) anything );
 
386
                }
 
387
                public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
 
388
                        // replicate does cascade to uninitialized collections
 
389
                        return getLoadedElementsIterator(session, collectionType, collection);
 
390
                }
 
391
                public boolean deleteOrphans() {
 
392
                        return false; //I suppose?
 
393
                }
 
394
                public String toString() {
 
395
                        return "ACTION_REPLICATE";
 
396
                }
 
397
        };
 
398
 
 
399
 
 
400
        // static helper methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
401
 
 
402
        /**
 
403
         * Given a collection, get an iterator of all its children, loading them
 
404
         * from the database if necessary.
 
405
         *
 
406
         * @param session The session within which the cascade is occuring.
 
407
         * @param collectionType The mapping type of the collection.
 
408
         * @param collection The collection instance.
 
409
         * @return The children iterator.
 
410
         */
 
411
        private static Iterator getAllElementsIterator(
 
412
                        EventSource session,
 
413
                        CollectionType collectionType,
 
414
                        Object collection) {
 
415
                return collectionType.getElementsIterator( collection, session );
 
416
        }
 
417
 
 
418
        /**
 
419
         * Iterate just the elements of the collection that are already there. Don't load
 
420
         * any new elements from the database.
 
421
         */
 
422
        public static Iterator getLoadedElementsIterator(SessionImplementor session, CollectionType collectionType, Object collection) {
 
423
                if ( collectionIsInitialized(collection) ) {
 
424
                        // handles arrays and newly instantiated collections
 
425
                        return collectionType.getElementsIterator(collection, session);
 
426
                }
 
427
                else {
 
428
                        // does not handle arrays (thats ok, cos they can't be lazy)
 
429
                        // or newly instantiated collections, so we can do the cast
 
430
                        return ( (PersistentCollection) collection ).queuedAdditionIterator();
 
431
                }
 
432
        }
 
433
 
 
434
        private static boolean collectionIsInitialized(Object collection) {
 
435
                return !(collection instanceof PersistentCollection) || ( (PersistentCollection) collection ).wasInitialized();
 
436
        }
 
437
 
 
438
}
 
 
b'\\ No newline at end of file'