abstractsaveeventlistener.java

来自「好东西,hibernate-3.2.0,他是一开元的树杖hibernate-3.」· Java 代码 · 共 518 行 · 第 1/2 页

JAVA
518
字号
//$Id: AbstractSaveEventListener.java 9673 2006-03-22 14:57:59Z steve.ebersole@jboss.com $
package org.hibernate.event.def;

import java.io.Serializable;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.NonUniqueObjectException;
import org.hibernate.action.EntityIdentityInsertAction;
import org.hibernate.action.EntityInsertAction;
import org.hibernate.classic.Lifecycle;
import org.hibernate.classic.Validatable;
import org.hibernate.engine.Cascade;
import org.hibernate.engine.CascadingAction;
import org.hibernate.engine.EntityEntry;
import org.hibernate.engine.EntityKey;
import org.hibernate.engine.ForeignKeys;
import org.hibernate.engine.Nullability;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.Status;
import org.hibernate.engine.Versioning;
import org.hibernate.event.EventSource;
import org.hibernate.id.IdentifierGenerationException;
import org.hibernate.id.IdentifierGeneratorFactory;
import org.hibernate.intercept.FieldInterceptionHelper;
import org.hibernate.intercept.FieldInterceptor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.type.Type;
import org.hibernate.type.TypeFactory;

/**
 * A convenience bas class for listeners responding to save events.
 *
 * @author Steve Ebersole.
 */
public abstract class AbstractSaveEventListener extends AbstractReassociateEventListener {

	protected static final int PERSISTENT = 0;
	protected static final int TRANSIENT = 1;
	protected static final int DETACHED = 2;
	protected static final int DELETED = 3;

	private static final Log log = LogFactory.getLog(AbstractSaveEventListener.class);

	/**
	 * Prepares the save call using the given requested id.
	 * @param entity The entity to be saved.
	 * @param requestedId The id to which to associate the entity.
	 * @param source The session which is the source of this save event.
	 * @return The id used to save the entity.
	 * @throws HibernateException
	 */
	protected Serializable saveWithRequestedId(
			Object entity,
			Serializable requestedId,
			String entityName,
			Object anything,
			EventSource source) 
	throws HibernateException {
		return performSave(
				entity,
				requestedId,
				source.getEntityPersister(entityName, entity),
				false,
				anything,
				source,
		        true
			);
	}

	/**
	 * Prepares the save call using a newly generated id.
	 * @param entity The entity to be saved
	 * @param entityName The entity-name for the entity to be saved
	 * @param source The session which is the source of this save event.
	 * @param requiresImmediateIdAccess does the event context require
	 * access to the identifier immediately after execution of this method (if
	 * not, post-insert style id generators may be postponed if we are outside
	 * a transaction).
	 * @return The id used to save the entity; may be null depending on the
	 * type of id generator used and the requiresImmediateIdAccess value
	 * @throws HibernateException
	 */
	protected Serializable saveWithGeneratedId(
			Object entity,
			String entityName,
			Object anything,
			EventSource source,
	        boolean requiresImmediateIdAccess)
	throws HibernateException {
		
		EntityPersister persister = source.getEntityPersister(entityName, entity);

		Serializable generatedId = persister.getIdentifierGenerator()
			.generate( source, entity );
		
		if ( generatedId == null ) {
			throw new IdentifierGenerationException( "null id generated for:" + entity.getClass() );
		}
		else if ( generatedId == IdentifierGeneratorFactory.SHORT_CIRCUIT_INDICATOR ) {
			return source.getIdentifier( entity );
		}
		else if ( generatedId == IdentifierGeneratorFactory.POST_INSERT_INDICATOR ) {
			return performSave( entity, null, persister, true, anything, source, requiresImmediateIdAccess );
		}
		else {
			
			if ( log.isDebugEnabled() ) {
				log.debug(
						"generated identifier: " + 
						persister.getIdentifierType().toLoggableString( generatedId, source.getFactory() ) + 
						", using strategy: " + 
						persister.getIdentifierGenerator().getClass().getName() //TODO: define toString()s for generators
					);
			}
			
			return performSave( entity, generatedId, persister, false, anything, source, true );
		}
	}

