package org.hibernate.engine.loading.internal;
import java.io.Serializable;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.hibernate.CacheMode;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.cache.spi.CacheKey;
import org.hibernate.cache.spi.entry.CollectionCacheEntry;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
public class CollectionLoadContext {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( CollectionLoadContext.class );
private final LoadContexts loadContexts;
private final ResultSet resultSet;
private Set<CollectionKey> localLoadingCollectionKeys = new HashSet<CollectionKey>();
public CollectionLoadContext(LoadContexts loadContexts, ResultSet resultSet) {
this.loadContexts = loadContexts;
this.resultSet = resultSet;
}
public ResultSet getResultSet() {
return resultSet;
}
public LoadContexts getLoadContext() {
return loadContexts;
}
public PersistentCollection getLoadingCollection(final CollectionPersister persister, final Serializable key) {
final EntityMode em = persister.getOwnerEntityPersister().getEntityMetamodel().getEntityMode();
final CollectionKey collectionKey = new CollectionKey( persister, key, em );
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Starting attempt to find loading collection [{0}]",
MessageHelper.collectionInfoString( persister.getRole(), key ) );
}
final LoadingCollectionEntry loadingCollectionEntry = loadContexts.locateLoadingCollectionEntry( collectionKey );
if ( loadingCollectionEntry == null ) {
PersistentCollection collection = loadContexts.getPersistenceContext().getCollection( collectionKey );
if ( collection != null ) {
if ( collection.wasInitialized() ) {
LOG.trace( "Collection already initialized; ignoring" );
return null;
}
LOG.trace( "Collection not yet initialized; initializing" );
}
else {
final Object owner = loadContexts.getPersistenceContext().getCollectionOwner( key, persister );
final boolean newlySavedEntity = owner != null
&& loadContexts.getPersistenceContext().getEntry( owner ).getStatus() != Status.LOADING;
if ( newlySavedEntity ) {
LOG.trace( "Owning entity already loaded; ignoring" );
return null;
}
LOG.tracev( "Instantiating new collection [key={0}, rs={1}]", key, resultSet );
collection = persister.getCollectionType().instantiate(
loadContexts.getPersistenceContext().getSession(), persister, key );
}
collection.beforeInitialize( persister, -1 );
collection.beginRead();
localLoadingCollectionKeys.add( collectionKey );
loadContexts.registerLoadingCollectionXRef( collectionKey, new LoadingCollectionEntry( resultSet, persister, key, collection ) );
return collection;
}
if ( loadingCollectionEntry.getResultSet() == resultSet ) {
LOG.trace( "Found loading collection bound to current result set processing; reading row" );
return loadingCollectionEntry.getCollection();
}
LOG.trace( "Collection is already being initialized; ignoring row" );
return null;
}
public void endLoadingCollections(CollectionPersister persister) {
final SessionImplementor session = getLoadContext().getPersistenceContext().getSession();
if ( !loadContexts.hasLoadingCollectionEntries()
&& localLoadingCollectionKeys.isEmpty() ) {
return;
}
List<LoadingCollectionEntry> matches = null;
final Iterator itr = localLoadingCollectionKeys.iterator();
while ( itr.hasNext() ) {
final CollectionKey collectionKey = (CollectionKey) itr.next();
final LoadingCollectionEntry lce = loadContexts.locateLoadingCollectionEntry( collectionKey );
if ( lce == null ) {
LOG.loadingCollectionKeyNotFound( collectionKey );
}
else if ( lce.getResultSet() == resultSet && lce.getPersister() == persister ) {
if ( matches == null ) {
matches = new ArrayList<LoadingCollectionEntry>();
}
matches.add( lce );
if ( lce.getCollection().getOwner() == null ) {
session.getPersistenceContext().addUnownedCollection(
new CollectionKey(
persister,
lce.getKey(),
persister.getOwnerEntityPersister().getEntityMetamodel().getEntityMode()
),
lce.getCollection()
);
}
LOG.tracev( "Removing collection load entry [{0}]", lce );
loadContexts.unregisterLoadingCollectionXRef( collectionKey );
itr.remove();
}
}
endLoadingCollections( persister, matches );
if ( localLoadingCollectionKeys.isEmpty() ) {
loadContexts.cleanup( resultSet );
}
}
private void endLoadingCollections(CollectionPersister persister, List<LoadingCollectionEntry> matchedCollectionEntries) {
final boolean debugEnabled = LOG.isDebugEnabled();
if ( matchedCollectionEntries == null ) {
if ( debugEnabled ) {
LOG.debugf( "No collections were found in result set for role: %s", persister.getRole() );
}
return;
}
final int count = matchedCollectionEntries.size();
if ( debugEnabled ) {
LOG.debugf( "%s collections were found in result set for role: %s", count, persister.getRole() );
}
for ( LoadingCollectionEntry matchedCollectionEntry : matchedCollectionEntries ) {
endLoadingCollection( matchedCollectionEntry, persister );
}
if ( debugEnabled ) {
LOG.debugf( "%s collections initialized for role: %s", count, persister.getRole() );
}
}
private void endLoadingCollection(LoadingCollectionEntry lce, CollectionPersister persister) {
LOG.tracev( "Ending loading collection [{0}]", lce );
final SessionImplementor session = getLoadContext().getPersistenceContext().getSession();
final boolean hasNoQueuedAdds = lce.getCollection().endRead();
if ( persister.getCollectionType().hasHolder() ) {
getLoadContext().getPersistenceContext().addCollectionHolder( lce.getCollection() );
}
CollectionEntry ce = getLoadContext().getPersistenceContext().getCollectionEntry( lce.getCollection() );
if ( ce == null ) {
ce = getLoadContext().getPersistenceContext().addInitializedCollection( persister, lce.getCollection(), lce.getKey() );
}
else {
ce.postInitialize( lce.getCollection() );
}
boolean addToCache =
hasNoQueuedAdds
&& persister.hasCache()
&& session.getCacheMode().isPutEnabled() && !ce.isDoremove();
if ( addToCache ) {
addCollectionToCache( lce, persister );
}
if ( LOG.isDebugEnabled() ) {
LOG.debugf(
"Collection fully initialized: %s",
MessageHelper.collectionInfoString( persister, lce.getCollection(), lce.getKey(), session )
);
}
if ( session.getFactory().getStatistics().isStatisticsEnabled() ) {
session.getFactory().getStatisticsImplementor().loadCollection( persister.getRole() );
}
}
private void addCollectionToCache(LoadingCollectionEntry lce, CollectionPersister persister) {
final SessionImplementor session = getLoadContext().getPersistenceContext().getSession();
final SessionFactoryImplementor factory = session.getFactory();
final boolean debugEnabled = LOG.isDebugEnabled();
if ( debugEnabled ) {
LOG.debugf( "Caching collection: %s", MessageHelper.collectionInfoString( persister, lce.getCollection(), lce.getKey(), session ) );
}
if ( !session.getEnabledFilters().isEmpty() && persister.isAffectedByEnabledFilters( session ) ) {
if ( debugEnabled ) {
LOG.debug( "Refusing to add to cache due to enabled filters" );
}
return;
}
final Object version;
if ( persister.isVersioned() ) {
Object collectionOwner = getLoadContext().getPersistenceContext().getCollectionOwner( lce.getKey(), persister );
if ( collectionOwner == null ) {
if ( lce.getCollection() != null ) {
final Object linkedOwner = lce.getCollection().getOwner();
if ( linkedOwner != null ) {
final Serializable ownerKey = persister.getOwnerEntityPersister().getIdentifier( linkedOwner, session );
collectionOwner = getLoadContext().getPersistenceContext().getCollectionOwner( ownerKey, persister );
}
}
if ( collectionOwner == null ) {
throw new HibernateException(
"Unable to resolve owner of loading collection [" +
MessageHelper.collectionInfoString( persister, lce.getCollection(), lce.getKey(), session ) +
"] for second level caching"
);
}
}
version = getLoadContext().getPersistenceContext().getEntry( collectionOwner ).getVersion();
}
else {
version = null;
}
final CollectionCacheEntry entry = new CollectionCacheEntry( lce.getCollection(), persister );
final CacheKey cacheKey = session.generateCacheKey( lce.getKey(), persister.getKeyType(), persister.getRole() );
boolean isPutFromLoad = true;
if ( persister.getElementType().isAssociationType() ) {
for ( Serializable id : entry.getState() ) {
EntityPersister entityPersister = ( (QueryableCollection) persister ).getElementPersister();
if ( session.getPersistenceContext().wasInsertedDuringTransaction( entityPersister, id ) ) {
isPutFromLoad = false;
break;
}
}
}
if (isPutFromLoad) {
try {
session.getEventListenerManager().cachePutStart();
final boolean put = persister.getCacheAccessStrategy().putFromLoad(
cacheKey,
persister.getCacheEntryStructure().structure( entry ),
session.getTimestamp(),
version,
factory.getSettings().isMinimalPutsEnabled() && session.getCacheMode()!= CacheMode.REFRESH
);
if ( put && factory.getStatistics().isStatisticsEnabled() ) {
factory.getStatisticsImplementor().secondLevelCachePut( persister.getCacheAccessStrategy().getRegion().getName() );
}
}
finally {
session.getEventListenerManager().cachePutEnd();
}
}
}
void cleanup() {
if ( !localLoadingCollectionKeys.isEmpty() ) {
LOG.localLoadingCollectionKeysCount( localLoadingCollectionKeys.size() );
}
loadContexts.cleanupCollectionXRefs( localLoadingCollectionKeys );
localLoadingCollectionKeys.clear();
}
@Override
public String toString() {
return super.toString() + "<rs=" + resultSet + ">";
}
}