HHH-7457 - Enable loading of collections thats been detached from session

This commit is contained in:
Steve Ebersole 2012-08-07 14:51:13 -05:00
parent a1c9ed7756
commit 467258cffa
2 changed files with 262 additions and 213 deletions

View File

@ -23,20 +23,30 @@
*/ */
package org.hibernate.collection.internal; package org.hibernate.collection.internal;
import javax.naming.NamingException;
import java.io.Serializable; import java.io.Serializable;
import java.util.*; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.LazyInitializationException; import org.hibernate.LazyInitializationException;
import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Configuration;
import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.internal.ForeignKeys; import org.hibernate.engine.internal.ForeignKeys;
import org.hibernate.engine.spi.*; import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.engine.spi.TypedValue;
import org.hibernate.internal.SessionFactoryRegistry; import org.hibernate.internal.SessionFactoryRegistry;
import org.hibernate.internal.util.MarkerObject; 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.EmptyIterator;
import org.hibernate.internal.util.collections.IdentitySet; import org.hibernate.internal.util.collections.IdentitySet;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
@ -44,8 +54,6 @@ import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper; import org.hibernate.pretty.MessageHelper;
import org.hibernate.type.Type; import org.hibernate.type.Type;
import javax.naming.NamingException;
/** /**
* Base class implementing {@link org.hibernate.collection.spi.PersistentCollection} * Base class implementing {@link org.hibernate.collection.spi.PersistentCollection}
* *
@ -60,7 +68,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
private transient boolean initializing; private transient boolean initializing;
private Object owner; private Object owner;
private int cachedSize = -1; private int cachedSize = -1;
private String role; private String role;
private Serializable key; private Serializable key;
// collections detect changes made via their public interface and mark // collections detect changes made via their public interface and mark
@ -74,60 +82,63 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
public final String getRole() { public final String getRole() {
return role; return role;
} }
public final Serializable getKey() { public final Serializable getKey() {
return key; return key;
} }
public final boolean isUnreferenced() { public final boolean isUnreferenced() {
return role==null; return role == null;
} }
public final boolean isDirty() { public final boolean isDirty() {
return dirty; return dirty;
} }
public final void clearDirty() { public final void clearDirty() {
dirty = false; dirty = false;
} }
public final void dirty() { public final void dirty() {
dirty = true; dirty = true;
} }
public final Serializable getStoredSnapshot() { public final Serializable getStoredSnapshot() {
return storedSnapshot; return storedSnapshot;
} }
//Careful: these methods do not initialize the collection. //Careful: these methods do not initialize the collection.
/** /**
* Is the initialized collection empty? * Is the initialized collection empty?
*/ */
public abstract boolean empty(); public abstract boolean empty();
/** /**
* Called by any read-only method of the collection interface * Called by any read-only method of the collection interface
*/ */
protected final void read() { protected final void read() {
initialize(false); initialize( false );
} }
/** /**
* Called by the {@link Collection#size} method * Called by the {@link Collection#size} method
*/ */
@SuppressWarnings( {"JavaDoc"}) @SuppressWarnings({"JavaDoc"})
protected boolean readSize() { protected boolean readSize() {
if (!initialized) { if ( !initialized ) {
if ( cachedSize!=-1 && !hasQueuedOperations() ) { if ( cachedSize != -1 && !hasQueuedOperations() ) {
return true; return true;
} }
else { else {
try { try {
if(specjLazyLoad) { if ( specjLazyLoad ) {
specialSpecjInitialization(false); specialSpecjInitialization( false );
} }
else else {
throwLazyInitializationExceptionIfNotConnected(); throwLazyInitializationExceptionIfNotConnected();
CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(this); }
CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( this );
CollectionPersister persister = entry.getLoadedPersister(); CollectionPersister persister = entry.getLoadedPersister();
if ( persister.isExtraLazy() ) { if ( persister.isExtraLazy() ) {
if ( hasQueuedOperations() ) { if ( hasQueuedOperations() ) {
@ -138,8 +149,9 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
} }
} }
finally { finally {
if(specjLazyLoad) if ( specjLazyLoad ) {
session = null; session = null;
}
} }
} }
} }
@ -148,14 +160,15 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
} }
protected Boolean readIndexExistence(Object index) { protected Boolean readIndexExistence(Object index) {
if (!initialized) { if ( !initialized ) {
try { try {
if(specjLazyLoad) { if ( specjLazyLoad ) {
specialSpecjInitialization(false); specialSpecjInitialization( false );
} }
else else {
throwLazyInitializationExceptionIfNotConnected(); throwLazyInitializationExceptionIfNotConnected();
CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(this); }
CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( this );
CollectionPersister persister = entry.getLoadedPersister(); CollectionPersister persister = entry.getLoadedPersister();
if ( persister.isExtraLazy() ) { if ( persister.isExtraLazy() ) {
if ( hasQueuedOperations() ) { if ( hasQueuedOperations() ) {
@ -165,8 +178,9 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
} }
} }
finally { finally {
if(specjLazyLoad) if ( specjLazyLoad ) {
session = null; session = null;
}
} }
} }
read(); read();
@ -174,14 +188,15 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
} }
protected Boolean readElementExistence(Object element) { protected Boolean readElementExistence(Object element) {
if (!initialized) { if ( !initialized ) {
try { try {
if(specjLazyLoad) { if ( specjLazyLoad ) {
specialSpecjInitialization(false); specialSpecjInitialization( false );
} }
else else {
throwLazyInitializationExceptionIfNotConnected(); throwLazyInitializationExceptionIfNotConnected();
CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(this); }
CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( this );
CollectionPersister persister = entry.getLoadedPersister(); CollectionPersister persister = entry.getLoadedPersister();
if ( persister.isExtraLazy() ) { if ( persister.isExtraLazy() ) {
if ( hasQueuedOperations() ) { if ( hasQueuedOperations() ) {
@ -191,48 +206,49 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
} }
} }
finally { finally {
if(specjLazyLoad) if ( specjLazyLoad ) {
session = null; session = null;
}
} }
} }
read(); read();
return null; return null;
} }
protected static final Object UNKNOWN = new MarkerObject("UNKNOWN"); protected static final Object UNKNOWN = new MarkerObject( "UNKNOWN" );
protected Object readElementByIndex(Object index) { protected Object readElementByIndex(Object index) {
if (!initialized) { if ( !initialized ) {
throwLazyInitializationExceptionIfNotConnected(); throwLazyInitializationExceptionIfNotConnected();
CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(this); CollectionEntry entry = session.getPersistenceContext().getCollectionEntry( this );
CollectionPersister persister = entry.getLoadedPersister(); CollectionPersister persister = entry.getLoadedPersister();
if ( persister.isExtraLazy() ) { if ( persister.isExtraLazy() ) {
if ( hasQueuedOperations() ) { if ( hasQueuedOperations() ) {
session.flush(); session.flush();
} }
return persister.getElementByIndex(entry.getLoadedKey(), index, session, owner); return persister.getElementByIndex( entry.getLoadedKey(), index, session, owner );
} }
} }
read(); read();
return UNKNOWN; return UNKNOWN;
} }
protected int getCachedSize() { protected int getCachedSize() {
return cachedSize; return cachedSize;
} }
private boolean isConnectedToSession() { private boolean isConnectedToSession() {
return session!=null && return session != null &&
session.isOpen() && session.isOpen() &&
session.getPersistenceContext().containsCollection(this); session.getPersistenceContext().containsCollection( this );
} }
/** /**
* Called by any writer method of the collection interface * Called by any writer method of the collection interface
*/ */
protected final void write() { protected final void write() {
initialize(true); initialize( true );
dirty(); dirty();
} }
@ -240,29 +256,31 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
* Is this collection in a state that would allow us to * Is this collection in a state that would allow us to
* "queue" operations? * "queue" operations?
*/ */
@SuppressWarnings( {"JavaDoc"}) @SuppressWarnings({"JavaDoc"})
protected boolean isOperationQueueEnabled() { protected boolean isOperationQueueEnabled() {
return !initialized && return !initialized &&
isConnectedToSession() && isConnectedToSession() &&
isInverseCollection(); isInverseCollection();
} }
/** /**
* Is this collection in a state that would allow us to * Is this collection in a state that would allow us to
* "queue" puts? This is a special case, because of orphan * "queue" puts? This is a special case, because of orphan
* delete. * delete.
*/ */
@SuppressWarnings( {"JavaDoc"}) @SuppressWarnings({"JavaDoc"})
protected boolean isPutQueueEnabled() { protected boolean isPutQueueEnabled() {
return !initialized && return !initialized &&
isConnectedToSession() && isConnectedToSession() &&
isInverseOneToManyOrNoOrphanDelete(); isInverseOneToManyOrNoOrphanDelete();
} }
/** /**
* Is this collection in a state that would allow us to * Is this collection in a state that would allow us to
* "queue" clear? This is a special case, because of orphan * "queue" clear? This is a special case, because of orphan
* delete. * delete.
*/ */
@SuppressWarnings( {"JavaDoc"}) @SuppressWarnings({"JavaDoc"})
protected boolean isClearQueueEnabled() { protected boolean isClearQueueEnabled() {
return !initialized && return !initialized &&
isConnectedToSession() && isConnectedToSession() &&
@ -272,9 +290,9 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
/** /**
* Is this the "inverse" end of a bidirectional association? * Is this the "inverse" end of a bidirectional association?
*/ */
@SuppressWarnings( {"JavaDoc"}) @SuppressWarnings({"JavaDoc"})
private boolean isInverseCollection() { private boolean isInverseCollection() {
CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(this); CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
return ce != null && ce.getLoadedPersister().isInverse(); return ce != null && ce.getLoadedPersister().isInverse();
} }
@ -282,34 +300,34 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
* Is this the "inverse" end of a bidirectional association with * Is this the "inverse" end of a bidirectional association with
* no orphan delete enabled? * no orphan delete enabled?
*/ */
@SuppressWarnings( {"JavaDoc"}) @SuppressWarnings({"JavaDoc"})
private boolean isInverseCollectionNoOrphanDelete() { private boolean isInverseCollectionNoOrphanDelete() {
CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(this); CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
return ce != null && return ce != null &&
ce.getLoadedPersister().isInverse() && ce.getLoadedPersister().isInverse() &&
!ce.getLoadedPersister().hasOrphanDelete(); !ce.getLoadedPersister().hasOrphanDelete();
} }
/** /**
* Is this the "inverse" end of a bidirectional one-to-many, or * Is this the "inverse" end of a bidirectional one-to-many, or
* of a collection with no orphan delete? * of a collection with no orphan delete?
*/ */
@SuppressWarnings( {"JavaDoc"}) @SuppressWarnings({"JavaDoc"})
private boolean isInverseOneToManyOrNoOrphanDelete() { private boolean isInverseOneToManyOrNoOrphanDelete() {
CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(this); CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
return ce != null && ce.getLoadedPersister().isInverse() && ( return ce != null && ce.getLoadedPersister().isInverse() && (
ce.getLoadedPersister().isOneToMany() || ce.getLoadedPersister().isOneToMany() ||
!ce.getLoadedPersister().hasOrphanDelete() !ce.getLoadedPersister().hasOrphanDelete()
); );
} }
/** /**
* Queue an addition * Queue an addition
*/ */
@SuppressWarnings( {"JavaDoc"}) @SuppressWarnings({"JavaDoc"})
protected final void queueOperation(DelayedOperation operation) { protected final void queueOperation(DelayedOperation operation) {
if (operationQueue==null) { if ( operationQueue == null ) {
operationQueue = new ArrayList<DelayedOperation>(10); operationQueue = new ArrayList<DelayedOperation>( 10 );
} }
operationQueue.add( operation ); operationQueue.add( operation );
dirty = true; //needed so that we remove this collection from the second-level cache dirty = true; //needed so that we remove this collection from the second-level cache
@ -339,16 +357,17 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
* database state is now synchronized with the memory state. * database state is now synchronized with the memory state.
*/ */
public void postAction() { public void postAction() {
operationQueue=null; operationQueue = null;
cachedSize = -1; cachedSize = -1;
clearDirty(); clearDirty();
} }
/** /**
* Not called by Hibernate, but used by non-JDK serialization, * Not called by Hibernate, but used by non-JDK serialization,
* eg. SOAP libraries. * eg. SOAP libraries.
*/ */
public AbstractPersistentCollection() {} public AbstractPersistentCollection() {
}
protected AbstractPersistentCollection(SessionImplementor session) { protected AbstractPersistentCollection(SessionImplementor session) {
this.session = session; this.session = session;
@ -376,13 +395,13 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
//override on some subclasses //override on some subclasses
return afterInitialize(); return afterInitialize();
} }
public boolean afterInitialize() { public boolean afterInitialize() {
setInitialized(); setInitialized();
//do this bit after setting initialized to true or it will recurse //do this bit after setting initialized to true or it will recurse
if (operationQueue!=null) { if ( operationQueue != null ) {
performQueuedOperations(); performQueuedOperations();
operationQueue=null; operationQueue = null;
cachedSize = -1; cachedSize = -1;
return false; return false;
} }
@ -394,40 +413,42 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
/** /**
* Initialize the collection, if possible, wrapping any exceptions * Initialize the collection, if possible, wrapping any exceptions
* in a runtime exception * in a runtime exception
*
* @param writing currently obsolete * @param writing currently obsolete
*
* @throws LazyInitializationException if we cannot initialize * @throws LazyInitializationException if we cannot initialize
*/ */
protected final void initialize(boolean writing) { protected final void initialize(boolean writing) {
if (!initialized) { if ( !initialized ) {
if (initializing) { if ( initializing ) {
throw new LazyInitializationException("illegal access to loading collection"); throw new LazyInitializationException( "illegal access to loading collection" );
} }
else if ( specjLazyLoad ) { else if ( specjLazyLoad ) {
specialSpecjInitialization(writing); specialSpecjInitialization( writing );
} }
else if ( session==null ) { else if ( session == null ) {
throw new LazyInitializationException("could not initialize proxy - no Session"); throw new LazyInitializationException( "could not initialize proxy - no Session" );
} }
else if ( !session.isOpen() ) { else if ( !session.isOpen() ) {
throw new LazyInitializationException("could not initialize proxy - the owning Session was closed"); throw new LazyInitializationException( "could not initialize proxy - the owning Session was closed" );
} }
else if ( !session.isConnected() ) { else if ( !session.isConnected() ) {
throw new LazyInitializationException("could not initialize proxy - the owning Session is disconnected"); throw new LazyInitializationException( "could not initialize proxy - the owning Session is disconnected" );
} }
else { else {
throwLazyInitializationExceptionIfNotConnected(); throwLazyInitializationExceptionIfNotConnected();
session.initializeCollection(this, writing); session.initializeCollection( this, writing );
} }
} }
} }
private void throwLazyInitializationExceptionIfNotConnected() { private void throwLazyInitializationExceptionIfNotConnected() {
if ( !isConnectedToSession() ) { if ( !isConnectedToSession() ) {
throwLazyInitializationException("no session or session was closed"); throwLazyInitializationException( "no session or session was closed" );
} }
if ( !session.isConnected() ) { if ( !session.isConnected() ) {
throwLazyInitializationException("session is disconnected"); throwLazyInitializationException( "session is disconnected" );
} }
} }
protected void specialSpecjInitialization(boolean writing) { protected void specialSpecjInitialization(boolean writing) {
@ -437,15 +458,15 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
throwLazyInitializationExceptionIfNotConnected(); throwLazyInitializationExceptionIfNotConnected();
} }
try { try {
SessionFactoryImplementor sf = (SessionFactoryImplementor) SessionFactoryImplementor sf = (SessionFactoryImplementor)
SessionFactoryRegistry.INSTANCE.getSessionFactory( sessionFactoryUuid ); SessionFactoryRegistry.INSTANCE.getSessionFactory( sessionFactoryUuid );
session = (SessionImplementor) sf.openSession(); session = (SessionImplementor) sf.openSession();
CollectionPersister collectionPersister = CollectionPersister collectionPersister =
session.getFactory().getCollectionPersister( this.getRole() ); session.getFactory().getCollectionPersister( this.getRole() );
session.getPersistenceContext() session.getPersistenceContext()
.addUninitializedDetachedCollection( collectionPersister, this ); .addUninitializedDetachedCollection( collectionPersister, this );
session.initializeCollection(this, writing); session.initializeCollection( this, writing );
//CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(this); //CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(this);
//CollectionPersister persister = entry.getLoadedPersister(); //CollectionPersister persister = entry.getLoadedPersister();
@ -453,23 +474,23 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
//session = null; //session = null;
} }
catch( Exception e ) { catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
throw new LazyInitializationException(e.getMessage()); throw new LazyInitializationException( e.getMessage() );
} }
} }
else { else {
session.initializeCollection(this, writing); session.initializeCollection( this, writing );
} }
} }
private void throwLazyInitializationException(String message) { private void throwLazyInitializationException(String message) {
throw new LazyInitializationException( throw new LazyInitializationException(
"failed to lazily initialize a collection" + "failed to lazily initialize a collection" +
( role==null ? "" : " of role: " + role ) + (role == null ? "" : " of role: " + role) +
", " + message ", " + message
); );
} }
protected final void setInitialized() { protected final void setInitialized() {
@ -491,12 +512,13 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
/** /**
* Disassociate this collection from the given session. * Disassociate this collection from the given session.
*
* @return true if this was currently associated with the given session * @return true if this was currently associated with the given session
*/ */
public final boolean unsetSession(SessionImplementor currentSession) { public final boolean unsetSession(SessionImplementor currentSession) {
prepareForPossibleSpecialSpecjInitialization(); prepareForPossibleSpecialSpecjInitialization();
if (currentSession==this.session) { if ( currentSession == this.session ) {
this.session=null; this.session = null;
return true; return true;
} }
else { else {
@ -506,11 +528,15 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
protected void prepareForPossibleSpecialSpecjInitialization() { protected void prepareForPossibleSpecialSpecjInitialization() {
if ( session != null ) { if ( session != null ) {
specjLazyLoad = Boolean.parseBoolean( session.getFactory().getProperties().getProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS)); specjLazyLoad = Boolean.parseBoolean(
session.getFactory()
.getProperties()
.getProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS )
);
if ( specjLazyLoad && sessionFactoryUuid == null) { if ( specjLazyLoad && sessionFactoryUuid == null ) {
try { try {
sessionFactoryUuid = (String) session.getFactory().getReference().get("uuid").getContent(); sessionFactoryUuid = (String) session.getFactory().getReference().get( "uuid" ).getContent();
} }
catch (NamingException e) { catch (NamingException e) {
//not much we can do if this fails... //not much we can do if this fails...
@ -522,31 +548,33 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
/** /**
* Associate the collection with the given session. * Associate the collection with the given session.
*
* @return false if the collection was already associated with the session * @return false if the collection was already associated with the session
*
* @throws HibernateException if the collection was already associated * @throws HibernateException if the collection was already associated
* with another open session * with another open session
*/ */
public final boolean setCurrentSession(SessionImplementor session) throws HibernateException { public final boolean setCurrentSession(SessionImplementor session) throws HibernateException {
if (session==this.session) { if ( session == this.session ) {
return false; return false;
} }
else { else {
if ( isConnectedToSession() ) { if ( isConnectedToSession() ) {
CollectionEntry ce = session.getPersistenceContext().getCollectionEntry(this); CollectionEntry ce = session.getPersistenceContext().getCollectionEntry( this );
if (ce==null) { if ( ce == null ) {
throw new HibernateException( throw new HibernateException(
"Illegal attempt to associate a collection with two open sessions" "Illegal attempt to associate a collection with two open sessions"
); );
} }
else { else {
throw new HibernateException( throw new HibernateException(
"Illegal attempt to associate a collection with two open sessions: " + "Illegal attempt to associate a collection with two open sessions: " +
MessageHelper.collectionInfoString( MessageHelper.collectionInfoString(
ce.getLoadedPersister(), ce.getLoadedPersister(),
ce.getLoadedKey(), ce.getLoadedKey(),
session.getFactory() session.getFactory()
) )
); );
} }
} }
else { else {
@ -562,23 +590,23 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
public boolean needsRecreate(CollectionPersister persister) { public boolean needsRecreate(CollectionPersister persister) {
return false; return false;
} }
/** /**
* To be called internally by the session, forcing * To be called internally by the session, forcing
* immediate initialization. * immediate initialization.
*/ */
public final void forceInitialization() throws HibernateException { public final void forceInitialization() throws HibernateException {
if (!initialized) { if ( !initialized ) {
if (initializing) { if ( initializing ) {
throw new AssertionFailure("force initialize loading collection"); throw new AssertionFailure( "force initialize loading collection" );
} }
if (session==null) { if ( session == null ) {
throw new HibernateException("collection is not associated with any session"); throw new HibernateException( "collection is not associated with any session" );
} }
if ( !session.isConnected() ) { if ( !session.isConnected() ) {
throw new HibernateException("disconnected session"); throw new HibernateException( "disconnected session" );
} }
session.initializeCollection(this, false); session.initializeCollection( this, false );
} }
} }
@ -586,9 +614,9 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
/** /**
* Get the current snapshot from the session * Get the current snapshot from the session
*/ */
@SuppressWarnings( {"JavaDoc"}) @SuppressWarnings({"JavaDoc"})
protected final Serializable getSnapshot() { protected final Serializable getSnapshot() {
return session.getPersistenceContext().getSnapshot(this); return session.getPersistenceContext().getSnapshot( this );
} }
/** /**
@ -597,7 +625,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
public final boolean wasInitialized() { public final boolean wasInitialized() {
return initialized; return initialized;
} }
public boolean isRowUpdatePossible() { public boolean isRowUpdatePossible() {
return true; return true;
} }
@ -606,8 +634,9 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
* Does this instance have any "queued" additions? * Does this instance have any "queued" additions?
*/ */
public final boolean hasQueuedOperations() { public final boolean hasQueuedOperations() {
return operationQueue!=null; return operationQueue != null;
} }
/** /**
* Iterate the "queued" additions * Iterate the "queued" additions
*/ */
@ -615,12 +644,15 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
if ( hasQueuedOperations() ) { if ( hasQueuedOperations() ) {
return new Iterator() { return new Iterator() {
int i = 0; int i = 0;
public Object next() { public Object next() {
return operationQueue.get(i++).getAddedInstance(); return operationQueue.get( i++ ).getAddedInstance();
} }
public boolean hasNext() { public boolean hasNext() {
return i<operationQueue.size(); return i < operationQueue.size();
} }
public void remove() { public void remove() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@ -630,10 +662,11 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
return EmptyIterator.INSTANCE; return EmptyIterator.INSTANCE;
} }
} }
/** /**
* Iterate the "queued" additions * Iterate the "queued" additions
*/ */
@SuppressWarnings( {"unchecked"}) @SuppressWarnings({"unchecked"})
public final Collection getQueuedOrphans(String entityName) { public final Collection getQueuedOrphans(String entityName) {
if ( hasQueuedOperations() ) { if ( hasQueuedOperations() ) {
Collection additions = new ArrayList( operationQueue.size() ); Collection additions = new ArrayList( operationQueue.size() );
@ -653,11 +686,15 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
* Called before inserting rows, to ensure that any surrogate keys * Called before inserting rows, to ensure that any surrogate keys
* are fully generated * are fully generated
*/ */
public void preInsert(CollectionPersister persister) throws HibernateException {} public void preInsert(CollectionPersister persister) throws HibernateException {
}
/** /**
* Called after inserting a row, to fetch the natively generated id * Called after inserting a row, to fetch the natively generated id
*/ */
public void afterRowInsert(CollectionPersister persister, Object entry, int i) throws HibernateException {} public void afterRowInsert(CollectionPersister persister, Object entry, int i) throws HibernateException {
}
/** /**
* get all "orphaned" elements * get all "orphaned" elements
*/ */
@ -666,7 +703,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
/** /**
* Get the current session * Get the current session
*/ */
@SuppressWarnings( {"JavaDoc"}) @SuppressWarnings({"JavaDoc"})
public final SessionImplementor getSession() { public final SessionImplementor getSession() {
return session; return session;
} }
@ -677,6 +714,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
public IteratorProxy(Iterator itr) { public IteratorProxy(Iterator itr) {
this.itr = itr; this.itr = itr;
} }
public boolean hasNext() { public boolean hasNext() {
return itr.hasNext(); return itr.hasNext();
} }
@ -699,10 +737,10 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
this.itr = itr; this.itr = itr;
} }
@SuppressWarnings( {"unchecked"}) @SuppressWarnings({"unchecked"})
public void add(Object o) { public void add(Object o) {
write(); write();
itr.add(o); itr.add( o );
} }
public boolean hasNext() { public boolean hasNext() {
@ -734,10 +772,10 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
itr.remove(); itr.remove();
} }
@SuppressWarnings( {"unchecked"}) @SuppressWarnings({"unchecked"})
public void set(Object o) { public void set(Object o) {
write(); write();
itr.set(o); itr.set( o );
} }
} }
@ -746,19 +784,19 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
protected final Collection set; protected final Collection set;
public SetProxy(Collection set) { public SetProxy(Collection set) {
this.set=set; this.set = set;
} }
@SuppressWarnings( {"unchecked"}) @SuppressWarnings({"unchecked"})
public boolean add(Object o) { public boolean add(Object o) {
write(); write();
return set.add(o); return set.add( o );
} }
@SuppressWarnings( {"unchecked"}) @SuppressWarnings({"unchecked"})
public boolean addAll(Collection c) { public boolean addAll(Collection c) {
write(); write();
return set.addAll(c); return set.addAll( c );
} }
public void clear() { public void clear() {
@ -767,11 +805,11 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
} }
public boolean contains(Object o) { public boolean contains(Object o) {
return set.contains(o); return set.contains( o );
} }
public boolean containsAll(Collection c) { public boolean containsAll(Collection c) {
return set.containsAll(c); return set.containsAll( c );
} }
public boolean isEmpty() { public boolean isEmpty() {
@ -784,17 +822,17 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
public boolean remove(Object o) { public boolean remove(Object o) {
write(); write();
return set.remove(o); return set.remove( o );
} }
public boolean removeAll(Collection c) { public boolean removeAll(Collection c) {
write(); write();
return set.removeAll(c); return set.removeAll( c );
} }
public boolean retainAll(Collection c) { public boolean retainAll(Collection c) {
write(); write();
return set.retainAll(c); return set.retainAll( c );
} }
public int size() { public int size() {
@ -805,9 +843,9 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
return set.toArray(); return set.toArray();
} }
@SuppressWarnings( {"unchecked"}) @SuppressWarnings({"unchecked"})
public Object[] toArray(Object[] array) { public Object[] toArray(Object[] array) {
return set.toArray(array); return set.toArray( array );
} }
} }
@ -820,31 +858,31 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
} }
@Override @Override
@SuppressWarnings( {"unchecked"}) @SuppressWarnings({"unchecked"})
public void add(int index, Object value) { public void add(int index, Object value) {
write(); write();
list.add(index, value); list.add( index, value );
} }
@Override @Override
@SuppressWarnings( {"unchecked"}) @SuppressWarnings({"unchecked"})
public boolean add(Object o) { public boolean add(Object o) {
write(); write();
return list.add(o); return list.add( o );
} }
@Override @Override
@SuppressWarnings( {"unchecked"}) @SuppressWarnings({"unchecked"})
public boolean addAll(Collection c) { public boolean addAll(Collection c) {
write(); write();
return list.addAll(c); return list.addAll( c );
} }
@Override @Override
@SuppressWarnings( {"unchecked"}) @SuppressWarnings({"unchecked"})
public boolean addAll(int i, Collection c) { public boolean addAll(int i, Collection c) {
write(); write();
return list.addAll(i, c); return list.addAll( i, c );
} }
@Override @Override
@ -855,22 +893,22 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
@Override @Override
public boolean contains(Object o) { public boolean contains(Object o) {
return list.contains(o); return list.contains( o );
} }
@Override @Override
public boolean containsAll(Collection c) { public boolean containsAll(Collection c) {
return list.containsAll(c); return list.containsAll( c );
} }
@Override @Override
public Object get(int i) { public Object get(int i) {
return list.get(i); return list.get( i );
} }
@Override @Override
public int indexOf(Object o) { public int indexOf(Object o) {
return list.indexOf(o); return list.indexOf( o );
} }
@Override @Override
@ -885,7 +923,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
@Override @Override
public int lastIndexOf(Object o) { public int lastIndexOf(Object o) {
return list.lastIndexOf(o); return list.lastIndexOf( o );
} }
@Override @Override
@ -895,35 +933,35 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
@Override @Override
public ListIterator listIterator(int i) { public ListIterator listIterator(int i) {
return new ListIteratorProxy( list.listIterator(i) ); return new ListIteratorProxy( list.listIterator( i ) );
} }
@Override @Override
public Object remove(int i) { public Object remove(int i) {
write(); write();
return list.remove(i); return list.remove( i );
} }
@Override @Override
public boolean remove(Object o) { public boolean remove(Object o) {
write(); write();
return list.remove(o); return list.remove( o );
} }
@Override @Override
public boolean removeAll(Collection c) { public boolean removeAll(Collection c) {
write(); write();
return list.removeAll(c); return list.removeAll( c );
} }
@Override @Override
public boolean retainAll(Collection c) { public boolean retainAll(Collection c) {
write(); write();
return list.retainAll(c); return list.retainAll( c );
} }
@Override @Override
@SuppressWarnings( {"unchecked"}) @SuppressWarnings({"unchecked"})
public Object set(int i, Object o) { public Object set(int i, Object o) {
write(); write();
return list.set( i, o ); return list.set( i, o );
@ -936,7 +974,7 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
@Override @Override
public List subList(int i, int j) { public List subList(int i, int j) {
return list.subList(i, j); return list.subList( i, j );
} }
@Override @Override
@ -945,9 +983,9 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
} }
@Override @Override
@SuppressWarnings( {"unchecked"}) @SuppressWarnings({"unchecked"})
public Object[] toArray(Object[] array) { public Object[] toArray(Object[] array) {
return list.toArray(array); return list.toArray( array );
} }
} }
@ -957,27 +995,29 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
*/ */
protected interface DelayedOperation { protected interface DelayedOperation {
public void operate(); public void operate();
public Object getAddedInstance(); public Object getAddedInstance();
public Object getOrphan(); public Object getOrphan();
} }
/** /**
* Given a collection of entity instances that used to * Given a collection of entity instances that used to
* belong to the collection, and a collection of instances * belong to the collection, and a collection of instances
* that currently belong, return a collection of orphans * that currently belong, return a collection of orphans
*/ */
@SuppressWarnings( {"JavaDoc", "unchecked"}) @SuppressWarnings({"JavaDoc", "unchecked"})
protected static Collection getOrphans( protected static Collection getOrphans(
Collection oldElements, Collection oldElements,
Collection currentElements, Collection currentElements,
String entityName, String entityName,
SessionImplementor session) throws HibernateException { SessionImplementor session) throws HibernateException {
// short-circuit(s) // short-circuit(s)
if ( currentElements.size()==0 ) { if ( currentElements.size() == 0 ) {
return oldElements; // no new elements, the old list contains only Orphans return oldElements; // no new elements, the old list contains only Orphans
} }
if ( oldElements.size()==0) { if ( oldElements.size() == 0 ) {
return oldElements; // no old elements, so no Orphans neither return oldElements; // no old elements, so no Orphans neither
} }
@ -1021,19 +1061,19 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
} }
public static void identityRemove( public static void identityRemove(
Collection list, Collection list,
Object object, Object object,
String entityName, String entityName,
SessionImplementor session) throws HibernateException { SessionImplementor session) throws HibernateException {
if ( object!=null && ForeignKeys.isNotTransient(entityName, object, null, session) ) { if ( object != null && ForeignKeys.isNotTransient( entityName, object, null, session ) ) {
final EntityPersister entityPersister = session.getFactory().getEntityPersister( entityName ); final EntityPersister entityPersister = session.getFactory().getEntityPersister( entityName );
Type idType = entityPersister.getIdentifierType(); Type idType = entityPersister.getIdentifierType();
Serializable idOfCurrent = ForeignKeys.getEntityIdentifierIfNotUnsaved(entityName, object, session); Serializable idOfCurrent = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, object, session );
Iterator itr = list.iterator(); Iterator itr = list.iterator();
while ( itr.hasNext() ) { while ( itr.hasNext() ) {
Serializable idOfOld = ForeignKeys.getEntityIdentifierIfNotUnsaved(entityName, itr.next(), session); Serializable idOfOld = ForeignKeys.getEntityIdentifierIfNotUnsaved( entityName, itr.next(), session );
if ( idType.isEqual( idOfCurrent, idOfOld, session.getFactory() ) ) { if ( idType.isEqual( idOfCurrent, idOfOld, session.getFactory() ) ) {
itr.remove(); itr.remove();
break; break;
@ -1042,18 +1082,18 @@ public abstract class AbstractPersistentCollection implements Serializable, Pers
} }
} }
public Object getIdentifier(Object entry, int i) { public Object getIdentifier(Object entry, int i) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public Object getOwner() { public Object getOwner() {
return owner; return owner;
} }
public void setOwner(Object owner) { public void setOwner(Object owner) {
this.owner = owner; this.owner = owner;
} }
} }

View File

@ -56,6 +56,7 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
private String sessionFactoryUuid; private String sessionFactoryUuid;
private boolean specjLazyLoad = false; private boolean specjLazyLoad = false;
/** /**
* For serialization from the non-pojo initializers (HHH-3309) * For serialization from the non-pojo initializers (HHH-3309)
*/ */
@ -110,12 +111,12 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
public final void setSession(SessionImplementor s) throws HibernateException { public final void setSession(SessionImplementor s) throws HibernateException {
if ( s != session ) { if ( s != session ) {
// check for s == null first, since it is least expensive // check for s == null first, since it is least expensive
if ( s == null ){ if ( s == null ) {
unsetSession(); unsetSession();
} }
else if ( isConnectedToSession() ) { else if ( isConnectedToSession() ) {
//TODO: perhaps this should be some other RuntimeException... //TODO: perhaps this should be some other RuntimeException...
throw new HibernateException("illegally attempted to associate a proxy with two open Sessions"); throw new HibernateException( "illegally attempted to associate a proxy with two open Sessions" );
} }
else { else {
// s != null // s != null
@ -123,7 +124,7 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
if ( readOnlyBeforeAttachedToSession == null ) { if ( readOnlyBeforeAttachedToSession == null ) {
// use the default read-only/modifiable setting // use the default read-only/modifiable setting
final EntityPersister persister = s.getFactory().getEntityPersister( entityName ); final EntityPersister persister = s.getFactory().getEntityPersister( entityName );
setReadOnly( s.getPersistenceContext().isDefaultReadOnly() || ! persister.isMutable() ); setReadOnly( s.getPersistenceContext().isDefaultReadOnly() || !persister.isMutable() );
} }
else { else {
// use the read-only/modifiable setting indicated during deserialization // use the read-only/modifiable setting indicated during deserialization
@ -151,21 +152,21 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
@Override @Override
public final void initialize() throws HibernateException { public final void initialize() throws HibernateException {
if (!initialized) { if ( !initialized ) {
if( specjLazyLoad ) { if ( specjLazyLoad ) {
specialSpecjInitialization(); specialSpecjInitialization();
} }
else if ( session==null ) { else if ( session == null ) {
throw new LazyInitializationException("could not initialize proxy - no Session"); throw new LazyInitializationException( "could not initialize proxy - no Session" );
} }
else if ( !session.isOpen() ) { else if ( !session.isOpen() ) {
throw new LazyInitializationException("could not initialize proxy - the owning Session was closed"); throw new LazyInitializationException( "could not initialize proxy - the owning Session was closed" );
} }
else if ( !session.isConnected() ) { else if ( !session.isConnected() ) {
throw new LazyInitializationException("could not initialize proxy - the owning Session is disconnected"); throw new LazyInitializationException( "could not initialize proxy - the owning Session is disconnected" );
} }
else { else {
target = session.immediateLoad(entityName, id); target = session.immediateLoad( entityName, id );
initialized = true; initialized = true;
checkTargetState(); checkTargetState();
} }
@ -179,43 +180,47 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
if ( session == null ) { if ( session == null ) {
//we have a detached collection thats set to null, reattach //we have a detached collection thats set to null, reattach
if ( sessionFactoryUuid == null ) { if ( sessionFactoryUuid == null ) {
throw new LazyInitializationException("could not initialize proxy - no Session"); throw new LazyInitializationException( "could not initialize proxy - no Session" );
} }
try { try {
SessionFactoryImplementor sf = (SessionFactoryImplementor) SessionFactoryImplementor sf = (SessionFactoryImplementor)
SessionFactoryRegistry.INSTANCE.getSessionFactory( sessionFactoryUuid ); SessionFactoryRegistry.INSTANCE.getSessionFactory( sessionFactoryUuid );
session = (SessionImplementor) sf.openSession(); session = (SessionImplementor) sf.openSession();
target = session.immediateLoad( entityName, id ); target = session.immediateLoad( entityName, id );
initialized = true; initialized = true;
checkTargetState(); checkTargetState();
} }
catch( Exception e ) { catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
throw new LazyInitializationException(e.getMessage()); throw new LazyInitializationException( e.getMessage() );
} }
finally { finally {
session = null; session = null;
} }
} }
else if(session.isOpen() && session.isConnected()) { else if ( session.isOpen() && session.isConnected() ) {
target = session.immediateLoad( entityName, id ); target = session.immediateLoad( entityName, id );
initialized = true; initialized = true;
checkTargetState(); checkTargetState();
} }
else { else {
throw new LazyInitializationException("could not initialize proxy - Session was closed or disced"); throw new LazyInitializationException( "could not initialize proxy - Session was closed or disced" );
} }
} }
protected void prepareForPossibleSpecialSpecjInitialization() { protected void prepareForPossibleSpecialSpecjInitialization() {
if ( session != null ) { if ( session != null ) {
specjLazyLoad = specjLazyLoad =
Boolean.parseBoolean( session.getFactory().getProperties().getProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS)); Boolean.parseBoolean(
session.getFactory()
.getProperties()
.getProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS )
);
if ( specjLazyLoad && sessionFactoryUuid == null) { if ( specjLazyLoad && sessionFactoryUuid == null ) {
try { try {
sessionFactoryUuid = (String) session.getFactory().getReference().get("uuid").getContent(); sessionFactoryUuid = (String) session.getFactory().getReference().get( "uuid" ).getContent();
} }
catch (NamingException e) { catch (NamingException e) {
//not much we can do if this fails... //not much we can do if this fails...
@ -264,7 +269,7 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
@Override @Override
public final Object getImplementation(SessionImplementor s) throws HibernateException { public final Object getImplementation(SessionImplementor s) throws HibernateException {
final EntityKey entityKey = generateEntityKeyOrNull( getIdentifier(), s, getEntityName() ); final EntityKey entityKey = generateEntityKeyOrNull( getIdentifier(), s, getEntityName() );
return ( entityKey == null ? null : s.getPersistenceContext().getEntity( entityKey ) ); return (entityKey == null ? null : s.getPersistenceContext().getEntity( entityKey ));
} }
/** /**
@ -280,17 +285,19 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
@Override @Override
public final boolean isReadOnlySettingAvailable() { public final boolean isReadOnlySettingAvailable() {
return ( session != null && ! session.isClosed() ); return (session != null && !session.isClosed());
} }
private void errorIfReadOnlySettingNotAvailable() { private void errorIfReadOnlySettingNotAvailable() {
if ( session == null ) { if ( session == null ) {
throw new TransientObjectException( throw new TransientObjectException(
"Proxy is detached (i.e, session is null). The read-only/modifiable setting is only accessible when the proxy is associated with an open session." ); "Proxy is detached (i.e, session is null). The read-only/modifiable setting is only accessible when the proxy is associated with an open session."
);
} }
if ( session.isClosed() ) { if ( session.isClosed() ) {
throw new SessionException( throw new SessionException(
"Session is closed. The read-only/modifiable setting is only accessible when the proxy is associated with an open session." ); "Session is closed. The read-only/modifiable setting is only accessible when the proxy is associated with an open session."
);
} }
} }
@ -306,8 +313,8 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
// only update if readOnly is different from current setting // only update if readOnly is different from current setting
if ( this.readOnly != readOnly ) { if ( this.readOnly != readOnly ) {
final EntityPersister persister = session.getFactory().getEntityPersister( entityName ); final EntityPersister persister = session.getFactory().getEntityPersister( entityName );
if ( ! persister.isMutable() && ! readOnly ) { if ( !persister.isMutable() && !readOnly ) {
throw new IllegalStateException( "cannot make proxies for immutable entities modifiable"); throw new IllegalStateException( "cannot make proxies for immutable entities modifiable" );
} }
this.readOnly = readOnly; this.readOnly = readOnly;
if ( initialized ) { if ( initialized ) {
@ -322,13 +329,14 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
/** /**
* Get the read-only/modifiable setting that should be put in affect when it is * Get the read-only/modifiable setting that should be put in affect when it is
* attached to a session. * attached to a session.
* * <p/>
* This method should only be called during serialization when read-only/modifiable setting * This method should only be called during serialization when read-only/modifiable setting
* is not available (i.e., isReadOnlySettingAvailable() == false) * is not available (i.e., isReadOnlySettingAvailable() == false)
* *
* @return null, if the default setting should be used; * @return null, if the default setting should be used;
* true, for read-only; * true, for read-only;
* false, for modifiable * false, for modifiable
*
* @throws IllegalStateException if isReadOnlySettingAvailable() == true * @throws IllegalStateException if isReadOnlySettingAvailable() == true
*/ */
protected final Boolean isReadOnlyBeforeAttachedToSession() { protected final Boolean isReadOnlyBeforeAttachedToSession() {
@ -343,12 +351,13 @@ public abstract class AbstractLazyInitializer implements LazyInitializer {
/** /**
* Set the read-only/modifiable setting that should be put in affect when it is * Set the read-only/modifiable setting that should be put in affect when it is
* attached to a session. * attached to a session.
* * <p/>
* This method should only be called during deserialization, before associating * This method should only be called during deserialization, before associating
* the proxy with a session. * the proxy with a session.
* *
* @param readOnlyBeforeAttachedToSession, the read-only/modifiable setting to use when * @param readOnlyBeforeAttachedToSession, the read-only/modifiable setting to use when
* associated with a session; null indicates that the default should be used. * associated with a session; null indicates that the default should be used.
*
* @throws IllegalStateException if isReadOnlySettingAvailable() == true * @throws IllegalStateException if isReadOnlySettingAvailable() == true
*/ */
/* package-private */ /* package-private */