package org.hibernate.engine.spi;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Collection;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.collection.internal.AbstractPersistentCollection;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.internal.CoreLogging;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.pretty.MessageHelper;
import org.jboss.logging.Logger;
public final class CollectionEntry implements Serializable {
private static final Logger LOG = CoreLogging.logger( CollectionEntry.class );
private Serializable snapshot;
private String role;
private transient CollectionPersister loadedPersister;
private Serializable loadedKey;
private transient boolean reached;
private transient boolean processed;
private transient boolean doupdate;
private transient boolean doremove;
private transient boolean dorecreate;
private transient boolean ignore;
private transient CollectionPersister currentPersister;
private transient Serializable currentKey;
public CollectionEntry(CollectionPersister persister, PersistentCollection collection) {
ignore = false;
collection.clearDirty();
snapshot = persister.isMutable() ?
collection.getSnapshot(persister) :
null;
collection.setSnapshot(loadedKey, role, snapshot);
}
public CollectionEntry(
final PersistentCollection collection,
final CollectionPersister loadedPersister,
final Serializable loadedKey,
final boolean ignore
) {
this.ignore=ignore;
this.loadedKey = loadedKey;
setLoadedPersister(loadedPersister);
collection.setSnapshot(loadedKey, role, null);
}
public CollectionEntry(CollectionPersister loadedPersister, Serializable loadedKey) {
ignore = false;
this.loadedKey = loadedKey;
setLoadedPersister(loadedPersister);
}
public CollectionEntry(PersistentCollection collection, SessionFactoryImplementor factory) throws MappingException {
ignore = false;
loadedKey = collection.getKey();
setLoadedPersister( factory.getCollectionPersister( collection.getRole() ) );
snapshot = collection.getStoredSnapshot();
}
private CollectionEntry(
String role,
Serializable snapshot,
Serializable loadedKey,
SessionFactoryImplementor factory) {
this.role = role;
this.snapshot = snapshot;
this.loadedKey = loadedKey;
if ( role != null ) {
afterDeserialize( factory );
}
}
private void dirty(PersistentCollection collection) throws HibernateException {
boolean forceDirty = collection.wasInitialized() &&
!collection.isDirty() &&
getLoadedPersister() != null &&
getLoadedPersister().isMutable() &&
( collection.isDirectlyAccessible() || getLoadedPersister().getElementType().isMutable() ) &&
!collection.equalsSnapshot( getLoadedPersister() );
if ( forceDirty ) {
collection.dirty();
}
}
public void preFlush(PersistentCollection collection) throws HibernateException {
if ( loadedKey == null && collection.getKey() != null ) {
loadedKey = collection.getKey();
}
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.debugf( "Collection dirty: %s",
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);
if (getLoadedPersister().getBatchSize() > 1) {
((AbstractPersistentCollection) collection).getSession().getPersistenceContext().getBatchFetchQueue().removeBatchLoadableCollection(this);
}
}
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);
}
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);
}
collection.postAction();
}
public Serializable getKey() {
return getLoadedKey();
}
public String getRole() {
return role;
}
public Serializable getSnapshot() {
return snapshot;
}
private boolean fromMerge;
public void resetStoredSnapshot(PersistentCollection collection, Serializable storedSnapshot) {
LOG.debugf("Reset storedSnapshot to %s for %s", storedSnapshot, this);
if ( fromMerge ) {
return;
}
snapshot = storedSnapshot;
collection.setSnapshot( loadedKey, role, snapshot );
fromMerge = true;
}
private void setLoadedPersister(CollectionPersister persister) {
loadedPersister = persister;
setRole( persister == null ? null : persister.getRole() );
}
void afterDeserialize(SessionFactoryImplementor factory) {
loadedPersister = ( factory == null ? null : 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;
}
public Serializable getCurrentKey() {
return currentKey;
}
public void setCurrentKey(Serializable currentKey) {
this.currentKey = currentKey;
}
public CollectionPersister getLoadedPersister() {
return loadedPersister;
}
public Serializable getLoadedKey() {
return loadedKey;
}
public void setRole(String role) {
this.role = role;
}
@Override
public String toString() {
String result = "CollectionEntry" +
MessageHelper.collectionInfoString( loadedPersister.getRole(), loadedKey );
if ( currentPersister != null ) {
result += "->" +
MessageHelper.collectionInfoString( currentPersister.getRole(), currentKey );
}
return result;
}
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) {
return collection.wasInitialized() &&
( getLoadedPersister()==null || getLoadedPersister().isMutable() ) &&
collection.isSnapshotEmpty( getSnapshot() );
}
public void serialize(ObjectOutputStream oos) throws IOException {
oos.writeObject( role );
oos.writeObject( snapshot );
oos.writeObject( loadedKey );
}
public static CollectionEntry deserialize(
ObjectInputStream ois,
SessionImplementor session) throws IOException, ClassNotFoundException {
return new CollectionEntry(
(String) ois.readObject(),
(Serializable) ois.readObject(),
(Serializable) ois.readObject(),
(session == null ? null : session.getFactory())
);
}
}