FileDocCategorySizeDatePackage
DefaultSaveOrUpdateEventListener.javaAPI DocHibernate 3.2.510662Thu Dec 07 14:53:42 GMT 2006org.hibernate.event.def

DefaultSaveOrUpdateEventListener

public class DefaultSaveOrUpdateEventListener extends AbstractSaveEventListener implements org.hibernate.event.SaveOrUpdateEventListener
Defines the default listener used by Hibernate for handling save-update events.
author
Steve Ebersole
author
Gavin King

Fields Summary
private static final Log
log
Constructors Summary
Methods Summary
private voidcascadeOnUpdate(org.hibernate.event.SaveOrUpdateEvent event, org.hibernate.persister.entity.EntityPersister persister, java.lang.Object entity)
Handles the calls needed to perform cascades as part of an update request for the given entity.

param
event The event currently being processed.
param
persister The defined persister for the entity being updated.
param
entity The entity being updated.

		EventSource source = event.getSession();
		source.getPersistenceContext().incrementCascadeLevel();
		try {
			new Cascade( CascadingAction.SAVE_UPDATE, Cascade.AFTER_UPDATE, source )
					.cascade( persister, entity );
		}
		finally {
			source.getPersistenceContext().decrementCascadeLevel();
		}
	
protected voidentityIsDetached(org.hibernate.event.SaveOrUpdateEvent event)
The given save-update event named a detached entity.

Here, we will perform the update processing.

param
event The update event to be handled.


		log.trace( "updating detached instance" );


		if ( event.getSession().getPersistenceContext().isEntryFor( event.getEntity() ) ) {
			//TODO: assertion only, could be optimized away
			throw new AssertionFailure( "entity was persistent" );
		}

		Object entity = event.getEntity();

		EntityPersister persister = event.getSession().getEntityPersister( event.getEntityName(), entity );

		event.setRequestedId(
				getUpdateId(
						entity, persister, event.getRequestedId(), event.getSession().getEntityMode()
				)
		);

		performUpdate( event, entity, persister );

	
protected java.io.SerializableentityIsPersistent(org.hibernate.event.SaveOrUpdateEvent event)

		log.trace( "ignoring persistent instance" );

		EntityEntry entityEntry = event.getEntry();
		if ( entityEntry == null ) {
			throw new AssertionFailure( "entity was transient or detached" );
		}
		else {

			if ( entityEntry.getStatus() == Status.DELETED ) {
				throw new AssertionFailure( "entity was deleted" );
			}

			final SessionFactoryImplementor factory = event.getSession().getFactory();

			Serializable requestedId = event.getRequestedId();

			Serializable savedId;
			if ( requestedId == null ) {
				savedId = entityEntry.getId();
			}
			else {

				final boolean isEqual = !entityEntry.getPersister().getIdentifierType()
						.isEqual( requestedId, entityEntry.getId(), event.getSession().getEntityMode(), factory );

				if ( isEqual ) {
					throw new PersistentObjectException(
							"object passed to save() was already persistent: " +
									MessageHelper.infoString( entityEntry.getPersister(), requestedId, factory )
					);
				}

				savedId = requestedId;

			}

			if ( log.isTraceEnabled() ) {
				log.trace(
						"object already associated with session: " +
								MessageHelper.infoString( entityEntry.getPersister(), savedId, factory )
				);
			}

			return savedId;

		}
	
protected java.io.SerializableentityIsTransient(org.hibernate.event.SaveOrUpdateEvent event)
The given save-update event named a transient entity.

Here, we will perform the save processing.

param
event The save event to be handled.
return
The entity's identifier after saving.


		log.trace( "saving transient instance" );

		final EventSource source = event.getSession();

		EntityEntry entityEntry = event.getEntry();
		if ( entityEntry != null ) {
			if ( entityEntry.getStatus() == Status.DELETED ) {
				source.forceFlush( entityEntry );
			}
			else {
				throw new AssertionFailure( "entity was persistent" );
			}
		}

		Serializable id = saveWithGeneratedOrRequestedId( event );

		source.getPersistenceContext().reassociateProxy( event.getObject(), id );

		return id;
	
protected org.hibernate.engine.CascadingActiongetCascadeAction()

		return CascadingAction.SAVE_UPDATE;
	
protected java.io.SerializablegetUpdateId(java.lang.Object entity, org.hibernate.persister.entity.EntityPersister persister, java.io.Serializable requestedId, org.hibernate.EntityMode entityMode)
Determine the id to use for updating.

param
entity The entity.
param
persister The entity persister
param
requestedId The requested identifier
param
entityMode The entity mode.
return
The id.
throws
TransientObjectException If the entity is considered transient.

		// use the id assigned to the instance
		Serializable id = persister.getIdentifier( entity, entityMode );
		if ( id == null ) {
			// assume this is a newly instantiated transient object
			// which should be saved rather than updated
			throw new TransientObjectException(
					"The given object has a null identifier: " +
							persister.getEntityName()
			);
		}
		else {
			return id;
		}

	
