org.hibernate.engine.CollectionEntry Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hibernate Show documentation
Show all versions of hibernate Show documentation
Relational Persistence for Java
//$Id: CollectionEntry.java 9551 2006-03-04 03:49:55Z [email protected] $
package org.hibernate.engine;
import java.io.Serializable;
import java.io.ObjectOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Collection;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.pretty.MessageHelper;
/**
* We need an entry to tell us all about the current state
* of a collection with respect to its persistent state
*
* @author Gavin King
*/
public final class CollectionEntry implements Serializable {
private static final Log log = LogFactory.getLog(CollectionEntry.class);
//ATTRIBUTES MAINTAINED BETWEEN FLUSH CYCLES
// session-start/post-flush persistent state
private Serializable snapshot;
// allow the CollectionSnapshot to be serialized
private String role;
// "loaded" means the reference that is consistent
// with the current database state
private transient CollectionPersister loadedPersister;
private Serializable loadedKey;
// ATTRIBUTES USED ONLY DURING FLUSH CYCLE
// during flush, we navigate the object graph to
// collections and decide what to do with them
private transient boolean reached;
private transient boolean processed;
private transient boolean doupdate;
private transient boolean doremove;
private transient boolean dorecreate;
// if we instantiate a collection during the flush() process,
// we must ignore it for the rest of the flush()
private transient boolean ignore;
// "current" means the reference that was found during flush()
private transient CollectionPersister currentPersister;
private transient Serializable currentKey;
/**
* For newly wrapped collections, or dereferenced collection wrappers
*/
public CollectionEntry(CollectionPersister persister, PersistentCollection collection) {
// new collections that get found + wrapped
// during flush shouldn't be ignored
ignore = false;
collection.clearDirty(); //a newly wrapped collection is NOT dirty (or we get unnecessary version updates)
snapshot = persister.isMutable() ?
collection.getSnapshot(persister) :
null;
collection.setSnapshot(loadedKey, role, snapshot);
}
/**
* For collections just loaded from the database
*/
public CollectionEntry(
final PersistentCollection collection,
final CollectionPersister loadedPersister,
final Serializable loadedKey,
final boolean ignore
) {
this.ignore=ignore;
//collection.clearDirty()
this.loadedKey = loadedKey;
setLoadedPersister(loadedPersister);
collection.setSnapshot(loadedKey, role, null);
//postInitialize() will be called after initialization
}
/**
* For uninitialized detached collections
*/
public CollectionEntry(CollectionPersister loadedPersister, Serializable loadedKey) {
// detached collection wrappers that get found + reattached
// during flush shouldn't be ignored
ignore = false;
//collection.clearDirty()
this.loadedKey = loadedKey;
setLoadedPersister(loadedPersister);
}
/**
* For initialized detached collections
*/
CollectionEntry(PersistentCollection collection, SessionFactoryImplementor factory)
throws MappingException {
// detached collections that get found + reattached
// during flush shouldn't be ignored
ignore = false;
loadedKey = collection.getKey();
setLoadedPersister( factory.getCollectionPersister( collection.getRole() ) );
snapshot = collection.getStoredSnapshot();
}
/**
* Used from custom serialization.
*
* @see #serialize
* @see #deserialize
*/
private CollectionEntry(
String role,
Serializable snapshot,
Serializable loadedKey,
SessionFactoryImplementor factory) {
this.role = role;
this.snapshot = snapshot;
this.loadedKey = loadedKey;
if ( role != null ) {
afterDeserialize( factory );
}
}
/**
* Determine if the collection is "really" dirty, by checking dirtiness
* of the collection elements, if necessary
*/
private void dirty(PersistentCollection collection) throws HibernateException {
boolean forceDirty = collection.wasInitialized() &&
!collection.isDirty() && //optimization
getLoadedPersister() != null &&
getLoadedPersister().isMutable() && //optimization
( collection.isDirectlyAccessible() || getLoadedPersister().getElementType().isMutable() ) && //optimization
!collection.equalsSnapshot( getLoadedPersister() );
if ( forceDirty ) {
collection.dirty();
}
}
public void preFlush(PersistentCollection collection) throws HibernateException {
boolean nonMutableChange = collection.isDirty() &&
getLoadedPersister()!=null &&
!getLoadedPersister().isMutable();
if (nonMutableChange) {
throw new HibernateException(
"changed an immutable collection instance: " +
MessageHelper.collectionInfoString( getLoadedPersister().getRole(), getLoadedKey() )
);
}
dirty(collection);
if ( log.isDebugEnabled() && collection.isDirty() && getLoadedPersister() != null ) {
log.debug(
"Collection dirty: " +
MessageHelper.collectionInfoString( getLoadedPersister().getRole(), getLoadedKey() )
);
}
setDoupdate(false);
setDoremove(false);
setDorecreate(false);
setReached(false);
setProcessed(false);
}
public void postInitialize(PersistentCollection collection) throws HibernateException {
snapshot = getLoadedPersister().isMutable() ?
collection.getSnapshot( getLoadedPersister() ) :
null;
collection.setSnapshot(loadedKey, role, snapshot);
}
/**
* Called after a successful flush
*/
public void postFlush(PersistentCollection collection) throws HibernateException {
if ( isIgnore() ) {
ignore = false;
}
else if ( !isProcessed() ) {
throw new AssertionFailure( "collection [" + collection.getRole() + "] was not processed by flush()" );
}
collection.setSnapshot(loadedKey, role, snapshot);
}
/**
* Called after execution of an action
*/
public void afterAction(PersistentCollection collection) {
loadedKey = getCurrentKey();
setLoadedPersister( getCurrentPersister() );
boolean resnapshot = collection.wasInitialized() &&
( isDoremove() || isDorecreate() || isDoupdate() );
if ( resnapshot ) {
snapshot = loadedPersister==null || !loadedPersister.isMutable() ?
null :
collection.getSnapshot(loadedPersister); //re-snapshot
}
collection.postAction();
}
public Serializable getKey() {
return getLoadedKey();
}
public String getRole() {
return role;
}
public Serializable getSnapshot() {
return snapshot;
}
private void setLoadedPersister(CollectionPersister persister) {
loadedPersister = persister;
setRole( persister == null ? null : persister.getRole() );
}
void afterDeserialize(SessionFactoryImplementor factory) {
loadedPersister = factory.getCollectionPersister(role);
}
public boolean wasDereferenced() {
return getLoadedKey() == null;
}
public boolean isReached() {
return reached;
}
public void setReached(boolean reached) {
this.reached = reached;
}
public boolean isProcessed() {
return processed;
}
public void setProcessed(boolean processed) {
this.processed = processed;
}
public boolean isDoupdate() {
return doupdate;
}
public void setDoupdate(boolean doupdate) {
this.doupdate = doupdate;
}
public boolean isDoremove() {
return doremove;
}
public void setDoremove(boolean doremove) {
this.doremove = doremove;
}
public boolean isDorecreate() {
return dorecreate;
}
public void setDorecreate(boolean dorecreate) {
this.dorecreate = dorecreate;
}
public boolean isIgnore() {
return ignore;
}
public CollectionPersister getCurrentPersister() {
return currentPersister;
}
public void setCurrentPersister(CollectionPersister currentPersister) {
this.currentPersister = currentPersister;
}
/**
* This is only available late during the flush
* cycle
*/
public Serializable getCurrentKey() {
return currentKey;
}
public void setCurrentKey(Serializable currentKey) {
this.currentKey = currentKey;
}
/**
* This is only available late during the flush cycle
*/
public CollectionPersister getLoadedPersister() {
return loadedPersister;
}
public Serializable getLoadedKey() {
return loadedKey;
}
public void setRole(String role) {
this.role = role;
}
public String toString() {
String result = "CollectionEntry" +
MessageHelper.collectionInfoString( loadedPersister.getRole(), loadedKey );
if (currentPersister!=null) {
result += "->" +
MessageHelper.collectionInfoString( currentPersister.getRole(), currentKey );
}
return result;
}
/**
* Get the collection orphans (entities which were removed from the collection)
*/
public Collection getOrphans(String entityName, PersistentCollection collection)
throws HibernateException {
if (snapshot==null) {
throw new AssertionFailure("no collection snapshot for orphan delete");
}
return collection.getOrphans( snapshot, entityName );
}
public boolean isSnapshotEmpty(PersistentCollection collection) {
//TODO: does this really need to be here?
// does the collection already have
// it's own up-to-date snapshot?
return collection.wasInitialized() &&
( getLoadedPersister()==null || getLoadedPersister().isMutable() ) &&
collection.isSnapshotEmpty( getSnapshot() );
}
/**
* Custom serialization routine used during serialization of a
* Session/PersistenceContext for increased performance.
*
* @param oos The stream to which we should write the serial data.
* @throws java.io.IOException
*/
void serialize(ObjectOutputStream oos) throws IOException {
oos.writeObject( role );
oos.writeObject( snapshot );
oos.writeObject( loadedKey );
}
/**
* Custom deserialization routine used during deserialization of a
* Session/PersistenceContext for increased performance.
*
* @param ois The stream from which to read the entry.
* @param session The session being deserialized.
* @return The deserialized CollectionEntry
* @throws IOException
* @throws ClassNotFoundException
*/
static CollectionEntry deserialize(
ObjectInputStream ois,
SessionImplementor session) throws IOException, ClassNotFoundException {
return new CollectionEntry(
( String ) ois.readObject(),
( Serializable ) ois.readObject(),
( Serializable ) ois.readObject(),
session.getFactory()
);
}
}