KickJava   Java API By Example, From Geeks To Geeks.

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


1 //$Id: Cascade.java,v 1.3 2005/06/05 05:09:57 oneovthafew Exp $
2
package org.hibernate.engine;
3
4 import java.util.Iterator JavaDoc;
5
6 import org.apache.commons.logging.Log;
7 import org.apache.commons.logging.LogFactory;
8 import org.hibernate.EntityMode;
9 import org.hibernate.HibernateException;
10 import org.hibernate.collection.PersistentCollection;
11 import org.hibernate.event.EventSource;
12 import org.hibernate.persister.collection.CollectionPersister;
13 import org.hibernate.persister.entity.EntityPersister;
14 import org.hibernate.type.AbstractComponentType;
15 import org.hibernate.type.AssociationType;
16 import org.hibernate.type.CollectionType;
17 import org.hibernate.type.EntityType;
18 import org.hibernate.type.Type;
19
20 /**
21  * Implements cascaded save / delete / update / lock / evict / replicate / persist / merge
22  *
23  * @see org.hibernate.type.AssociationType
24  * @author Gavin King
25  */

26 public final class Cascade {
27     
28     private int cascadeTo;
29     private EventSource eventSource;
30     private CascadingAction action;
31
32     public Cascade(
33             final CascadingAction action,
34             final int cascadeTo,
35             final EventSource eventSource
36     ) {
37         this.cascadeTo = cascadeTo;
38         this.eventSource = eventSource;
39         this.action = action;
40     }
41
42     private static final Log log = LogFactory.getLog(Cascade.class);
43
44     // The available cascade actions:
45

46     /**
47      * A cascade point that occurs just after the insertion of the parent entity and
48      * just before deletion
49      */

50     public static final int AFTER_INSERT_BEFORE_DELETE = 1;
51     /**
52      * A cascade point that occurs just before the insertion of the parent entity and
53      * just after deletion
54      */

55     public static final int BEFORE_INSERT_AFTER_DELETE = 2;
56     /**
57      * A cascade point that occurs just after the insertion of the parent entity and
58      * just before deletion, inside a collection
59      */

60     public static final int AFTER_INSERT_BEFORE_DELETE_VIA_COLLECTION = 3;
61     /**
62      * A cascade point that occurs just after update of the parent entity
63      */

64     public static final int AFTER_UPDATE = 0;
65     /**
66      * A cascade point that occurs just before the session is flushed
67      */

68     public static final int BEFORE_FLUSH = 0;
69     /**
70      * A cascade point that occurs just after eviction of the parent entity from the
71      * session cache
72      */

73     public static final int AFTER_EVICT = 0;
74     /**
75      * A cascade point that occurs just after locking a transient parent entity into the
76      * session cache
77      */

78     public static final int AFTER_REFRESH = 0;
79     /**
80      * A cascade point that occurs just after refreshing a parent entity
81      */

82     public static final int AFTER_LOCK = 0;
83     /**
84      * A cascade point that occurs just before merging from a transient parent entity into
85      * the object in the session cache
86      */

87     public static final int BEFORE_MERGE = 0;
88
89     // The allowable cascade styles for a property:
90

91     /**
92      * Cascade an action to the child or children
93      */

94     private void cascadeProperty(
95         final Object JavaDoc child,
96         final Type type,
97         final CascadeStyle style,
98         final Object JavaDoc anything,
99         final boolean isCascadeDeleteEnabled)
100     throws HibernateException {
101
102         if (child!=null) {
103             if ( type.isAssociationType() ) {
104                 AssociationType associationType = (AssociationType) type;
105                 if ( cascadeAssociationNow( associationType ) ) {
106                     cascadeAssociation(
107                             child,
108                             type,
109                             style,
110                             anything,
111                             isCascadeDeleteEnabled
112                         );
113                 }
114             }
115             else if ( type.isComponentType() ) {
116                 cascadeComponent( child, (AbstractComponentType) type, anything );
117             }
118         }
119     }
120
121     private boolean cascadeAssociationNow(AssociationType associationType) {
122         return associationType.getForeignKeyDirection().cascadeNow(cascadeTo) &&
123             ( eventSource.getEntityMode()!=EntityMode.DOM4J || associationType.isEmbeddedInXML() );
124     }
125
126     private void cascadeComponent(
127             final Object JavaDoc child,
128             final AbstractComponentType componentType,
129             final Object JavaDoc anything
130     ) {
131         Object JavaDoc[] children = componentType.getPropertyValues(child, eventSource);
132         Type[] types = componentType.getSubtypes();
133         for ( int i=0; i<types.length; i++ ) {
134             CascadeStyle componentPropertyStyle = componentType.getCascadeStyle(i);
135             if ( componentPropertyStyle.doCascade(action) ) {
136                 cascadeProperty(
137                         children[i],
138                         types[i],
139                         componentPropertyStyle,
140                         anything,
141                         false
142                     );
143             }
144         }
145     }
146
147     private void cascadeAssociation(
148             final Object JavaDoc child,
149             final Type type,
150             final CascadeStyle style,
151             final Object JavaDoc anything,
152             final boolean isCascadeDeleteEnabled
153     ) {
154         if ( type.isEntityType() || type.isAnyType() ) {
155             cascadeToOne( child, type, style, anything, isCascadeDeleteEnabled );
156         }
157         else if ( type.isCollectionType() ) {
158             cascadeCollection( child, style, anything, (CollectionType) type );
159         }
160     }
161     
162     /**
163      * Cascade an action to a collection
164      */

165     private void cascadeCollection(
166             final Object JavaDoc child,
167             final CascadeStyle style,
168             final Object JavaDoc anything,
169             final CollectionType type
170     ) {
171         
172         CollectionPersister persister = eventSource.getFactory()
173                 .getCollectionPersister( type.getRole() );
174         Type elemType = persister.getElementType();
175
176         final int oldCascadeTo = cascadeTo;
177         if ( cascadeTo==AFTER_INSERT_BEFORE_DELETE) {
178             cascadeTo = AFTER_INSERT_BEFORE_DELETE_VIA_COLLECTION;
179         }
180         
181         //cascade to current collection elements
182
if ( elemType.isEntityType() || elemType.isAnyType() || elemType.isComponentType() ) {
183             cascadeCollectionElements(
184                 child,
185                 type,
186                 style,
187                 elemType,
188                 anything,
189                 persister.isCascadeDeleteEnabled()
190             );
191         }
192         
193         cascadeTo = oldCascadeTo;
194     }
195     
196     /**
197      * Cascade an action to a to-one association or any type
198      */

199     private void cascadeToOne(
200             final Object JavaDoc child,
201             final Type type,
202             final CascadeStyle style,
203             final Object JavaDoc anything,
204             final boolean isCascadeDeleteEnabled
205     ) {
206         
207         final String JavaDoc entityName = type.isEntityType() ?
208                 ( (EntityType) type ).getAssociatedEntityName() : null;
209                 
210         if ( style.reallyDoCascade(action) ) { //not really necessary, but good for consistency...
211
action.cascade(eventSource, child, entityName, anything, isCascadeDeleteEnabled);
212         }
213         
214     }
215
216     /**
217      * Cascade an action from the parent entity instance to all its children
218      */

219     public void cascade(final EntityPersister persister, final Object JavaDoc parent)
220     throws HibernateException {
221         cascade(persister, parent, null);
222     }
223
224     /**
225      * Cascade an action from the parent entity instance to all its children
226      */

227     public void cascade(
228         final EntityPersister persister,
229         final Object JavaDoc parent,
230         final Object JavaDoc anything)
231     throws HibernateException {
232
233         if ( persister.hasCascades() ) { // performance opt
234
if ( log.isTraceEnabled() ) {
235                 log.trace( "processing cascade " + action + " for: " + persister.getEntityName() );
236             }
237             
238             Type[] types = persister.getPropertyTypes();
239             CascadeStyle[] cascadeStyles = persister.getPropertyCascadeStyles();
240             for ( int i=0; i<types.length; i++) {
241                 CascadeStyle style = cascadeStyles[i];
242                 if ( style.doCascade(action) ) {
243                     // associations cannot be field-level lazy="true", so don't
244
// need to check that the field is fetched (laziness for
245
// associations is always done by proxying currently)
246
cascadeProperty(
247                             persister.getPropertyValue( parent, i, eventSource.getEntityMode() ),
248                             types[i],
249                             style,
250                             anything,
251                             false
252                     );
253                 }
254             }
255             
256             if ( log.isTraceEnabled() ) {
257                 log.trace( "done processing cascade " + action + " for: " + persister.getEntityName() );
258             }
259         }
260     }
261
262     /**
263      * Cascade to the collection elements
264      */

265     private void cascadeCollectionElements(
266         final Object JavaDoc child,
267         final CollectionType collectionType,
268         final CascadeStyle style,
269         final Type elemType,
270         final Object JavaDoc anything,
271         final boolean isCascadeDeleteEnabled)
272     throws HibernateException {
273         
274         // we can't cascade to non-embedded elements
275
boolean embeddedElements = eventSource.getEntityMode()!=EntityMode.DOM4J ||
276                 ( (EntityType) collectionType.getElementType( eventSource.getFactory() ) ).isEmbeddedInXML();
277         
278         boolean reallyDoCascade = style.reallyDoCascade(action) &&
279             embeddedElements && child!=CollectionType.UNFETCHED_COLLECTION;
280         
281         if ( reallyDoCascade ) {
282             if ( log.isTraceEnabled() ) {
283                 log.trace( "cascade " + action + " for collection: " + collectionType.getRole() );
284             }
285             
286             Iterator JavaDoc iter = action.getCascadableChildrenIterator(eventSource, collectionType, child);
287             while ( iter.hasNext() ) {
288                 cascadeProperty(
289                         iter.next(),
290                         elemType,
291                         style,
292                         anything,
293                         isCascadeDeleteEnabled
294                 );
295             }
296             
297             if ( log.isTraceEnabled() ) {
298                 log.trace( "done cascade " + action + " for collection: " + collectionType.getRole() );
299             }
300         }
301         
302         final boolean deleteOrphans = style.hasOrphanDelete() &&
303                 action.deleteOrphans() &&
304                 elemType.isEntityType() &&
305                 child instanceof PersistentCollection; //a newly instantiated collection can't have orphans
306

307         if ( deleteOrphans ) { // handle orphaned entities!!
308
if ( log.isTraceEnabled() ) {
309                 log.trace( "deleting orphans for collection: " + collectionType.getRole() );
310             }
311             
312             // we can do the cast since orphan-delete does not apply to:
313
// 1. newly instantiated collections
314
// 2. arrays (we can't track orphans for detached arrays)
315
final String JavaDoc entityName = collectionType.getAssociatedEntityName( eventSource.getFactory() );
316             deleteOrphans( entityName, (PersistentCollection) child );
317             
318             if ( log.isTraceEnabled() ) {
319                 log.trace( "done deleting orphans for collection: " + collectionType.getRole() );
320             }
321         }
322     }
323
324     /**
325      * Delete any entities that were removed from the collection
326      */

327     private void deleteOrphans(String JavaDoc entityName, PersistentCollection pc)
328             throws HibernateException {
329         if ( pc.wasInitialized() ) { //can't be any orphans if it was not initialized!
330
CollectionEntry ce = eventSource.getPersistenceContext().getCollectionEntry(pc);
331             if (ce!=null) {
332                 Iterator JavaDoc orphanIter = ce.getOrphans(entityName, pc).iterator();
333                 while ( orphanIter.hasNext() ) {
334                     Object JavaDoc orphan = orphanIter.next();
335                     if (orphan!=null) {
336                         if ( log.isTraceEnabled() ) log.trace("deleting orphaned: " + entityName);
337                         eventSource.delete(entityName, orphan, false);
338                     }
339                 }
340             }
341         }
342     }
343
344 }
345
Popular Tags