Package org.hibernate.engine.loading.internal

Source Code of org.hibernate.engine.loading.internal.LoadContexts

/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors.  All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA  02110-1301  USA
*/
package org.hibernate.engine.loading.internal;

import java.io.Serializable;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.jboss.logging.Logger;

import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.collections.IdentityMap;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.pretty.MessageHelper;

/**
* 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 CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, LoadContexts.class.getName());

  private final PersistenceContext persistenceContext;
  private Map<ResultSet,CollectionLoadContext> collectionLoadContexts;
  private Map<ResultSet,EntityLoadContext> entityLoadContexts;

  private Map<CollectionKey,LoadingCollectionEntry> 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;
  }

  private SessionImplementor getSession() {
    return getPersistenceContext().getSession();
  }


  // cleanup code ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

   /**
   * Release internal state associated with the given result set.
   * <p/>
   * This should be called when we are done with processing said result set,
   * ideally as the result set is being closed.
   *
   * @param resultSet The result set for which it is ok to release
   * associated resources.
   */
  public void cleanup(ResultSet resultSet) {
    if ( collectionLoadContexts != null ) {
      CollectionLoadContext collectionLoadContext = collectionLoadContexts.remove( resultSet );
      collectionLoadContext.cleanup();
    }
    if ( entityLoadContexts != null ) {
      EntityLoadContext entityLoadContext = entityLoadContexts.remove( resultSet );
      entityLoadContext.cleanup();
    }
  }

  /**
   * Release internal state associated with *all* result sets.
   * <p/>
   * This is intended as a "failsafe" process to make sure we get everything
   * cleaned up and released.
   */
  public void cleanup() {
    if ( collectionLoadContexts != null ) {
      for ( CollectionLoadContext collectionLoadContext : collectionLoadContexts.values() ) {
        LOG.failSafeCollectionsCleanup( collectionLoadContext );
        collectionLoadContext.cleanup();
      }
      collectionLoadContexts.clear();
    }
    if ( entityLoadContexts != null ) {
      for ( EntityLoadContext entityLoadContext : entityLoadContexts.values() ) {
        LOG.failSafeEntitiesCleanup( entityLoadContext );
        entityLoadContext.cleanup();
      }
      entityLoadContexts.clear();
    }
  }


  // Collection load contexts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  /**
   * Do we currently have any internal entries corresponding to loading
   * collections?
   *
   * @return True if we currently hold state pertaining to loading collections;
   * false otherwise.
   */
  public boolean hasLoadingCollectionEntries() {
    return ( collectionLoadContexts != null && !collectionLoadContexts.isEmpty() );
  }

  /**
   * Do we currently have any registered internal entries corresponding to loading
   * collections?
   *
   * @return True if we currently hold state pertaining to a registered loading collections;
   * false otherwise.
   */
  public boolean hasRegisteredLoadingCollectionEntries() {
    return ( xrefLoadingCollectionEntries != null && !xrefLoadingCollectionEntries.isEmpty() );
  }


  /**
   * 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 = collectionLoadContexts.get(resultSet);
    }
    if ( context == null ) {
      LOG.tracev( "Constructing collection load context for result set [{0}]", 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 ) );
    if ( lce != null ) {
      if ( LOG.isTraceEnabled() ) {
        LOG.tracef(
            "Returning loading collection: %s",
            MessageHelper.collectionInfoString( persister, ownerKey, getSession().getFactory() )
        );
      }
      return lce.getCollection();
    }
    // TODO : should really move this log statement to CollectionType, where this is used from...
    if ( LOG.isTraceEnabled() ) {
      LOG.tracef( "Creating collection wrapper: %s",
          MessageHelper.collectionInfoString( persister, ownerKey, getSession().getFactory() ) );
    }
    return null;
  }

  // loading collection xrefs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  /**
   * Register a loading collection xref.
   * <p/>
   * This xref map is used because sometimes a collection is in process of
   * being loaded from one result set, but needs to be accessed from the
   * context of another "nested" result set processing.
   * <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 entryKey The xref collection key
   * @param entry The corresponding loading collection entry
   */
  void registerLoadingCollectionXRef(CollectionKey entryKey, LoadingCollectionEntry entry) {
    if ( xrefLoadingCollectionEntries == null ) {
      xrefLoadingCollectionEntries = new HashMap<CollectionKey,LoadingCollectionEntry>();
    }
    xrefLoadingCollectionEntries.put( entryKey, entry );
  }

  /**
   * The inverse of {@link #registerLoadingCollectionXRef}.  Here, we are done
   * processing the said collection entry, so we remove it from the
   * load context.
   * <p/>
   * The idea here is that other loading collections can now reference said
   * collection directly from the {@link PersistenceContext} because it
   * has completed its load cycle.
   * <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 key of the collection we are done processing.
   */
  void unregisterLoadingCollectionXRef(CollectionKey key) {
    if ( !hasRegisteredLoadingCollectionEntries() ) {
      return;
    }
    xrefLoadingCollectionEntries.remove(key);
   }

  /*package*/Map getLoadingCollectionXRefs() {
     return xrefLoadingCollectionEntries;
   }


  /**
   * 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;
    }
    LOG.tracev( "Attempting to locate loading collection entry [{0}] in any result-set context", key );
    LoadingCollectionEntry rtn = xrefLoadingCollectionEntries.get( key );
    if ( rtn == null ) {
      LOG.tracev( "Collection [{0}] not located in load context", key );
    }
    else {
      LOG.tracev( "Collection [{0}] located in load context", key );
    }
    return rtn;
  }

  /*package*/void cleanupCollectionXRefs(Set<CollectionKey> entryKeys) {
    for ( CollectionKey entryKey : entryKeys ) {
      xrefLoadingCollectionEntries.remove( entryKey );
    }
  }


  // Entity load contexts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  //   * currently, not yet used...

  public EntityLoadContext getEntityLoadContext(ResultSet resultSet) {
    EntityLoadContext context = null;
    if ( entityLoadContexts == null ) {
      entityLoadContexts = IdentityMap.instantiate( 8 );
    }
    else {
      context = entityLoadContexts.get( resultSet );
    }
    if ( context == null ) {
      context = new EntityLoadContext( this, resultSet );
      entityLoadContexts.put( resultSet, context );
    }
    return context;
  }
}
TOP

Related Classes of org.hibernate.engine.loading.internal.LoadContexts

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.