1
//$Id: CascadingAction.java 10458 2006-09-06 14:07:22Z epbernard $
2
package org.hibernate.engine;
4
import java.util.Iterator;
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;
23
* A session action that may be cascaded from parent entity to its children
27
public abstract class CascadingAction {
29
private static final Log log = LogFactory.getLog( CascadingAction.class );
32
// the CascadingAction contract ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
35
* protected constructor
41
* Cascade the action to the child object.
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
51
public abstract void cascade(
56
boolean isCascadeDeleteEnabled) throws HibernateException;
59
* Given a collection, get an iterator of the children upon which the
60
* current cascading action should be visited.
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.
67
public abstract Iterator getCascadableChildrenIterator(
69
CollectionType collectionType,
73
* Does this action potentially extrapolate to orphan deletes?
75
* @return True if this action can lead to deletions of orphans.
77
public abstract boolean deleteOrphans();
81
* Does the specified cascading action require verification of no cascade validity?
83
* @return True if this action requires no-cascade verification; false otherwise.
85
public boolean requiresNoCascadeChecking() {
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.
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.
99
public void noCascade(EventSource session, Object child, Object parent, EntityPersister persister, int propertyIndex) {
103
* Should this action be performed (or noCascade consulted) in the case of lazy properties.
105
public boolean performOnLazyProperty() {
110
// the CascadingAction implementations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
113
* @see org.hibernate.Session#delete(Object)
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);
121
session.delete( entityName, child, isCascadeDeleteEnabled, ( Set ) anything );
123
public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
124
// delete does cascade to uninitialized collections
125
return CascadingAction.getAllElementsIterator(session, collectionType, collection);
127
public boolean deleteOrphans() {
128
// orphans should be deleted during delete
131
public String toString() {
132
return "ACTION_DELETE";
137
* @see org.hibernate.Session#lock(Object, LockMode)
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 );
145
session.lock( entityName, child, LockMode.NONE/*(LockMode) anything*/ );
147
public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
148
// lock doesn't cascade to uninitialized collections
149
return getLoadedElementsIterator(session, collectionType, collection);
151
public boolean deleteOrphans() {
152
//TODO: should orphans really be deleted during lock???
155
public String toString() {
156
return "ACTION_LOCK";
161
* @see org.hibernate.Session#refresh(Object)
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 );
169
session.refresh( child, (Map) anything );
171
public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
172
// refresh doesn't cascade to uninitialized collections
173
return getLoadedElementsIterator(session, collectionType, collection);
175
public boolean deleteOrphans() {
178
public String toString() {
179
return "ACTION_REFRESH";
184
* @see org.hibernate.Session#evict(Object)
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 );
192
session.evict(child);
194
public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
195
// evicts don't cascade to uninitialized collections
196
return getLoadedElementsIterator(session, collectionType, collection);
198
public boolean deleteOrphans() {
201
public boolean performOnLazyProperty() {
204
public String toString() {
205
return "ACTION_EVICT";
210
* @see org.hibernate.Session#saveOrUpdate(Object)
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 );
218
session.saveOrUpdate(entityName, child);
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);
224
public boolean deleteOrphans() {
225
// orphans should be deleted during save/update
228
public boolean performOnLazyProperty() {
231
public String toString() {
232
return "ACTION_SAVE_UPDATE";
237
* @see org.hibernate.Session#merge(Object)
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 );
245
session.merge( entityName, child, (Map) anything );
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);
252
public boolean deleteOrphans() {
253
// orphans should not be deleted during merge??
256
public String toString() {
257
return "ACTION_MERGE";
262
* @see org.hibernate.classic.Session#saveOrUpdateCopy(Object)
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 );
271
session.saveOrUpdateCopy( entityName, child, (Map) anything );
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);
277
public boolean deleteOrphans() {
278
// orphans should not be deleted during copy??
281
public String toString() {
282
return "ACTION_SAVE_UPDATE_COPY";
287
* @see org.hibernate.Session#persist(Object)
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 );
295
session.persist( entityName, child, (Map) anything );
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);
301
public boolean deleteOrphans() {
304
public boolean performOnLazyProperty() {
307
public String toString() {
308
return "ACTION_PERSIST";
313
* Execute persist during flush time
315
* @see org.hibernate.Session#persist(Object)
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 );
323
session.persistOnFlush( entityName, child, (Map) anything );
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);
329
public boolean deleteOrphans() {
332
public boolean requiresNoCascadeChecking() {
335
public void noCascade(
339
EntityPersister persister,
341
if ( child == null ) {
344
Type type = persister.getPropertyTypes()[propertyIndex];
345
if ( type.isEntityType() ) {
346
String childEntityName = ( ( EntityType ) type ).getAssociatedEntityName( session.getFactory() );
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
362
public boolean performOnLazyProperty() {
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);
371
public String toString() {
372
return "ACTION_PERSIST_ON_FLUSH";
377
* @see org.hibernate.Session#replicate(Object, org.hibernate.ReplicationMode)
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 );
385
session.replicate( entityName, child, (ReplicationMode) anything );
387
public Iterator getCascadableChildrenIterator(EventSource session, CollectionType collectionType, Object collection) {
388
// replicate does cascade to uninitialized collections
389
return getLoadedElementsIterator(session, collectionType, collection);
391
public boolean deleteOrphans() {
392
return false; //I suppose?
394
public String toString() {
395
return "ACTION_REPLICATE";
400
// static helper methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
403
* Given a collection, get an iterator of all its children, loading them
404
* from the database if necessary.
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.
411
private static Iterator getAllElementsIterator(
413
CollectionType collectionType,
415
return collectionType.getElementsIterator( collection, session );
419
* Iterate just the elements of the collection that are already there. Don't load
420
* any new elements from the database.
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);
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();
434
private static boolean collectionIsInitialized(Object collection) {
435
return !(collection instanceof PersistentCollection) || ( (PersistentCollection) collection ).wasInitialized();
b'\\ No newline at end of file'