FileDocCategorySizeDatePackage
AbstractPersistentCollection.javaAPI DocHibernate 3.2.522524Mon Mar 19 14:43:46 GMT 2007org.hibernate.collection

AbstractPersistentCollection

public abstract class AbstractPersistentCollection extends Object implements PersistentCollection, Serializable
Base class implementing PersistentCollection
see
PersistentCollection
author
Gavin King

Fields Summary
private transient org.hibernate.engine.SessionImplementor
session
private boolean
initialized
private transient List
operationQueue
private transient boolean
directlyAccessible
private transient boolean
initializing
private Object
owner
private int
cachedSize
private String
role
private Serializable
key
private boolean
dirty
private Serializable
storedSnapshot
protected static final Object
UNKNOWN
Constructors Summary
public AbstractPersistentCollection()
Not called by Hibernate, but used by non-JDK serialization, eg. SOAP libraries.

protected AbstractPersistentCollection(org.hibernate.engine.SessionImplementor session)

		this.session = session;
	
Methods Summary
public booleanafterInitialize()

		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;
		}
	
public voidafterRowInsert(org.hibernate.persister.collection.CollectionPersister persister, java.lang.Object entry, int i)
Called after inserting a row, to fetch the natively generated id

public voidbeginRead()
Called just before reading any rows from the JDBC result set

		// override on some subclasses
		initializing = true;
	
public final voidclearDirty()

		dirty = false;
	
public final voiddirty()

		dirty = true;
	
public abstract booleanempty()
Is the initialized collection empty?

public booleanendRead()
Called after reading all rows from the JDBC result set

		//override on some subclasses
		return afterInitialize();
	
public final voidforceInitialization()
To be called internally by the session, forcing immediate initialization.

		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);
		}
	
protected intgetCachedSize()

		return cachedSize;
	
public java.lang.ObjectgetIdentifier(java.lang.Object entry, int i)

		throw new UnsupportedOperationException();
	
public final java.io.SerializablegetKey()

		return key;
	
public abstract java.util.CollectiongetOrphans(java.io.Serializable snapshot, java.lang.String entityName)
get all "orphaned" elements

protected static java.util.CollectiongetOrphans(java.util.Collection oldElements, java.util.Collection currentElements, java.lang.String entityName, org.hibernate.engine.SessionImplementor session)
Given a collection of entity instances that used to belong to the collection, and a collection of instances that currently belong, return a collection of orphans


		// short-circuit(s)
		if ( currentElements.size()==0 ) return oldElements; // no new elements, the old list contains only Orphans
		if ( oldElements.size()==0) return oldElements; // no old elements, so no Orphans neither
		
		Type idType = session.getFactory().getEntityPersister(entityName).getIdentifierType();

		// create the collection holding the Orphans
		Collection res = new ArrayList();

		// collect EntityIdentifier(s) of the *current* elements - add them into a HashSet for fast access
		java.util.Set currentIds = new HashSet();
		for ( Iterator it=currentElements.iterator(); it.hasNext(); ) {
			Object current = it.next();
			if ( current!=null && ForeignKeys.isNotTransient(entityName, current, null, session) ) {
				Serializable currentId = ForeignKeys.getEntityIdentifierIfNotUnsaved(entityName, current, session);
				currentIds.add( new TypedValue( idType, currentId, session.getEntityMode() ) );
			}
		}

		// iterate over the *old* list
		for ( Iterator it=oldElements.iterator(); it.hasNext(); ) {
			Object old = it.next();
			Serializable oldId = ForeignKeys.getEntityIdentifierIfNotUnsaved(entityName, old, session);
			if ( !currentIds.contains( new TypedValue( idType, oldId, session.getEntityMode() ) ) ) {
				res.add(old);
			}
		}

		return res;
	
public java.lang.ObjectgetOwner()

		return owner;
	
