⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 statefulpersistencecontext.java

📁 hibernate-3.1.3-all-src.zip 面向对象的访问数据库工具
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
// $Id: StatefulPersistenceContext.java 9194 2006-02-01 19:59:07Z steveebersole $
package org.hibernate.engine;

import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.ReferenceMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.AssertionFailure;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.NonUniqueObjectException;
import org.hibernate.PersistentObjectException;
import org.hibernate.TransientObjectException;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.tuple.ElementWrapper;
import org.hibernate.util.IdentityMap;
import org.hibernate.util.MarkerObject;

/**
 * A <tt>PersistenceContext</tt> represents the state of persistent "stuff" which
 * Hibernate is tracking.  This includes persistent entities, collections,
 * as well as proxies generated.
 * </p>
 * There is meant to be a one-to-one correspondence between a SessionImpl and
 * a PersistentContext.  The SessionImpl uses the PersistentContext to track
 * the current state of its context.  Event-listeners then use the
 * PersistentContext to drive their processing.
 *
 * @author Steve Ebersole
 */
public class StatefulPersistenceContext implements PersistenceContext {

	public static final Object NO_ROW = new MarkerObject( "NO_ROW" );

	private static final Log log = LogFactory.getLog( StatefulPersistenceContext.class );
	private static final Log PROXY_WARN_LOG = LogFactory.getLog( StatefulPersistenceContext.class.getName() + ".ProxyWarnLog" );
	private static final int INIT_COLL_SIZE = 8;

	private SessionImplementor session;
	
	// Loaded entity instances, by EntityKey
	private Map entitiesByKey;

	// Loaded entity instances, by EntityUniqueKey
	private Map entitiesByUniqueKey;
	
	// Identity map of EntityEntry instances, by the entity instance
	private Map entityEntries;
	
	// Entity proxies, by EntityKey
	private Map proxiesByKey;
	
	// Snapshots of current database state for entities
	// that have *not* been loaded
	private Map entitySnapshotsByKey;
	
	// Identity map of array holder ArrayHolder instances, by the array instance
	private Map arrayHolders;
	
	// Identity map of CollectionEntry instances, by the collection wrapper
	private Map collectionEntries;
	
	// Collection wrappers, by the CollectionKey
	private Map collectionsByKey; //key=CollectionKey, value=PersistentCollection
	
	// Set of EntityKeys of deleted objects
	private HashSet nullifiableEntityKeys;
	
	// properties that we have tried to load, and not found in the database
	private HashSet nullAssociations;
	
	// A list of collection wrappers that were instantiating during result set
	// processing, that we will need to initialize at the end of the query
	private List nonlazyCollections;
	
	// A container for collections we load up when the owning entity is not
	// yet loaded ... for now, this is purely transient!
	private Map unownedCollections;
	
	private int cascading = 0;
	private int loadCounter = 0;
	private boolean flushing = false;
	
	private boolean hasNonReadOnlyEntities = false;
	
	private CollectionLoadContext collectionLoadContext;
	private BatchFetchQueue batchFetchQueue;



	/**
	 * Constructs a PersistentContext, bound to the given session.
	 *
	 * @param session The session "owning" this context.
	 */
	public StatefulPersistenceContext(SessionImplementor session) {
		this.session = session;

		entitiesByKey = new HashMap( INIT_COLL_SIZE );
		entitiesByUniqueKey = new HashMap( INIT_COLL_SIZE );
		proxiesByKey = new ReferenceMap( ReferenceMap.HARD, ReferenceMap.WEAK );
		entitySnapshotsByKey = new HashMap( INIT_COLL_SIZE );

		entityEntries = IdentityMap.instantiateSequenced( INIT_COLL_SIZE );
		collectionEntries = IdentityMap.instantiateSequenced( INIT_COLL_SIZE );
		collectionsByKey = new HashMap( INIT_COLL_SIZE );
		arrayHolders = IdentityMap.instantiate( INIT_COLL_SIZE );

		nullifiableEntityKeys = new HashSet();

		initTransientState();
	}

	private void initTransientState() {
		nullAssociations = new HashSet( INIT_COLL_SIZE );
		nonlazyCollections = new ArrayList( INIT_COLL_SIZE );
	}

	public boolean isStateless() {
		return false;
	}
	
	public SessionImplementor getSession() {
		return session;
	}
	
