FileDocCategorySizeDatePackage
Cascade.javaAPI DocHibernate 3.2.511161Tue Aug 22 16:29:28 BST 2006org.hibernate.engine

Cascade

public final class Cascade extends Object
Delegate responsible for, in conjunction with the various {@link CascadingAction actions}, implementing cascade processing.
author
Gavin King
see
CascadingAction

Fields Summary
public static final int
AFTER_INSERT_BEFORE_DELETE
A cascade point that occurs just after the insertion of the parent entity and just before deletion
public static final int
BEFORE_INSERT_AFTER_DELETE
A cascade point that occurs just before the insertion of the parent entity and just after deletion
public static final int
AFTER_INSERT_BEFORE_DELETE_VIA_COLLECTION
A cascade point that occurs just after the insertion of the parent entity and just before deletion, inside a collection
public static final int
AFTER_UPDATE
A cascade point that occurs just after update of the parent entity
public static final int
BEFORE_FLUSH
A cascade point that occurs just before the session is flushed
public static final int
AFTER_EVICT
A cascade point that occurs just after eviction of the parent entity from the session cache
public static final int
BEFORE_REFRESH
A cascade point that occurs just after locking a transient parent entity into the session cache
public static final int
AFTER_LOCK
A cascade point that occurs just after refreshing a parent entity
public static final int
BEFORE_MERGE
A cascade point that occurs just before merging from a transient parent entity into the object in the session cache
private static final Log
log
private int
cascadeTo
private org.hibernate.event.EventSource
eventSource
private CascadingAction
action
Constructors Summary
public Cascade(CascadingAction action, int cascadeTo, org.hibernate.event.EventSource eventSource)


	          
		this.cascadeTo = cascadeTo;
		this.eventSource = eventSource;
		this.action = action;
	
Methods Summary
public voidcascade(org.hibernate.persister.entity.EntityPersister persister, java.lang.Object parent)
Cascade an action from the parent entity instance to all its children.

param
persister The parent's entity persister
param
parent The parent reference.
throws
HibernateException

		cascade( persister, parent, null );
	
public voidcascade(org.hibernate.persister.entity.EntityPersister persister, java.lang.Object parent, java.lang.Object anything)
Cascade an action from the parent entity instance to all its children. This form is typicaly called from within cascade actions.

param
persister The parent's entity persister
param
parent The parent reference.
param
anything Anything ;) Typically some form of cascade-local cache which is specific to each CascadingAction type
throws
HibernateException


		if ( persister.hasCascades() || action.requiresNoCascadeChecking() ) { // performance opt
			if ( log.isTraceEnabled() ) {
				log.trace( "processing cascade " + action + " for: " + persister.getEntityName() );
			}

			Type[] types = persister.getPropertyTypes();
			CascadeStyle[] cascadeStyles = persister.getPropertyCascadeStyles();
			EntityMode entityMode = eventSource.getEntityMode();
			boolean hasUninitializedLazyProperties = persister.hasUninitializedLazyProperties( parent, entityMode );
			for ( int i=0; i<types.length; i++) {
				CascadeStyle style = cascadeStyles[i];
				if ( hasUninitializedLazyProperties && persister.getPropertyLaziness()[i] && ! action.performOnLazyProperty() ) {
					//do nothing to avoid a lazy property initialization
					continue;
				}

				if ( style.doCascade( action ) ) {
					cascadeProperty(
					        persister.getPropertyValue( parent, i, entityMode ),
					        types[i],
					        style,
					        anything,
					        false
					);
				}
				else if ( action.requiresNoCascadeChecking() ) {
					action.noCascade(
							eventSource,
							persister.getPropertyValue( parent, i, entityMode ),
							parent,
							persister,
							i
					);
				}
			}

			if ( log.isTraceEnabled() ) {
				log.trace( "done processing cascade " + action + " for: " + persister.getEntityName() );
			}
		}
	
private voidcascadeAssociation(java.lang.Object child, org.hibernate.type.Type type, CascadeStyle style, java.lang.Object anything, boolean isCascadeDeleteEnabled)

		if ( type.isEntityType() || type.isAnyType() ) {
			cascadeToOne( child, type, style, anything, isCascadeDeleteEnabled );
		}
		else if ( type.isCollectionType() ) {
			cascadeCollection( child, style, anything, (CollectionType) type );
		}
	
private booleancascadeAssociationNow(org.hibernate.type.AssociationType associationType)

		return associationType.getForeignKeyDirection().cascadeNow(cascadeTo) &&
			( eventSource.getEntityMode()!=EntityMode.DOM4J || associationType.isEmbeddedInXML() );
	
private voidcascadeCollection(java.lang.Object child, CascadeStyle style, java.lang.Object anything, org.hibernate.type.CollectionType type)
Cascade an action to a collection

		CollectionPersister persister = eventSource.getFactory()
				.getCollectionPersister( type.getRole() );
		Type elemType = persister.getElementType();

		final int oldCascadeTo = cascadeTo;
		if ( cascadeTo==AFTER_INSERT_BEFORE_DELETE) {
			cascadeTo = AFTER_INSERT_BEFORE_DELETE_VIA_COLLECTION;
		}

		//cascade to current collection elements
		if ( elemType.isEntityType() || elemType.isAnyType() || elemType.isComponentType() ) {
			cascadeCollectionElements(
				child,
				type,
				style,
				elemType,
				anything,
				persister.isCascadeDeleteEnabled()
			);
		}

		cascadeTo = oldCascadeTo;
	