public final java.util.CollectiongetQueuedOrphans(java.lang.String entityName)
Iterate the "queued" additions

		if ( hasQueuedOperations() ) {
			Collection additions = new ArrayList( operationQueue.size() );
			Collection removals = new ArrayList( operationQueue.size() );
			for ( int i = 0; i < operationQueue.size(); i++ ) {
				DelayedOperation op = (DelayedOperation) operationQueue.get(i);
				additions.add( op.getAddedInstance() );
				removals.add( op.getOrphan() );
			}
			return getOrphans(removals, additions, entityName, session);
		}
		else {
			return CollectionHelper.EMPTY_COLLECTION;
		}
	
public final java.lang.StringgetRole()


	    
		return role;
	
public final org.hibernate.engine.SessionImplementorgetSession()
Get the current session

		return session;
	
protected final java.io.SerializablegetSnapshot()
Get the current snapshot from the session

		return session.getPersistenceContext().getSnapshot(this);
	
public final java.io.SerializablegetStoredSnapshot()

		return storedSnapshot;
	
public java.lang.ObjectgetValue()
return the user-visible collection (or array) instance

		return this;
	
public final booleanhasQueuedOperations()
Does this instance have any "queued" additions?

		return operationQueue!=null;
	
static voididentityRemove(java.util.Collection list, java.lang.Object object, java.lang.String entityName, org.hibernate.engine.SessionImplementor session)


		if ( object!=null && ForeignKeys.isNotTransient(entityName, object, null, session) ) {
			
			Type idType = session.getFactory().getEntityPersister(entityName).getIdentifierType();

			Serializable idOfCurrent = ForeignKeys.getEntityIdentifierIfNotUnsaved(entityName, object, session);
			Iterator iter = list.iterator();
			while ( iter.hasNext() ) {
				Serializable idOfOld = ForeignKeys.getEntityIdentifierIfNotUnsaved(entityName, iter.next(), session);
				if ( idType.isEqual( idOfCurrent, idOfOld, session.getEntityMode(), session.getFactory() ) ) {
					iter.remove();
					break;
				}
			}

		}
	
protected final voidinitialize(boolean writing)
Initialize the collection, if possible, wrapping any exceptions in a runtime exception

param
writing currently obsolete
throws
LazyInitializationException if we cannot initialize

		if (!initialized) {
			if (initializing) {
				throw new LazyInitializationException("illegal access to loading collection");
			}
			throwLazyInitializationExceptionIfNotConnected();
			session.initializeCollection(this, writing);
		}
	
protected booleanisClearQueueEnabled()
Is this collection in a state that would allow us to "queue" clear? This is a special case, because of orphan delete.

		return !initialized &&
				isConnectedToSession() &&
				isInverseCollectionNoOrphanDelete();
	
private final booleanisConnectedToSession()
Is the collection currently connected to an open session?

		return session!=null && 
				session.isOpen() &&
				session.getPersistenceContext().containsCollection(this);
	
public booleanisDirectlyAccessible()
Could the application possibly have a direct reference to the underlying collection implementation?

		return directlyAccessible;
	
public final booleanisDirty()

		return dirty;
	
private booleanisInverseCollection()
Is this the "inverse" end of a bidirectional association?

		CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(this);
		return ce != null && ce.getLoadedPersister().isInverse();
	
private booleanisInverseCollectionNoOrphanDelete()
Is this the "inverse" end of a bidirectional association with no orphan delete enabled?

		CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(this);
		return ce != null && 
				ce.getLoadedPersister().isInverse() &&
				!ce.getLoadedPersister().hasOrphanDelete();
	
private booleanisInverseOneToManyOrNoOrphanDelete()
Is this the "inverse" end of a bidirectional one-to-many, or of a collection with no orphan delete?

		CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(this);
		return ce != null && ce.getLoadedPersister().isInverse() && (
				ce.getLoadedPersister().isOneToMany() || 
				!ce.getLoadedPersister().hasOrphanDelete() 
			);
	