	/**
	 * Ppepares the save call by checking the session caches for a pre-existing
	 * entity and performing any lifecycle callbacks.
	 * @param entity The entity to be saved.
	 * @param id The id by which to save the entity.
	 * @param persister The entity's persister instance.
	 * @param useIdentityColumn Is an identity column in use?
	 * @param source The session from which the event originated.
	 * @param requiresImmediateIdAccess does the event context require
	 * access to the identifier immediately after execution of this method (if
	 * not, post-insert style id generators may be postponed if we are outside
	 * a transaction).
	 * @return The id used to save the entity; may be null depending on the
	 * type of id generator used and the requiresImmediateIdAccess value
	 * @throws HibernateException
	 */
	protected Serializable performSave(
			Object entity,
			Serializable id,
			EntityPersister persister,
			boolean useIdentityColumn,
			Object anything,
			EventSource source,
	        boolean requiresImmediateIdAccess)
	throws HibernateException {

		if ( log.isTraceEnabled() ) {
			log.trace( 
					"saving " + 
					MessageHelper.infoString( persister, id, source.getFactory() ) 
				);
		}
		
		EntityKey key;
		if ( !useIdentityColumn ) {
			key = new EntityKey( id, persister, source.getEntityMode() );
			Object old = source.getPersistenceContext().getEntity(key);
			if (old != null) {
				if ( source.getPersistenceContext().getEntry(old).getStatus() == Status.DELETED ) {
					source.forceFlush( source.getPersistenceContext().getEntry(old) );
				}
				else {
					throw new NonUniqueObjectException( id, persister.getEntityName() );
				}
			}
			persister.setIdentifier(entity, id, source.getEntityMode());
		}
		else {
			key = null;
		}
		
		if ( invokeSaveLifecycle(entity, persister, source) ) {
			return id; //EARLY EXIT
		}

		return performSaveOrReplicate(
				entity, 
				key, 
				persister, 
				useIdentityColumn, 
				anything, 
				source,
		        requiresImmediateIdAccess
			);
	}
	
	protected boolean invokeSaveLifecycle(Object entity, EntityPersister persister, EventSource source) {
		// Sub-insertions should occur before containing insertion so
		// Try to do the callback now
		if ( persister.implementsLifecycle( source.getEntityMode() ) ) {
			log.debug( "calling onSave()" );
			if ( ( (Lifecycle) entity ).onSave(source) ) {
				log.debug( "insertion vetoed by onSave()" );
				return true;
			}
		}
		return false;
	}

	protected void validate(Object entity, EntityPersister persister, EventSource source) {
		if ( persister.implementsValidatable( source.getEntityMode() ) ) {
            ( ( Validatable ) entity ).validate();
        }
	}

	/**
	 * Performs all the actual work needed to save an entity (well to get the save moved to
	 * the execution queue).
	 * @param entity The entity to be saved
	 * @param key The id to be used for saving the entity (or null, in the case of identity columns)
	 * @param persister The entity's persister instance.
	 * @param useIdentityColumn Should an identity column be used for id generation?
	 * @param source The session which is the source of the current event.
	 * @return The id used to save the entity; may be null depending on the
	 * type of id generator used and the requiresImmediateIdAccess value
	 * @throws HibernateException
	 */
	protected Serializable performSaveOrReplicate(
			Object entity,
			EntityKey key,
			EntityPersister persister,
			boolean useIdentityColumn,
			Object anything,
			EventSource source,
	        boolean requiresImmediateIdAccess)
	throws HibernateException {
		
		validate( entity, persister, source );

		Serializable id = key==null ? null : key.getIdentifier();

		boolean inTxn = source.getJDBCContext().isTransactionInProgress();
		boolean shouldDelayIdentityInserts = !inTxn && !requiresImmediateIdAccess;

		if ( useIdentityColumn && !shouldDelayIdentityInserts ) {
			log.trace("executing insertions");
			source.getActionQueue().executeInserts();
		}

		// Put a placeholder in entries, so we don't recurse back and try to save() the
		// same object again. QUESTION: should this be done before onSave() is called?
		// likewise, should it be done before onUpdate()?
		source.getPersistenceContext().addEntry(
				entity,
				Status.SAVING,
				null,
				null,
				id,
				null,
				LockMode.WRITE,
				useIdentityColumn,
				persister, 
				false, 
				false
			);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?