alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Hibernate example source code file (AbstractPersistentCollection.java)

This example Hibernate source code file (AbstractPersistentCollection.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Hibernate tags/keywords

collection, collectionentry, hibernateexception, io, iterator, javadoc, object, object, override, override, serializable, serializable, string, suppresswarnings, suppresswarnings, util

The Hibernate AbstractPersistentCollection.java source code

/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * Copyright (c) 2008-2011, Red Hat Inc. 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 Inc.
 *
 * 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.collection.internal;

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.collection.spi.PersistentCollection;
import org.hibernate.engine.internal.ForeignKeys;
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.internal.util.MarkerObject;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.internal.util.collections.EmptyIterator;
import org.hibernate.internal.util.collections.IdentitySet;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.type.Type;

/**
 * Base class implementing {@link org.hibernate.collection.spi.PersistentCollection}
 *
 * @author Gavin King
 */
public abstract class AbstractPersistentCollection implements Serializable, PersistentCollection {

	private transient SessionImplementor session;
	private boolean initialized;
	private transient List<DelayedOperation> 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 {@link Collection#size} method
	 */
	@SuppressWarnings( {"JavaDoc"})
	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 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 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;
	}
	
	private 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?
	 */
	@SuppressWarnings( {"JavaDoc"})
	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.
	 */
	@SuppressWarnings( {"JavaDoc"})
	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.
	 */
	@SuppressWarnings( {"JavaDoc"})
	protected boolean isClearQueueEnabled() {
		return !initialized &&
				isConnectedToSession() &&
				isInverseCollectionNoOrphanDelete();
	}

	/**
	 * Is this the "inverse" end of a bidirectional association?
	 */
	@SuppressWarnings( {"JavaDoc"})
	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?
	 */
	@SuppressWarnings( {"JavaDoc"})
	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?
	 */
	@SuppressWarnings( {"JavaDoc"})
	private boolean isInverseOneToManyOrNoOrphanDelete() {
		CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(this);
		return ce != null && ce.getLoadedPersister().isInverse() && (
				ce.getLoadedPersister().isOneToMany() || 
				!ce.getLoadedPersister().hasOrphanDelete() 
			);
	}

	/**
	 * Queue an addition
	 */
	@SuppressWarnings( {"JavaDoc"})
	protected final void queueOperation(DelayedOperation operation) {
		if (operationQueue==null) {
			operationQueue = new ArrayList<DelayedOperation>(10);
		}
		operationQueue.add( operation );
		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 ( DelayedOperation operation : operationQueue ) {
			operation.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
	 */
	@SuppressWarnings( {"JavaDoc"})
	protected final Serializable getSnapshot() {
		return session.getPersistenceContext().getSnapshot(this);
	}

	/**
	 * Is this instance initialized?
	 */
	public final boolean wasInitialized() {
		return initialized;
	}
	
	public boolean isRowUpdatePossible() {
		return true;
	}

	/**
	 * Does this instance have any "queued" additions?
	 */
	public final boolean hasQueuedOperations() {
		return operationQueue!=null;
	}
	/**
	 * Iterate the "queued" additions
	 */
	public final Iterator queuedAdditionIterator() {
		if ( hasQueuedOperations() ) {
			return new Iterator() {
				int i = 0;
				public Object next() {
					return operationQueue.get(i++).getAddedInstance();
				}
				public boolean hasNext() {
					return i<operationQueue.size();
				}
				public void remove() {
					throw new UnsupportedOperationException();
				}
			};
		}
		else {
			return EmptyIterator.INSTANCE;
		}
	}
	/**
	 * Iterate the "queued" additions
	 */
	@SuppressWarnings( {"unchecked"})
	public final Collection getQueuedOrphans(String entityName) {
		if ( hasQueuedOperations() ) {
			Collection additions = new ArrayList( operationQueue.size() );
			Collection removals = new ArrayList( operationQueue.size() );
			for ( DelayedOperation operation : operationQueue ) {
				additions.add( operation.getAddedInstance() );
				removals.add( operation.getOrphan() );
			}
			return getOrphans( removals, additions, entityName, session );
		}
		else {
			return CollectionHelper.EMPTY_COLLECTION;
		}
	}

	/**
	 * Called before inserting rows, to ensure that any surrogate keys
	 * are fully generated
	 */
	public void preInsert(CollectionPersister persister) throws HibernateException {}
	/**
	 * Called after inserting a row, to fetch the natively generated id
	 */
	public void afterRowInsert(CollectionPersister persister, Object entry, int i) throws HibernateException {}
	/**
	 * get all "orphaned" elements
	 */
	public abstract Collection getOrphans(Serializable snapshot, String entityName) throws HibernateException;

	/**
	 * Get the current session
	 */
	@SuppressWarnings( {"JavaDoc"})
	public final SessionImplementor getSession() {
		return session;
	}

	protected final class IteratorProxy implements Iterator {
		protected final Iterator itr;

		public IteratorProxy(Iterator itr) {
			this.itr = itr;
		}
		public boolean hasNext() {
			return itr.hasNext();
		}

		public Object next() {
			return itr.next();
		}

		public void remove() {
			write();
			itr.remove();
		}

	}

	protected final class ListIteratorProxy implements ListIterator {
		protected final ListIterator itr;

		public ListIteratorProxy(ListIterator itr) {
			this.itr = itr;
		}

		@SuppressWarnings( {"unchecked"})
		public void add(Object o) {
			write();
			itr.add(o);
		}

		public boolean hasNext() {
			return itr.hasNext();
		}

		public boolean hasPrevious() {
			return itr.hasPrevious();
		}

		public Object next() {
			return itr.next();
		}

		public int nextIndex() {
			return itr.nextIndex();
		}

		public Object previous() {
			return itr.previous();
		}

		public int previousIndex() {
			return itr.previousIndex();
		}

		public void remove() {
			write();
			itr.remove();
		}

		@SuppressWarnings( {"unchecked"})
		public void set(Object o) {
			write();
			itr.set(o);
		}

	}

	protected class SetProxy implements java.util.Set {
		protected final Collection set;

		public SetProxy(Collection set) {
			this.set=set;
		}

		@SuppressWarnings( {"unchecked"})
		public boolean add(Object o) {
			write();
			return set.add(o);
		}

		@SuppressWarnings( {"unchecked"})
		public boolean addAll(Collection c) {
			write();
			return set.addAll(c);
		}

		public void clear() {
			write();
			set.clear();
		}

		public boolean contains(Object o) {
			return set.contains(o);
		}

		public boolean containsAll(Collection c) {
			return set.containsAll(c);
		}

		public boolean isEmpty() {
			return set.isEmpty();
		}

		public Iterator iterator() {
			return new IteratorProxy( set.iterator() );
		}

		public boolean remove(Object o) {
			write();
			return set.remove(o);
		}

		public boolean removeAll(Collection c) {
			write();
			return set.removeAll(c);
		}

		public boolean retainAll(Collection c) {
			write();
			return set.retainAll(c);
		}

		public int size() {
			return set.size();
		}

		public Object[] toArray() {
			return set.toArray();
		}

		@SuppressWarnings( {"unchecked"})
		public Object[] toArray(Object[] array) {
			return set.toArray(array);
		}

	}

	protected final class ListProxy implements java.util.List {
		protected final List list;

		public ListProxy(List list) {
			this.list = list;
		}

		@Override
		@SuppressWarnings( {"unchecked"})
		public void add(int index, Object value) {
			write();
			list.add(index, value);
		}

		@Override
		@SuppressWarnings( {"unchecked"})
		public boolean add(Object o) {
			write();
			return list.add(o);
		}

		@Override
		@SuppressWarnings( {"unchecked"})
		public boolean addAll(Collection c) {
			write();
			return list.addAll(c);
		}

		@Override
		@SuppressWarnings( {"unchecked"})
		public boolean addAll(int i, Collection c) {
			write();
			return list.addAll(i, c);
		}

		@Override
		public void clear() {
			write();
			list.clear();
		}

		@Override
		public boolean contains(Object o) {
			return list.contains(o);
		}

		@Override
		public boolean containsAll(Collection c) {
			return list.containsAll(c);
		}

		@Override
		public Object get(int i) {
			return list.get(i);
		}

		@Override
		public int indexOf(Object o) {
			return list.indexOf(o);
		}

		@Override
		public boolean isEmpty() {
			return list.isEmpty();
		}

		@Override
		public Iterator iterator() {
			return new IteratorProxy( list.iterator() );
		}

		@Override
		public int lastIndexOf(Object o) {
			return list.lastIndexOf(o);
		}

		@Override
		public ListIterator listIterator() {
			return new ListIteratorProxy( list.listIterator() );
		}

		@Override
		public ListIterator listIterator(int i) {
			return new ListIteratorProxy( list.listIterator(i) );
		}

		@Override
		public Object remove(int i) {
			write();
			return list.remove(i);
		}

		@Override
		public boolean remove(Object o) {
			write();
			return list.remove(o);
		}

		@Override
		public boolean removeAll(Collection c) {
			write();
			return list.removeAll(c);
		}

		@Override
		public boolean retainAll(Collection c) {
			write();
			return list.retainAll(c);
		}

		@Override
		@SuppressWarnings( {"unchecked"})
		public Object set(int i, Object o) {
			write();
			return list.set( i, o );
		}

		@Override
		public int size() {
			return list.size();
		}

		@Override
		public List subList(int i, int j) {
			return list.subList(i, j);
		}

		@Override
		public Object[] toArray() {
			return list.toArray();
		}

		@Override
		@SuppressWarnings( {"unchecked"})
		public Object[] toArray(Object[] array) {
			return list.toArray(array);
		}

	}

	/**
	 * Contract for operations which are part of a collection's operation queue.
	 */
	protected interface DelayedOperation {
		public void operate();
		public Object getAddedInstance();
		public Object getOrphan();
	}
	
	/**
	 * 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
	 */
	@SuppressWarnings( {"JavaDoc", "unchecked"})
	protected static Collection getOrphans(
			Collection oldElements, 
			Collection currentElements, 
			String entityName, 
			SessionImplementor session) throws HibernateException {

		// 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
		}

		final EntityPersister entityPersister = session.getFactory().getEntityPersister( entityName );
		final Type idType = entityPersister.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();
		java.util.Set currentSaving = new IdentitySet();
		for ( Object current : currentElements ) {
			if ( current != null && ForeignKeys.isNotTransient( entityName, current, null, session ) ) {
				EntityEntry ee = session.getPersistenceContext().getEntry( current );
				if ( ee != null && ee.getStatus() == Status.SAVING ) {
					currentSaving.add( current );
				}
				else {
					Serializable currentId = ForeignKeys.getEntityIdentifierIfNotUnsaved(
							entityName,
							current,
							session
					);
					currentIds.add( new TypedValue( idType, currentId, entityPersister.getEntityMode() ) );
				}
			}
		}

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

		return res;
	}

	public static void identityRemove(
			Collection list, 
			Object object, 
			String entityName, 
			SessionImplementor session) throws HibernateException {

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

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

		}
	}
	
	public Object getIdentifier(Object entry, int i) {
		throw new UnsupportedOperationException();
	}
	
	public Object getOwner() {
		return owner;
	}
	
	public void setOwner(Object owner) {
		this.owner = owner;
	}
	
}

Other Hibernate examples (source code examples)

Here is a short list of links related to this Hibernate AbstractPersistentCollection.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.