1 package org.hibernate.engine; 3 4 import java.util.Iterator ; 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 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 46 50 public static final int AFTER_INSERT_BEFORE_DELETE = 1; 51 55 public static final int BEFORE_INSERT_AFTER_DELETE = 2; 56 60 public static final int AFTER_INSERT_BEFORE_DELETE_VIA_COLLECTION = 3; 61 64 public static final int AFTER_UPDATE = 0; 65 68 public static final int BEFORE_FLUSH = 0; 69 73 public static final int AFTER_EVICT = 0; 74 78 public static final int AFTER_REFRESH = 0; 79 82 public static final int AFTER_LOCK = 0; 83 87 public static final int BEFORE_MERGE = 0; 88 89 91 94 private void cascadeProperty( 95 final Object child, 96 final Type type, 97 final CascadeStyle style, 98 final Object 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 child, 128 final AbstractComponentType componentType, 129 final Object anything 130 ) { 131 Object [] 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 child, 149 final Type type, 150 final CascadeStyle style, 151 final Object 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 165 private void cascadeCollection( 166 final Object child, 167 final CascadeStyle style, 168 final Object 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 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 199 private void cascadeToOne( 200 final Object child, 201 final Type type, 202 final CascadeStyle style, 203 final Object anything, 204 final boolean isCascadeDeleteEnabled 205 ) { 206 207 final String entityName = type.isEntityType() ? 208 ( (EntityType) type ).getAssociatedEntityName() : null; 209 210 if ( style.reallyDoCascade(action) ) { action.cascade(eventSource, child, entityName, anything, isCascadeDeleteEnabled); 212 } 213 214 } 215 216 219 public void cascade(final EntityPersister persister, final Object parent) 220 throws HibernateException { 221 cascade(persister, parent, null); 222 } 223 224 227 public void cascade( 228 final EntityPersister persister, 229 final Object parent, 230 final Object anything) 231 throws HibernateException { 232 233 if ( persister.hasCascades() ) { 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 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 265 private void cascadeCollectionElements( 266 final Object child, 267 final CollectionType collectionType, 268 final CascadeStyle style, 269 final Type elemType, 270 final Object anything, 271 final boolean isCascadeDeleteEnabled) 272 throws HibernateException { 273 274 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 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; 307 if ( deleteOrphans ) { if ( log.isTraceEnabled() ) { 309 log.trace( "deleting orphans for collection: " + collectionType.getRole() ); 310 } 311 312 final String 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 327 private void deleteOrphans(String entityName, PersistentCollection pc) 328 throws HibernateException { 329 if ( pc.wasInitialized() ) { CollectionEntry ce = eventSource.getPersistenceContext().getCollectionEntry(pc); 331 if (ce!=null) { 332 Iterator orphanIter = ce.getOrphans(entityName, pc).iterator(); 333 while ( orphanIter.hasNext() ) { 334 Object 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 |