	public CollectionLoadContext getCollectionLoadContext() {
		if (collectionLoadContext==null) {
			collectionLoadContext = new CollectionLoadContext(this);
		}
		return collectionLoadContext;
	}
	
	public void addUnownedCollection(CollectionKey key, PersistentCollection collection) {
		if (unownedCollections==null) {
			unownedCollections = new HashMap(8);
		}
		unownedCollections.put(key, collection);
	}
	
	public PersistentCollection useUnownedCollection(CollectionKey key) {
		if (unownedCollections==null) {
			return null;
		}
		else {
			return (PersistentCollection) unownedCollections.remove(key);
		}
	}
	
	/**
	 * Get the <tt>BatchFetchQueue</tt>, instantiating one if
	 * necessary.
	 */
	public BatchFetchQueue getBatchFetchQueue() {
		if (batchFetchQueue==null) {
			batchFetchQueue = new BatchFetchQueue(this);
		}
		return batchFetchQueue;
	}

	public void clear() {
		arrayHolders.clear();
		entitiesByKey.clear();
		entitiesByUniqueKey.clear();
		entityEntries.clear();
		entitySnapshotsByKey.clear();
		collectionsByKey.clear();
		collectionEntries.clear();
		if ( unownedCollections != null ) {
			unownedCollections.clear();
		}
		proxiesByKey.clear();
		nullifiableEntityKeys.clear();
		if ( batchFetchQueue != null ) {
			batchFetchQueue.clear();
		}
		hasNonReadOnlyEntities = false;
	}
	
	public boolean hasNonReadOnlyEntities() {
		return hasNonReadOnlyEntities;
	}
	
	public void setEntryStatus(EntityEntry entry, Status status) {
		entry.setStatus(status);
		setHasNonReadOnlyEnties(status);
	}
	
	private void setHasNonReadOnlyEnties(Status status) {
		if ( status==Status.DELETED || status==Status.MANAGED || status==Status.SAVING ) {
			hasNonReadOnlyEntities = true;
		}
	}

	public void afterTransactionCompletion() {
		// Downgrade locks
		Iterator iter = entityEntries.values().iterator();
		while ( iter.hasNext() ) {
			( (EntityEntry) iter.next() ).setLockMode(LockMode.NONE);
		}
	}

	/**
	 * Get the current state of the entity as known to the underlying
	 * database, or null if there is no corresponding row 
	 */
	public Object[] getDatabaseSnapshot(Serializable id, EntityPersister persister)
	throws HibernateException {
		EntityKey key = new EntityKey( id, persister, session.getEntityMode() );
		Object cached = entitySnapshotsByKey.get(key);
		if (cached!=null) {
			return cached==NO_ROW ? null : (Object[]) cached;
		}
		else {
			Object[] snapshot = persister.getDatabaseSnapshot( id, session );
			entitySnapshotsByKey.put( key, snapshot==null ? NO_ROW : snapshot );
			return snapshot;
		}
	}

	public Object[] getNaturalIdSnapshot(Serializable id, EntityPersister persister)
	throws HibernateException {
		if ( !persister.hasNaturalIdentifier() ) {
			return null;
		}

		// if the natural-id is marked as non-mutable, it is not retrieved during a
		// normal database-snapshot operation...
		int[] props = persister.getNaturalIdentifierProperties();
		boolean[] updateable = persister.getPropertyUpdateability();
		boolean allNatualIdPropsAreUpdateable = true;
		for ( int i = 0; i < props.length; i++ ) {
			if ( !updateable[ props[i] ] ) {
				allNatualIdPropsAreUpdateable = false;
				break;
			}
		}

		if ( allNatualIdPropsAreUpdateable ) {
			// do this when all the properties are updateable since there is
			// a certain likelihood that the information will already be
			// snapshot-cached.
			Object[] entitySnapshot = getDatabaseSnapshot( id, persister );
			if ( entitySnapshot == NO_ROW ) {
				return null;
			}
			Object[] naturalIdSnapshot = new Object[ props.length ];
			for ( int i = 0; i < props.length; i++ ) {
				naturalIdSnapshot[i] = entitySnapshot[ props[i] ];
			}
			return naturalIdSnapshot;
		}
		else {
			return persister.getNaturalIdentifierSnapshot( id, session );
		}
	}

