defaultmergeeventlistener.java

来自「hibernate-distribution-3.3.1.GA-dist.zip」· Java 代码 · 共 491 行 · 第 1/2 页

JAVA
491
字号
/* * Hibernate, Relational Persistence for Idiomatic Java * * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors.  All third-party contributions are * distributed under license by Red Hat Middleware LLC. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * Boston, MA  02110-1301  USA * */package org.hibernate.event.def;import java.io.Serializable;import java.util.Iterator;import java.util.Map;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.hibernate.AssertionFailure;import org.hibernate.HibernateException;import org.hibernate.ObjectDeletedException;import org.hibernate.StaleObjectStateException;import org.hibernate.TransientObjectException;import org.hibernate.WrongClassException;import org.hibernate.engine.Cascade;import org.hibernate.engine.CascadingAction;import org.hibernate.engine.EntityEntry;import org.hibernate.engine.EntityKey;import org.hibernate.engine.SessionImplementor;import org.hibernate.engine.Status;import org.hibernate.event.EventSource;import org.hibernate.event.MergeEvent;import org.hibernate.event.MergeEventListener;import org.hibernate.intercept.FieldInterceptionHelper;import org.hibernate.intercept.FieldInterceptor;import org.hibernate.persister.entity.EntityPersister;import org.hibernate.proxy.HibernateProxy;import org.hibernate.proxy.LazyInitializer;import org.hibernate.type.ForeignKeyDirection;import org.hibernate.type.TypeFactory;import org.hibernate.util.IdentityMap;/** * Defines the default copy event listener used by hibernate for copying entities * in response to generated copy events. * * @author Gavin King */public class DefaultMergeEventListener extends AbstractSaveEventListener 	implements MergeEventListener {	private static final Logger log = LoggerFactory.getLogger(DefaultMergeEventListener.class);		protected Map getMergeMap(Object anything) {		return IdentityMap.invert( (Map) anything );	}	/**	 * Handle the given merge event.	 *	 * @param event The merge event to be handled.	 * @throws HibernateException	 */	public void onMerge(MergeEvent event) throws HibernateException {		Map copyCache = IdentityMap.instantiate(10);		onMerge( event, copyCache );		for ( Iterator it=copyCache.values().iterator(); it.hasNext(); ) {			Object entity = it.next();			if ( entity instanceof HibernateProxy ) {				entity = ( (HibernateProxy) entity ).getHibernateLazyInitializer().getImplementation();			}			EntityEntry entry = event.getSession().getPersistenceContext().getEntry( entity );			if ( entry == null ) {				throw new TransientObjectException(						"object references an unsaved transient instance - save the transient instance before merging: " +						event.getSession().guessEntityName( entity )				);				// TODO: cache the entity name somewhere so that it is available to this exception				// entity name will not be available for non-POJO entities			}			if ( entry.getStatus() != Status.MANAGED ) {				throw new AssertionFailure( "Merged entity does not have status set to MANAGED; "+entry+" status="+entry.getStatus() );			}		}	}	/** 	 * Handle the given merge event.	 *	 * @param event The merge event to be handled.	 * @throws HibernateException	 */	public void onMerge(MergeEvent event, Map copyCache) throws HibernateException {		final EventSource source = event.getSession();		final Object original = event.getOriginal();		if ( original != null ) {			final Object entity;			if ( original instanceof HibernateProxy ) {				LazyInitializer li = ( (HibernateProxy) original ).getHibernateLazyInitializer();				if ( li.isUninitialized() ) {					log.trace("ignoring uninitialized proxy");					event.setResult( source.load( li.getEntityName(), li.getIdentifier() ) );					return; //EARLY EXIT!				}				else {					entity = li.getImplementation();				}			}			else {				entity = original;			}						if ( copyCache.containsKey(entity) &&					source.getContextEntityIdentifier( copyCache.get( entity ) ) != null ) {				log.trace("already merged");				event.setResult(entity);			}			else {				event.setEntity( entity );				int entityState = -1;				// Check the persistence context for an entry relating to this				// entity to be merged...				EntityEntry entry = source.getPersistenceContext().getEntry( entity );				if ( entry == null ) {					EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity );					Serializable id = persister.getIdentifier( entity, source.getEntityMode() );					if ( id != null ) {						EntityKey key = new EntityKey( id, persister, source.getEntityMode() );						Object managedEntity = source.getPersistenceContext().getEntity( key );						entry = source.getPersistenceContext().getEntry( managedEntity );						if ( entry != null ) {							// we have specialized case of a detached entity from the							// perspective of the merge operation.  Specifically, we							// have an incoming entity instance which has a corresponding							// entry in the current persistence context, but registered							// under a different entity instance							entityState = DETACHED;						}					}				}				if ( entityState == -1 ) {					entityState = getEntityState( entity, event.getEntityName(), entry, source );				}								switch (entityState) {					case DETACHED:						entityIsDetached(event, copyCache);						break;					case TRANSIENT:						entityIsTransient(event, copyCache);						break;					case PERSISTENT:						entityIsPersistent(event, copyCache);						break;					default: //DELETED						throw new ObjectDeletedException(								"deleted instance passed to merge", 								null, 								getLoggableName( event.getEntityName(), entity )							);							}			}					}			}	protected void entityIsPersistent(MergeEvent event, Map copyCache) {		log.trace("ignoring persistent instance");				//TODO: check that entry.getIdentifier().equals(requestedId)				final Object entity = event.getEntity();		final EventSource source = event.getSession();		final EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity );				copyCache.put(entity, entity); //before cascade!				cascadeOnMerge(source, persister, entity, copyCache);		copyValues(persister, entity, entity, source, copyCache);				event.setResult(entity);	}		protected void entityIsTransient(MergeEvent event, Map copyCache) {				log.trace("merging transient instance");				final Object entity = event.getEntity();		final EventSource source = event.getSession();		final EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity );		final String entityName = persister.getEntityName();				final Serializable id = persister.hasIdentifierProperty() ?				persister.getIdentifier( entity, source.getEntityMode() ) :		        null;		if ( copyCache.containsKey( entity ) ) {			persister.setIdentifier( copyCache.get( entity ), id, source.getEntityMode() );		}		else {			copyCache.put(entity, persister.instantiate( id, source.getEntityMode() ) ); //before cascade!			//TODO: should this be Session.instantiate(Persister, ...)?		}		final Object copy = copyCache.get( entity );		// cascade first, so that all unsaved objects get their		// copy created before we actually copy		//cascadeOnMerge(event, persister, entity, copyCache, Cascades.CASCADE_BEFORE_MERGE);		super.cascadeBeforeSave(source, persister, entity, copyCache);		copyValues(persister, entity, copy, source, copyCache, ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT);				//this bit is only *really* absolutely necessary for handling 		//requestedId, but is also good if we merge multiple object 		//graphs, since it helps ensure uniqueness		final Serializable requestedId = event.getRequestedId();		if (requestedId==null) {			saveWithGeneratedId( copy, entityName, copyCache, source, false );		}		else {			saveWithRequestedId( copy, requestedId, entityName, copyCache, source );		}				// cascade first, so that all unsaved objects get their 		// copy created before we actually copy		super.cascadeAfterSave(source, persister, entity, copyCache);

⌨️ 快捷键说明

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