private voidcascadeCollectionElements(java.lang.Object child, org.hibernate.type.CollectionType collectionType, CascadeStyle style, org.hibernate.type.Type elemType, java.lang.Object anything, boolean isCascadeDeleteEnabled)
Cascade to the collection elements

		// we can't cascade to non-embedded elements
		boolean embeddedElements = eventSource.getEntityMode()!=EntityMode.DOM4J ||
				( (EntityType) collectionType.getElementType( eventSource.getFactory() ) ).isEmbeddedInXML();

		boolean reallyDoCascade = style.reallyDoCascade(action) &&
			embeddedElements && child!=CollectionType.UNFETCHED_COLLECTION;

		if ( reallyDoCascade ) {
			if ( log.isTraceEnabled() ) {
				log.trace( "cascade " + action + " for collection: " + collectionType.getRole() );
			}

			Iterator iter = action.getCascadableChildrenIterator(eventSource, collectionType, child);
			while ( iter.hasNext() ) {
				cascadeProperty(
						iter.next(),
						elemType,
						style,
						anything,
						isCascadeDeleteEnabled
					);
			}

			if ( log.isTraceEnabled() ) {
				log.trace( "done cascade " + action + " for collection: " + collectionType.getRole() );
			}
		}

		final boolean deleteOrphans = style.hasOrphanDelete() &&
				action.deleteOrphans() &&
				elemType.isEntityType() &&
				child instanceof PersistentCollection; //a newly instantiated collection can't have orphans

		if ( deleteOrphans ) { // handle orphaned entities!!
			if ( log.isTraceEnabled() ) {
				log.trace( "deleting orphans for collection: " + collectionType.getRole() );
			}

			// we can do the cast since orphan-delete does not apply to:
			// 1. newly instantiated collections
			// 2. arrays (we can't track orphans for detached arrays)
			final String entityName = collectionType.getAssociatedEntityName( eventSource.getFactory() );
			deleteOrphans( entityName, (PersistentCollection) child );

			if ( log.isTraceEnabled() ) {
				log.trace( "done deleting orphans for collection: " + collectionType.getRole() );
			}
		}
	
private voidcascadeComponent(java.lang.Object child, org.hibernate.type.AbstractComponentType componentType, java.lang.Object anything)

		Object[] children = componentType.getPropertyValues(child, eventSource);
		Type[] types = componentType.getSubtypes();
		for ( int i=0; i<types.length; i++ ) {
			CascadeStyle componentPropertyStyle = componentType.getCascadeStyle(i);
			if ( componentPropertyStyle.doCascade(action) ) {
				cascadeProperty(
						children[i],
						types[i],
						componentPropertyStyle,
						anything,
						false
					);
			}
		}
	
private voidcascadeProperty(java.lang.Object child, org.hibernate.type.Type type, CascadeStyle style, java.lang.Object anything, boolean isCascadeDeleteEnabled)
Cascade an action to the child or children


		if (child!=null) {
			if ( type.isAssociationType() ) {
				AssociationType associationType = (AssociationType) type;
				if ( cascadeAssociationNow( associationType ) ) {
					cascadeAssociation(
							child,
							type,
							style,
							anything,
							isCascadeDeleteEnabled
						);
				}
			}
			else if ( type.isComponentType() ) {
				cascadeComponent( child, (AbstractComponentType) type, anything );
			}
		}
	
private voidcascadeToOne(java.lang.Object child, org.hibernate.type.Type type, CascadeStyle style, java.lang.Object anything, boolean isCascadeDeleteEnabled)
Cascade an action to a to-one association or any type

		final String entityName = type.isEntityType()
				? ( (EntityType) type ).getAssociatedEntityName()
				: null;
		if ( style.reallyDoCascade(action) ) { //not really necessary, but good for consistency...
			action.cascade(eventSource, child, entityName, anything, isCascadeDeleteEnabled);
		}
	
private voiddeleteOrphans(java.lang.String entityName, org.hibernate.collection.PersistentCollection pc)
Delete any entities that were removed from the collection

		//TODO: suck this logic into the collection!
		final Collection orphans;
		if ( pc.wasInitialized() ) {
			CollectionEntry ce = eventSource.getPersistenceContext().getCollectionEntry(pc);
			orphans = ce==null ?
					CollectionHelper.EMPTY_COLLECTION :
					ce.getOrphans(entityName, pc);
		}
		else {
			orphans = pc.getQueuedOrphans(entityName);
		}

		final Iterator orphanIter = orphans.iterator();
		while ( orphanIter.hasNext() ) {
			Object orphan = orphanIter.next();
			if (orphan!=null) {
				if ( log.isTraceEnabled() ) {
					log.trace("deleting orphaned entity instance: " + entityName);
				}
				eventSource.delete( entityName, orphan, false, null );
			}
		}