/**
   * Based on configured options, will either return a pre-existing proxy, generate a new proxy, or
   * perform an actual load.
   *
   * @return The result of the proxy/load operation.
   * @throws HibernateException
   */
  protected Object proxyOrLoad(
      final LoadEvent event,
      final EntityPersister persister,
      final EntityKey keyToLoad,
      final LoadEventListener.LoadType options)
      throws HibernateException {

    if (log.isTraceEnabled()) {
      log.trace(
          "loading entity: "
              + MessageHelper.infoString(
                  persister, event.getEntityId(), event.getSession().getFactory()));
    }

    if (!persister.hasProxy()) {
      // this class has no proxies (so do a shortcut)
      return load(event, persister, keyToLoad, options);
    } else {
      final PersistenceContext persistenceContext = event.getSession().getPersistenceContext();

      // look for a proxy
      Object proxy = persistenceContext.getProxy(keyToLoad);
      if (proxy != null) {
        return returnNarrowedProxy(event, persister, keyToLoad, options, persistenceContext, proxy);
      } else {
        if (options.isAllowProxyCreation()) {
          return createProxyIfNecessary(event, persister, keyToLoad, options, persistenceContext);
        } else {
          // return a newly loaded object
          return load(event, persister, keyToLoad, options);
        }
      }
    }
  }
  /**
   * 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;
  }
  /**
   * Attempts to locate the entity in the session-level cache. If checkDeleted was set to true, then
   * if the entity is found in the session-level cache, it's current status within the session cache
   * is checked to see if it has previously been scheduled for deletion.
   *
   * @return The entity from the session-level cache, or null.
   * @throws HibernateException
   */
  protected Object loadFromSessionCache(
      final LoadEvent event, final EntityKey keyToLoad, final LoadEventListener.LoadType options)
      throws HibernateException {

    SessionImplementor session = event.getSession();
    Object old = session.getEntityUsingInterceptor(keyToLoad);
    if (old != null) {
      // this object was already loaded
      EntityEntry oldEntry = session.getPersistenceContext().getEntry(old);
      if (options.isCheckDeleted()) {
        throwObjectDeletedIfNecessary(event, oldEntry);
      }
      upgradeLock(old, oldEntry, event.getLockMode(), session);
    }
    return old;
  }
 /** Given that there is a pre-existing proxy. Initialize it if necessary; narrow if necessary. */
 private Object returnNarrowedProxy(
     final LoadEvent event,
     final EntityPersister persister,
     final EntityKey keyToLoad,
     final LoadEventListener.LoadType options,
     final PersistenceContext persistenceContext,
     final Object proxy) {
   log.trace("entity proxy found in session cache");
   LazyInitializer li = ((HibernateProxy) proxy).getHibernateLazyInitializer();
   if (li.isUnwrap()) {
     return li.getImplementation();
   }
   // return existing or narrowed proxy
   Object impl =
       options.isAllowProxyCreation() ? null : load(event, persister, keyToLoad, options);
   return persistenceContext.narrowProxy(proxy, persister, keyToLoad, impl);
 }
  /**
   * 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;
    }
  }
 /**
  * Given that there is no pre-existing proxy. Check if the entity is already loaded. If it is,
  * return the entity, otherwise create and return a proxy.
  */
 private Object createProxyIfNecessary(
     final LoadEvent event,
     final EntityPersister persister,
     final EntityKey keyToLoad,
     final LoadEventListener.LoadType options,
     final PersistenceContext persistenceContext) {
   Object existing = persistenceContext.getEntity(keyToLoad);
   if (existing != null) {
     // return existing object or initialized proxy (unless deleted)
     log.trace("entity found in session cache");
     if (options.isCheckDeleted()) {
       EntityEntry entry = persistenceContext.getEntry(existing);
       throwObjectDeletedIfNecessary(event, entry);
     }
     return existing;
   } else {
     log.trace("creating new proxy for entity");
     // return new uninitialized proxy
     Object proxy = persister.createProxy(event.getEntityId(), event.getSession());
     persistenceContext.getBatchFetchQueue().addBatchLoadableEntityKey(keyToLoad);
     persistenceContext.addProxy(keyToLoad, proxy);
     return proxy;
   }
 }