/**
   * Perfoms the load of an entity.
   *
   * @return The loaded entity.
   * @throws HibernateException
   */
  protected Object load(
      final LoadEvent event,
      final EntityPersister persister,
      final EntityKey keyToLoad,
      final LoadEventListener.LoadType options)
      throws HibernateException {

    if (event.getInstanceToLoad() != null) {
      if (event.getSession().getPersistenceContext().getEntry(event.getInstanceToLoad()) != null) {
        throw new PersistentObjectException(
            "attempted to load into an instance that was already associated with the session: "
                + MessageHelper.infoString(
                    persister, event.getEntityId(), event.getSession().getFactory()));
      }
      persister.setIdentifier(
          event.getInstanceToLoad(), event.getEntityId(), event.getSession().getEntityMode());
    }

    Object entity = doLoad(event, persister, keyToLoad, options);

    boolean isOptionalInstance = event.getInstanceToLoad() != null;

    if (!options.isAllowNulls() || isOptionalInstance) {
      ObjectNotFoundException.throwIfNull(entity, event.getEntityId(), event.getEntityClassName());
    }

    if (isOptionalInstance && entity != event.getInstanceToLoad()) {
      throw new NonUniqueObjectException(event.getEntityId(), event.getEntityClassName());
    }

    return entity;
  }
  /**
   * Handle the given load event.
   *
   * @param event The load event to be handled.
   * @return The result (i.e., the loaded entity).
   * @throws HibernateException
   */
  public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
      throws HibernateException {

    final SessionImplementor source = event.getSession();

    EntityPersister persister;
    if (event.getInstanceToLoad() != null) {
      persister =
          source.getEntityPersister(
              null, event.getInstanceToLoad()); // the load() which takes an entity does not pass an
      // entityName
      event.setEntityClassName(event.getInstanceToLoad().getClass().getName());
    } else {
      persister = source.getFactory().getEntityPersister(event.getEntityClassName());
    }

    if (persister == null) {
      throw new HibernateException("Unable to locate persister: " + event.getEntityClassName());
    }

    EntityKey keyToLoad = new EntityKey(event.getEntityId(), persister, source.getEntityMode());

    try {
      if (loadType.isNakedEntityReturned()) {
        // do not return a proxy!
        // (this option indicates we are initializing a proxy)
        event.setResult(load(event, persister, keyToLoad, loadType));
      } else {
        // return a proxy if appropriate
        if (event.getLockMode() == LockMode.NONE) {
          event.setResult(proxyOrLoad(event, persister, keyToLoad, loadType));
        } else {
          event.setResult(lockAndLoad(event, persister, keyToLoad, loadType, source));
        }
      }
    } catch (HibernateException e) {
      log.info("Error performing load command", e);
      throw e;
    }
  }
  /**
   * Performs the process of loading an entity from the configured underlying datasource.
   *
   * @return The object loaded from the datasource, or null if not found.
   * @throws HibernateException
   */
  protected Object loadFromDatasource(
      final LoadEvent event,
      final EntityPersister persister,
      final EntityKey keyToLoad,
      final LoadEventListener.LoadType options)
      throws HibernateException {

    final SessionImplementor source = event.getSession();

    Object entity =
        persister.load(event.getEntityId(), event.getInstanceToLoad(), event.getLockMode(), source);

    /*if ( entity == null ) {
    	//remember it doesn't exist, in case of next time
    	source.getPersistenceContext().addNonExistantEntityKey(keyToLoad);
    }*/

    if (event.isAssociationFetch() && source.getFactory().getStatistics().isStatisticsEnabled()) {
      source.getFactory().getStatisticsImplementor().fetchEntity(event.getEntityClassName());
    }

    return entity;
  }
  private Object assembleCacheEntry(
      final CacheEntry entry,
      final Serializable id,
      final EntityPersister persister,
      final LoadEvent event)
      throws HibernateException {

    final Object optionalObject = event.getInstanceToLoad();
    final EventSource session = event.getSession();
    final SessionFactoryImplementor factory = session.getFactory();

    if (log.isTraceEnabled()) {
      log.trace(
          "assembling entity from second-level cache: "
              + MessageHelper.infoString(persister, id, factory));
    }

    EntityPersister subclassPersister = factory.getEntityPersister(entry.getSubclass());
    Object result =
        optionalObject == null ? session.instantiate(subclassPersister, id) : optionalObject;

    // make it circular-reference safe
    TwoPhaseLoad.addUninitializedCachedEntity(
        new EntityKey(id, subclassPersister, session.getEntityMode()),
        result,
        subclassPersister,
        LockMode.NONE,
        entry.areLazyPropertiesUnfetched(),
        entry.getVersion(),
        session);

    Type[] types = subclassPersister.getPropertyTypes();
    Object[] values =
        entry.assemble(
            result,
            id,
            subclassPersister,
            session.getInterceptor(),
            session); // intializes result by side-effect
    TypeFactory.deepCopy(
        values, types, subclassPersister.getPropertyUpdateability(), values, session);

    Object version = Versioning.getVersion(values, subclassPersister);
    if (log.isTraceEnabled()) log.trace("Cached Version: " + version);

    final PersistenceContext persistenceContext = session.getPersistenceContext();
    persistenceContext.addEntry(
        result,
        Status.MANAGED,
        values,
        null,
        id,
        version,
        LockMode.NONE,
        true,
        subclassPersister,
        false,
        entry.areLazyPropertiesUnfetched());
    subclassPersister.afterInitialize(result, entry.areLazyPropertiesUnfetched(), session);
    persistenceContext.initializeNonLazyCollections();
    // upgrade the lock if necessary:
    // lock(result, lockMode);

    // PostLoad is needed for EJB3
    // TODO: reuse the PostLoadEvent...
    PostLoadEvent postLoadEvent =
        new PostLoadEvent(session).setEntity(result).setId(id).setPersister(persister);
    PostLoadEventListener[] listeners = session.getListeners().getPostLoadEventListeners();
    for (int i = 0; i < listeners.length; i++) {
      listeners[i].onPostLoad(postLoadEvent);
    }

    return result;
  }