📄 abstractpersistentcollection.java
字号:
//$Id: AbstractPersistentCollection.java 11302 2007-03-19 20:44:11Z steve.ebersole@jboss.com $package org.hibernate.collection;import java.io.Serializable;import java.util.ArrayList;import java.util.Collection;import java.util.HashSet;import java.util.Iterator;import java.util.List;import java.util.ListIterator;import org.hibernate.AssertionFailure;import org.hibernate.HibernateException;import org.hibernate.LazyInitializationException;import org.hibernate.engine.CollectionEntry;import org.hibernate.engine.ForeignKeys;import org.hibernate.engine.SessionImplementor;import org.hibernate.engine.TypedValue;import org.hibernate.persister.collection.CollectionPersister;import org.hibernate.pretty.MessageHelper;import org.hibernate.type.Type;import org.hibernate.util.CollectionHelper;import org.hibernate.util.EmptyIterator;import org.hibernate.util.MarkerObject;/** * Base class implementing <tt>PersistentCollection</tt> * @see PersistentCollection * @author Gavin King */public abstract class AbstractPersistentCollection implements Serializable, PersistentCollection { private transient SessionImplementor session; private boolean initialized; private transient List operationQueue; private transient boolean directlyAccessible; private transient boolean initializing; private Object owner; private int cachedSize = -1; private String role; private Serializable key; // collections detect changes made via their public interface and mark // themselves as dirty as a performance optimization private boolean dirty; private Serializable storedSnapshot; public final String getRole() { return role; } public final Serializable getKey() { return key; } public final boolean isUnreferenced() { return role==null; } public final boolean isDirty() { return dirty; } public final void clearDirty() { dirty = false; } public final void dirty() { dirty = true; } public final Serializable getStoredSnapshot() { return storedSnapshot; } //Careful: these methods do not initialize the collection. /** * Is the initialized collection empty? */ public abstract boolean empty(); /** * Called by any read-only method of the collection interface */ protected final void read() { initialize(false); } /** * Called by the <tt>size()</tt> method */ protected boolean readSize() { if (!initialized) { if ( cachedSize!=-1 && !hasQueuedOperations() ) { return true; } else { throwLazyInitializationExceptionIfNotConnected(); CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(this); CollectionPersister persister = entry.getLoadedPersister(); if ( persister.isExtraLazy() ) { if ( hasQueuedOperations() ) { session.flush(); } cachedSize = persister.getSize( entry.getLoadedKey(), session ); return true; } } } read(); return false; } protected Boolean readIndexExistence(Object index) { if (!initialized) { throwLazyInitializationExceptionIfNotConnected(); CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(this); CollectionPersister persister = entry.getLoadedPersister(); if ( persister.isExtraLazy() ) { if ( hasQueuedOperations() ) { session.flush(); } return new Boolean( persister.indexExists( entry.getLoadedKey(), index, session ) ); } } read(); return null; } protected Boolean readElementExistence(Object element) { if (!initialized) { throwLazyInitializationExceptionIfNotConnected(); CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(this); CollectionPersister persister = entry.getLoadedPersister(); if ( persister.isExtraLazy() ) { if ( hasQueuedOperations() ) { session.flush(); } return new Boolean( persister.elementExists( entry.getLoadedKey(), element, session ) ); } } read(); return null; } protected static final Object UNKNOWN = new MarkerObject("UNKNOWN"); protected Object readElementByIndex(Object index) { if (!initialized) { throwLazyInitializationExceptionIfNotConnected(); CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(this); CollectionPersister persister = entry.getLoadedPersister(); if ( persister.isExtraLazy() ) { if ( hasQueuedOperations() ) { session.flush(); } return persister.getElementByIndex( entry.getLoadedKey(), index, session, owner ); } } read(); return UNKNOWN; } protected int getCachedSize() { return cachedSize; } /** * Is the collection currently connected to an open session? */ private final boolean isConnectedToSession() { return session!=null && session.isOpen() && session.getPersistenceContext().containsCollection(this); } /** * Called by any writer method of the collection interface */ protected final void write() { initialize(true); dirty(); } /** * Is this collection in a state that would allow us to * "queue" operations? */ protected boolean isOperationQueueEnabled() { return !initialized && isConnectedToSession() && isInverseCollection(); } /** * Is this collection in a state that would allow us to * "queue" puts? This is a special case, because of orphan * delete. */ protected boolean isPutQueueEnabled() { return !initialized && isConnectedToSession() && isInverseOneToManyOrNoOrphanDelete(); } /** * Is this collection in a state that would allow us to * "queue" clear? This is a special case, because of orphan * delete. */ protected boolean isClearQueueEnabled() { return !initialized && isConnectedToSession() && isInverseCollectionNoOrphanDelete(); } /** * Is this the "inverse" end of a bidirectional association? */ private boolean isInverseCollection() { CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(this); return ce != null && ce.getLoadedPersister().isInverse(); } /** * Is this the "inverse" end of a bidirectional association with * no orphan delete enabled? */ private boolean isInverseCollectionNoOrphanDelete() { CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(this); return ce != null && ce.getLoadedPersister().isInverse() && !ce.getLoadedPersister().hasOrphanDelete(); } /** * Is this the "inverse" end of a bidirectional one-to-many, or * of a collection with no orphan delete? */ private boolean isInverseOneToManyOrNoOrphanDelete() { CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(this); return ce != null && ce.getLoadedPersister().isInverse() && ( ce.getLoadedPersister().isOneToMany() || !ce.getLoadedPersister().hasOrphanDelete() ); } /** * Queue an addition */ protected final void queueOperation(Object element) { if (operationQueue==null) operationQueue = new ArrayList(10); operationQueue.add(element); dirty = true; //needed so that we remove this collection from the second-level cache } /** * After reading all existing elements from the database, * add the queued elements to the underlying collection. */ protected final void performQueuedOperations() { for ( int i=0; i<operationQueue.size(); i++ ) { ( (DelayedOperation) operationQueue.get(i) ).operate(); } } /** * After flushing, re-init snapshot state. */ public void setSnapshot(Serializable key, String role, Serializable snapshot) { this.key = key; this.role = role; this.storedSnapshot = snapshot; } /** * After flushing, clear any "queued" additions, since the * database state is now synchronized with the memory state. */ public void postAction() { operationQueue=null; cachedSize = -1; clearDirty(); } /** * Not called by Hibernate, but used by non-JDK serialization, * eg. SOAP libraries. */ public AbstractPersistentCollection() {} protected AbstractPersistentCollection(SessionImplementor session) { this.session = session; } /** * return the user-visible collection (or array) instance */ public Object getValue() { return this; } /** * Called just before reading any rows from the JDBC result set */ public void beginRead() { // override on some subclasses initializing = true; } /** * Called after reading all rows from the JDBC result set */ public boolean endRead() { //override on some subclasses return afterInitialize(); } public boolean afterInitialize() { setInitialized(); //do this bit after setting initialized to true or it will recurse if (operationQueue!=null) { performQueuedOperations(); operationQueue=null; cachedSize = -1; return false; } else { return true; } } /** * Initialize the collection, if possible, wrapping any exceptions * in a runtime exception * @param writing currently obsolete * @throws LazyInitializationException if we cannot initialize */ protected final void initialize(boolean writing) { if (!initialized) { if (initializing) { throw new LazyInitializationException("illegal access to loading collection"); } throwLazyInitializationExceptionIfNotConnected(); session.initializeCollection(this, writing); } } private void throwLazyInitializationExceptionIfNotConnected() { if ( !isConnectedToSession() ) { throwLazyInitializationException("no session or session was closed"); } if ( !session.isConnected() ) { throwLazyInitializationException("session is disconnected"); } } private void throwLazyInitializationException(String message) { throw new LazyInitializationException( "failed to lazily initialize a collection" + ( role==null ? "" : " of role: " + role ) + ", " + message ); } protected final void setInitialized() { this.initializing = false; this.initialized = true; } protected final void setDirectlyAccessible(boolean directlyAccessible) { this.directlyAccessible = directlyAccessible; } /** * Could the application possibly have a direct reference to * the underlying collection implementation? */ public boolean isDirectlyAccessible() { return directlyAccessible; } /** * Disassociate this collection from the given session. * @return true if this was currently associated with the given session */ public final boolean unsetSession(SessionImplementor currentSession) { if (currentSession==this.session) { this.session=null; return true; } else { return false; } } /** * Associate the collection with the given session. * @return false if the collection was already associated with the session * @throws HibernateException if the collection was already associated * with another open session */ public final boolean setCurrentSession(SessionImplementor session) throws HibernateException { if (session==this.session) { return false; } else { if ( isConnectedToSession() ) { CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(this); if (ce==null) { throw new HibernateException( "Illegal attempt to associate a collection with two open sessions" ); } else { throw new HibernateException( "Illegal attempt to associate a collection with two open sessions: " + MessageHelper.collectionInfoString( ce.getLoadedPersister(), ce.getLoadedKey(), session.getFactory() ) ); } } else { this.session = session; return true; } } } /** * Do we need to completely recreate this collection when it changes? */ public boolean needsRecreate(CollectionPersister persister) { return false; } /** * To be called internally by the session, forcing * immediate initialization. */ public final void forceInitialization() throws HibernateException { if (!initialized) { if (initializing) { throw new AssertionFailure("force initialize loading collection"); } if (session==null) { throw new HibernateException("collection is not associated with any session"); } if ( !session.isConnected() ) { throw new HibernateException("disconnected session"); } session.initializeCollection(this, false); } } /** * Get the current snapshot from the session */ protected final Serializable getSnapshot() { return session.getPersistenceContext().getSnapshot(this); } /** * Is this instance initialized? */ public final boolean wasInitialized() { return initialized; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -