All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.collection.AbstractPersistentCollection Maven / Gradle / Ivy

There is a newer version: 7.0.0.Beta1
Show newest version
/*
 * 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.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.EntityEntry;
import org.hibernate.engine.ForeignKeys;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.engine.Status;
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.IdentitySet;
import org.hibernate.util.MarkerObject;

/**
 * Base class implementing {@link 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 size() 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




© 2015 - 2024 Weber Informatics LLC | Privacy Policy