protected booleanisOperationQueueEnabled()
Is this collection in a state that would allow us to "queue" operations?

		return !initialized &&
				isConnectedToSession() &&
				isInverseCollection();
	
protected booleanisPutQueueEnabled()
Is this collection in a state that would allow us to "queue" puts? This is a special case, because of orphan delete.

		return !initialized &&
				isConnectedToSession() &&
				isInverseOneToManyOrNoOrphanDelete();
	
public booleanisRowUpdatePossible()

		return true;
	
public final booleanisUnreferenced()

		return role==null;
	
public booleanneedsRecreate(org.hibernate.persister.collection.CollectionPersister persister)
Do we need to completely recreate this collection when it changes?

		return false;
	
protected final voidperformQueuedOperations()
After reading all existing elements from the database, add the queued elements to the underlying collection.

		for ( int i=0; i<operationQueue.size(); i++ ) {
			( (DelayedOperation) operationQueue.get(i) ).operate();
		}
	
public voidpostAction()
After flushing, clear any "queued" additions, since the database state is now synchronized with the memory state.

		operationQueue=null;
		cachedSize = -1;
		clearDirty();
	
public voidpreInsert(org.hibernate.persister.collection.CollectionPersister persister)
Called before inserting rows, to ensure that any surrogate keys are fully generated

protected final voidqueueOperation(java.lang.Object element)
Queue an addition

		if (operationQueue==null) operationQueue = new ArrayList(10);
		operationQueue.add(element);
		dirty = true; //needed so that we remove this collection from the second-level cache
	
public final java.util.IteratorqueuedAdditionIterator()
Iterate the "queued" additions

		if ( hasQueuedOperations() ) {
			return new Iterator() {
				int i = 0;
				public Object next() {
					return ( (DelayedOperation) operationQueue.get(i++) ).getAddedInstance();
				}
				public boolean hasNext() {
					return i<operationQueue.size();
				}
				public void remove() {
					throw new UnsupportedOperationException();
				}
			};
		}
		else {
			return EmptyIterator.INSTANCE;
		}
	
protected final voidread()
Called by any read-only method of the collection interface

		initialize(false);
	
protected java.lang.ObjectreadElementByIndex(java.lang.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 java.lang.BooleanreadElementExistence(java.lang.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 java.lang.BooleanreadIndexExistence(java.lang.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 booleanreadSize()
Called by the size() method

		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;
	
public final booleansetCurrentSession(org.hibernate.engine.SessionImplementor session)
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

		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;
			}
		}
	
protected final voidsetDirectlyAccessible(boolean directlyAccessible)

		this.directlyAccessible = directlyAccessible;
	
protected final voidsetInitialized()

		this.initializing = false;
		this.initialized = true;
	
public voidsetOwner(java.lang.Object owner)

		this.owner = owner;
	
public voidsetSnapshot(java.io.Serializable key, java.lang.String role, java.io.Serializable snapshot)
After flushing, re-init snapshot state.

		this.key = key;
		this.role = role;
		this.storedSnapshot = snapshot;
	
private voidthrowLazyInitializationException(java.lang.String message)

		throw new LazyInitializationException(
				"failed to lazily initialize a collection" + 
				( role==null ?  "" : " of role: " + role ) + 
				", " + message
			);
	
private voidthrowLazyInitializationExceptionIfNotConnected()

		if ( !isConnectedToSession() )  {
			throwLazyInitializationException("no session or session was closed");
		}
		if ( !session.isConnected() ) {
            throwLazyInitializationException("session is disconnected");
		}		
	
public final booleanunsetSession(org.hibernate.engine.SessionImplementor currentSession)
Disassociate this collection from the given session.

return
true if this was currently associated with the given session

		if (currentSession==this.session) {
			this.session=null;
			return true;
		}
		else {
			return false;
		}
	
public final booleanwasInitialized()
Is this instance initialized?

		return initialized;
	
protected final voidwrite()
Called by any writer method of the collection interface

		initialize(true);
		dirty();