private void throwObjectDeletedIfNecessary(LoadEvent event, EntityEntry oldEntry) { Status status = oldEntry.getStatus(); if (status == Status.DELETED || status == Status.GONE) { throw new ObjectDeletedException( "The object with that id was deleted", event.getEntityId(), event.getEntityClassName()); } }
/** * 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); } } } }
/** * Attempts to load the entity from the second-level cache. * * @return The entity from the second-level cache, or null. * @throws HibernateException */ protected Object loadFromSecondLevelCache( final LoadEvent event, final EntityPersister persister, final LoadEventListener.LoadType options) throws HibernateException { final SessionImplementor source = event.getSession(); final boolean useCache = persister.hasCache() && source.getCacheMode().isGetEnabled() && event.getLockMode().lessThan(LockMode.READ); if (useCache) { final SessionFactoryImplementor factory = source.getFactory(); final CacheKey ck = new CacheKey( event.getEntityId(), persister.getIdentifierType(), persister.getRootEntityName(), source.getEntityMode(), source.getFactory()); Object ce = persister.getCache().get(ck, source.getTimestamp()); if (factory.getStatistics().isStatisticsEnabled()) { if (ce == null) { factory .getStatisticsImplementor() .secondLevelCacheMiss(persister.getCache().getRegionName()); } else { factory .getStatisticsImplementor() .secondLevelCacheHit(persister.getCache().getRegionName()); } } if (ce != null) { CacheEntry entry = (CacheEntry) persister.getCacheEntryStructure().destructure(ce, factory); // Entity was found in second-level cache... return assembleCacheEntry(entry, event.getEntityId(), persister, event); } } return null; }
/** * 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; }
/** * Coordinates the efforts to load a given entity. First, an attempt is made to load the entity * from the session-level cache. If not found there, an attempt is made to locate it in * second-level cache. Lastly, an attempt is made to load it directly from the datasource. * * @return The loaded entity. * @throws HibernateException */ protected Object doLoad( final LoadEvent event, final EntityPersister persister, final EntityKey keyToLoad, final LoadEventListener.LoadType options) throws HibernateException { if (log.isTraceEnabled()) { log.trace( "attempting to resolve: " + MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory())); } Object entity = loadFromSessionCache(event, keyToLoad, options); if (entity != null) { if (log.isTraceEnabled()) { log.trace( "resolved object in session cache: " + MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory())); } return entity; } // Entity not found in session; before going any further, see if we // already determined that this entity does not exist /*if ( event.getSession().getPersistenceContext().isNonExistant(keyToLoad) ) { if ( log.isTraceEnabled() ) log.trace("entity does not exist"); return null; }*/ entity = loadFromSecondLevelCache(event, persister, options); if (entity != null) { if (log.isTraceEnabled()) { log.trace( "resolved object in second-level cache: " + MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory())); } return entity; } if (log.isTraceEnabled()) { log.trace( "object not resolved in any cache: " + MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory())); } return loadFromDatasource(event, persister, keyToLoad, options); }
/** * If the class to be loaded has been configured with a cache, then lock given id in that cache * and then perform the load. * * @return The loaded entity * @throws HibernateException */ protected Object lockAndLoad( final LoadEvent event, final EntityPersister persister, final EntityKey keyToLoad, final LoadEventListener.LoadType options, final SessionImplementor source) throws HibernateException { CacheConcurrencyStrategy.SoftLock lock = null; final CacheKey ck; if (persister.hasCache()) { ck = new CacheKey( event.getEntityId(), persister.getIdentifierType(), persister.getRootEntityName(), source.getEntityMode(), source.getFactory()); lock = persister.getCache().lock(ck, null); } else { ck = null; } Object entity; try { entity = load(event, persister, keyToLoad, options); } finally { if (persister.hasCache()) { persister.getCache().release(ck, lock); } } Object proxy = event.getSession().getPersistenceContext().proxyFor(persister, keyToLoad, entity); return proxy; }
/** * 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; } }
/** * 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; }
/** * 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; } }
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; }
/** * 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; }