protected booleaninvokeUpdateLifecycle(java.lang.Object entity, org.hibernate.persister.entity.EntityPersister persister, org.hibernate.event.EventSource source)

		if ( persister.implementsLifecycle( source.getEntityMode() ) ) {
			log.debug( "calling onUpdate()" );
			if ( ( ( Lifecycle ) entity ).onUpdate( source ) ) {
				log.debug( "update vetoed by onUpdate()" );
				return true;
			}
		}
		return false;
	
public voidonSaveOrUpdate(org.hibernate.event.SaveOrUpdateEvent event)
Handle the given update event.

param
event The update event to be handled.


	             	 
	    
		final SessionImplementor source = event.getSession();
		final Object object = event.getObject();
		final Serializable requestedId = event.getRequestedId();

		if ( requestedId != null ) {
			//assign the requested id to the proxy, *before* 
			//reassociating the proxy
			if ( object instanceof HibernateProxy ) {
				( ( HibernateProxy ) object ).getHibernateLazyInitializer().setIdentifier( requestedId );
			}
		}

		if ( reassociateIfUninitializedProxy( object, source ) ) {
			log.trace( "reassociated uninitialized proxy" );
			// an uninitialized proxy, noop, don't even need to 
			// return an id, since it is never a save()
		}
		else {
			//initialize properties of the event:
			final Object entity = source.getPersistenceContext().unproxyAndReassociate( object );
			event.setEntity( entity );
			event.setEntry( source.getPersistenceContext().getEntry( entity ) );
			//return the id in the event object
			event.setResultId( performSaveOrUpdate( event ) );
		}

	
protected java.io.SerializableperformSaveOrUpdate(org.hibernate.event.SaveOrUpdateEvent event)

		int entityState = getEntityState(
				event.getEntity(),
				event.getEntityName(),
				event.getEntry(),
				event.getSession()
		);

		switch ( entityState ) {
			case DETACHED:
				entityIsDetached( event );
				return null;
			case PERSISTENT:
				return entityIsPersistent( event );
			default: //TRANSIENT or DELETED
				return entityIsTransient( event );
		}
	
protected voidperformUpdate(org.hibernate.event.SaveOrUpdateEvent event, java.lang.Object entity, org.hibernate.persister.entity.EntityPersister persister)


		if ( !persister.isMutable() ) {
			log.trace( "immutable instance passed to doUpdate(), locking" );
			reassociate( event, entity, event.getRequestedId(), persister );
		}
		else {

			if ( log.isTraceEnabled() ) {
				log.trace(
						"updating " +
								MessageHelper.infoString(
										persister, event.getRequestedId(), event.getSession().getFactory()
								)
				);
			}

			final EventSource source = event.getSession();

			EntityKey key = new EntityKey( event.getRequestedId(), persister, source.getEntityMode() );

			source.getPersistenceContext().checkUniqueness( key, entity );

			if ( invokeUpdateLifecycle( entity, persister, source ) ) {
				reassociate( event, event.getObject(), event.getRequestedId(), persister );
				return;
			}

			// this is a transient object with existing persistent state not loaded by the session

			new OnUpdateVisitor( source, event.getRequestedId(), entity ).process( entity, persister );

			//TODO: put this stuff back in to read snapshot from
			//      the second-level cache (needs some extra work)
			/*Object[] cachedState = null;

			if ( persister.hasCache() ) {
				CacheEntry entry = (CacheEntry) persister.getCache()
						.get( event.getRequestedId(), source.getTimestamp() );
			    cachedState = entry==null ? 
			    		null : 
			    		entry.getState(); //TODO: half-assemble this stuff
			}*/

			source.getPersistenceContext().addEntity(
					entity,
					Status.MANAGED,
					null, //cachedState,
					key,
					persister.getVersion( entity, source.getEntityMode() ),
					LockMode.NONE,
					true,
					persister,
					false,
					true //assume true, since we don't really know, and it doesn't matter
			);

			persister.afterReassociate( entity, source );

			if ( log.isTraceEnabled() ) {
				log.trace(
						"updating " +
								MessageHelper.infoString( persister, event.getRequestedId(), source.getFactory() )
				);
			}

			cascadeOnUpdate( event, persister, entity );

		}
	
protected booleanreassociateIfUninitializedProxy(java.lang.Object object, org.hibernate.engine.SessionImplementor source)

		return source.getPersistenceContext().reassociateIfUninitializedProxy( object );
	
protected java.io.SerializablesaveWithGeneratedOrRequestedId(org.hibernate.event.SaveOrUpdateEvent event)
Save the transient instance, assigning the right identifier

param
event The initiating event.
return
The entity's identifier value after saving.

		return saveWithGeneratedId(
				event.getEntity(),
				event.getEntityName(),
				null,
				event.getSession(),
				true
		);