	public Object[] getCachedDatabaseSnapshot(EntityKey key) {
		//TODO: assertion failure if NO_ROW
		return (Object[]) entitySnapshotsByKey.get(key);
	}

	/*public void removeDatabaseSnapshot(EntityKey key) {
		entitySnapshotsByKey.remove(key);
	}*/

	public void addEntity(EntityKey key, Object entity) {
		entitiesByKey.put(key, entity);
		getBatchFetchQueue().removeBatchLoadableEntityKey(key);
	}

	/**
	 * Get the entity instance associated with the given 
	 * <tt>EntityKey</tt>
	 */
	public Object getEntity(EntityKey key) {
		return entitiesByKey.get(key);
	}

	public boolean containsEntity(EntityKey key) {
		return entitiesByKey.containsKey(key);
	}

	/**
	 * Remove an entity from the session cache, also clear
	 * up other state associated with the entity, all except
	 * for the <tt>EntityEntry</tt>
	 */
	public Object removeEntity(EntityKey key) {
		Object entity = entitiesByKey.remove(key);
		Iterator iter = entitiesByUniqueKey.values().iterator();
		while ( iter.hasNext() ) {
			if ( iter.next()==entity ) iter.remove();
		}
		entitySnapshotsByKey.remove(key);
		nullifiableEntityKeys.remove(key);
		getBatchFetchQueue().removeBatchLoadableEntityKey(key);
		getBatchFetchQueue().removeSubselect(key);
		return entity;
	}

	/**
	 * Get an entity cached by unique key
	 */
	public Object getEntity(EntityUniqueKey euk) {
		return entitiesByUniqueKey.get(euk);
	}

	/**
	 * Add an entity to the cache by unique key
	 */
	public void addEntity(EntityUniqueKey euk, Object entity) {
		entitiesByUniqueKey.put(euk, entity);
	}

	/**
	 * Retreive the EntityEntry representation of the given entity.
	 *
	 * @param entity The entity for which to locate the EntityEntry.
	 * @return The EntityEntry for the given entity.
	 */
	public EntityEntry getEntry(Object entity) {
		return (EntityEntry) entityEntries.get(entity);
	}

	/**
	 * Remove an entity entry from the session cache
	 */
	public EntityEntry removeEntry(Object entity) {
		return (EntityEntry) entityEntries.remove(entity);
	}

	/**
	 * Is there an EntityEntry for this instance?
	 */
	public boolean isEntryFor(Object entity) {
		return entityEntries.containsKey(entity);
	}

	/**
	 * Get the collection entry for a persistent collection
	 */
	public CollectionEntry getCollectionEntry(PersistentCollection coll) {
		return (CollectionEntry) collectionEntries.get(coll);
	}

	/**
	 * Adds an entity to the internal caches.
	 */
	public EntityEntry addEntity(
			final Object entity,
			final Status status,
			final Object[] loadedState,
			final EntityKey entityKey,
			final Object version,
			final LockMode lockMode,
			final boolean existsInDatabase,
			final EntityPersister persister,
			final boolean disableVersionIncrement, 
			boolean lazyPropertiesAreUnfetched
	) {
		
		addEntity( entityKey, entity );
		
		return addEntry(
				entity,
				status,
				loadedState,
				null,
				entityKey.getIdentifier(),
				version,
				lockMode,
				existsInDatabase,
				persister,
				disableVersionIncrement, 
				lazyPropertiesAreUnfetched
			);
	}


	/**
	 * Generates an appropriate EntityEntry instance and adds it 
	 * to the event source's internal caches.
	 */
	public EntityEntry addEntry(
			final Object entity,
			final Status status,
			final Object[] loadedState,
			final Object rowId,
			final Serializable id,
			final Object version,
			final LockMode lockMode,
			final boolean existsInDatabase,
			final EntityPersister persister,
			final boolean disableVersionIncrement, 
			boolean lazyPropertiesAreUnfetched) {
		
		EntityEntry e = new EntityEntry(
				status,
				loadedState,
				rowId,
				id,
				version,
				lockMode,
				existsInDatabase,
				persister,
				session.getEntityMode(),
				disableVersionIncrement,
				lazyPropertiesAreUnfetched
			);
		entityEntries.put(entity, e);
		
		setHasNonReadOnlyEnties(status);
		return e;
	}

⌨️ 快捷键说明

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