package org.hibernate.engine.loading;
import java.sql.ResultSet;
import java.util.Map;
import java.util.Set;
import java.util.Iterator;
import java.util.HashMap;
import java.io.Serializable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.util.IdentityMap;
import org.hibernate.engine.PersistenceContext;
import org.hibernate.engine.CollectionKey;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.collection.PersistentCollection;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.EntityMode;
/**
* Maps {@link ResultSet result-sets} to specific contextual data
* related to processing that {@link ResultSet result-sets}.
* <p/>
* Implementation note: internally an {@link IdentityMap} is used to maintain
* the mappings; {@link IdentityMap} was chosen because I'd rather not be
* dependent upon potentially bad {@link ResultSet#equals} and {ResultSet#hashCode}
* implementations.
* <p/>
* Considering the JDBC-redesign work, would further like this contextual info
* not mapped seperately, but available based on the result set being processed.
* This would also allow maintaining a single mapping as we could reliably get
* notification of the result-set closing...
*
* @author Steve Ebersole
*/
public class LoadContexts {
private static final Log log = LogFactory.getLog( LoadContexts.class );
private final PersistenceContext persistenceContext;
private Map collectionLoadContexts;
private Map entityLoadContexts;
private Map xrefLoadingCollectionEntries;
/**
* Creates and binds this to the given persistence context.
*
* @param persistenceContext The persistence context to which this
* will be bound.
*/
public LoadContexts(PersistenceContext persistenceContext) {
this.persistenceContext = persistenceContext;
}
/**
* Retrieves the persistence context to which this is bound.
*
* @return The persistence context to which this is bound.
*/
public PersistenceContext getPersistenceContext() {
return persistenceContext;
}
/**
* Get the {@link CollectionLoadContext} associated with the given
* {@link ResultSet}, creating one if needed.
*
* @param resultSet The result set for which to retrieve the context.
* @return The processing context.
*/
public CollectionLoadContext getCollectionLoadContext(ResultSet resultSet) {
CollectionLoadContext context = null;
if ( collectionLoadContexts == null ) {
collectionLoadContexts = IdentityMap.instantiate( 8 );
}
else {
context = ( CollectionLoadContext ) collectionLoadContexts.get( resultSet );
}
if ( context == null ) {
if ( log.isTraceEnabled() ) {
log.trace( "constructing collection load context for result set [" + resultSet + "]" );
}
context = new CollectionLoadContext( this, resultSet );
collectionLoadContexts.put( resultSet, context );
}
return context;
}
/**
* Attempt to locate the loading collection given the owner's key. The lookup here
* occurs against all result-set contexts...
*
* @param persister The collection persister
* @param ownerKey The owner key
* @return The loading collection, or null if not found.
*/
public PersistentCollection locateLoadingCollection(CollectionPersister persister, Serializable ownerKey) {
LoadingCollectionEntry lce = locateLoadingCollectionEntry( new CollectionKey( persister, ownerKey, getEntityMode() ) );
if ( lce != null ) {
if ( log.isTraceEnabled() ) {
log.trace( "returning loading collection:" + MessageHelper.collectionInfoString( persister, ownerKey, getSession().getFactory() ) );
}
return lce.getCollection();
}
else {
// todo : should really move this log statement to CollectionType, where this is used from...
if ( log.isTraceEnabled() ) {
log.trace( "creating collection wrapper:" + MessageHelper.collectionInfoString( persister, ownerKey, getSession().getFactory() ) );
}
return null;
}
}
/**
* Locate the LoadingCollectionEntry within *any* of the tracked
* {@link CollectionLoadContext}s.
* <p/>
* Implementation note: package protected, as this is meant solely for use
* by {@link CollectionLoadContext} to be able to locate collections
* being loaded by other {@link CollectionLoadContext}s/{@link ResultSet}s.
*
* @param key The collection key.
* @return The located entry; or null.
*/
LoadingCollectionEntry locateLoadingCollectionEntry(CollectionKey key) {
if ( xrefLoadingCollectionEntries == null ) {
return null;
}
if ( log.isTraceEnabled() ) {
log.trace( "attempting to locate loading collection entry [" + key + "] in any result-set context" );
}
LoadingCollectionEntry rtn = ( LoadingCollectionEntry ) xrefLoadingCollectionEntries.get( key );
if ( log.isTraceEnabled() ) {
if ( rtn == null ) {
log.trace( "collection [" + key + "] located in load context" );
}
else {
log.trace( "collection [" + key + "] not located in load context" );
}
}
return rtn;
}
/*package*/void registerLoadingCollectionEntry(CollectionKey entryKey, LoadingCollectionEntry entry) {
if ( xrefLoadingCollectionEntries == null ) {
xrefLoadingCollectionEntries = new HashMap();
}
xrefLoadingCollectionEntries.put( entryKey, entry );
}
/*package*/Map getLoadingCollectionEntryMap() {
return xrefLoadingCollectionEntries;
}
/*package*/void cleanupCollectionEntries(Set entryKeys) {
Iterator itr = entryKeys.iterator();
while ( itr.hasNext() ) {
final CollectionKey entryKey = ( CollectionKey ) itr.next();
xrefLoadingCollectionEntries.remove( entryKey );
}
}
public EntityLoadContext getEntityLoadContext(ResultSet resultSet) {
EntityLoadContext context = null;
if ( entityLoadContexts == null ) {
entityLoadContexts = IdentityMap.instantiate( 8 );
}
else {
context = ( EntityLoadContext ) entityLoadContexts.get( resultSet );
}
if ( context == null ) {
context = new EntityLoadContext( this, resultSet );
entityLoadContexts.put( resultSet, context );
}
return context;
}
public void cleanup(ResultSet resultSet) {
if ( collectionLoadContexts != null ) {
CollectionLoadContext collectionLoadContext = ( CollectionLoadContext ) collectionLoadContexts.remove( resultSet );
collectionLoadContext.cleanup();
}
if ( entityLoadContexts != null ) {
EntityLoadContext entityLoadContext = ( EntityLoadContext ) entityLoadContexts.remove( resultSet );
entityLoadContext.cleanup();
}
}
private SessionImplementor getSession() {
return getPersistenceContext().getSession();
}
private EntityMode getEntityMode() {
return getSession().getEntityMode();
}
}
|