All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.internal.SessionImpl Maven / Gradle / Ivy

There is a newer version: 7.0.0.Alpha1
Show newest version
/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * Copyright (c) 2005-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.internal;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Reader;
import java.io.Serializable;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.NClob;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.EntityNotFoundException;

import org.hibernate.AssertionFailure;
import org.hibernate.CacheMode;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.Criteria;
import org.hibernate.EmptyInterceptor;
import org.hibernate.EntityNameResolver;
import org.hibernate.Filter;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.IdentifierLoadAccess;
import org.hibernate.Interceptor;
import org.hibernate.LobHelper;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.NaturalIdLoadAccess;
import org.hibernate.ObjectDeletedException;
import org.hibernate.ObjectNotFoundException;
import org.hibernate.Query;
import org.hibernate.QueryException;
import org.hibernate.ReplicationMode;
import org.hibernate.SQLQuery;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.SessionBuilder;
import org.hibernate.SessionEventListener;
import org.hibernate.SessionException;
import org.hibernate.SharedSessionBuilder;
import org.hibernate.SimpleNaturalIdLoadAccess;
import org.hibernate.Transaction;
import org.hibernate.TransientObjectException;
import org.hibernate.TypeHelper;
import org.hibernate.UnknownProfileException;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.criterion.NaturalIdentifier;
import org.hibernate.engine.internal.SessionEventListenerManagerImpl;
import org.hibernate.engine.internal.StatefulPersistenceContext;
import org.hibernate.engine.jdbc.LobCreator;
import org.hibernate.engine.jdbc.NonContextualLobCreator;
import org.hibernate.engine.query.spi.FilterQueryPlan;
import org.hibernate.engine.query.spi.HQLQueryPlan;
import org.hibernate.engine.query.spi.NativeSQLQueryPlan;
import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification;
import org.hibernate.engine.spi.ActionQueue;
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionOwner;
import org.hibernate.engine.spi.Status;
import org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import org.hibernate.engine.transaction.spi.TransactionImplementor;
import org.hibernate.engine.transaction.spi.TransactionObserver;
import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.AutoFlushEvent;
import org.hibernate.event.spi.AutoFlushEventListener;
import org.hibernate.event.spi.ClearEvent;
import org.hibernate.event.spi.ClearEventListener;
import org.hibernate.event.spi.DeleteEvent;
import org.hibernate.event.spi.DeleteEventListener;
import org.hibernate.event.spi.DirtyCheckEvent;
import org.hibernate.event.spi.DirtyCheckEventListener;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.EvictEvent;
import org.hibernate.event.spi.EvictEventListener;
import org.hibernate.event.spi.FlushEvent;
import org.hibernate.event.spi.FlushEventListener;
import org.hibernate.event.spi.InitializeCollectionEvent;
import org.hibernate.event.spi.InitializeCollectionEventListener;
import org.hibernate.event.spi.LoadEvent;
import org.hibernate.event.spi.LoadEventListener;
import org.hibernate.event.spi.LoadEventListener.LoadType;
import org.hibernate.event.spi.LockEvent;
import org.hibernate.event.spi.LockEventListener;
import org.hibernate.event.spi.MergeEvent;
import org.hibernate.event.spi.MergeEventListener;
import org.hibernate.event.spi.PersistEvent;
import org.hibernate.event.spi.PersistEventListener;
import org.hibernate.event.spi.RefreshEvent;
import org.hibernate.event.spi.RefreshEventListener;
import org.hibernate.event.spi.ReplicateEvent;
import org.hibernate.event.spi.ReplicateEventListener;
import org.hibernate.event.spi.ResolveNaturalIdEvent;
import org.hibernate.event.spi.ResolveNaturalIdEventListener;
import org.hibernate.event.spi.SaveOrUpdateEvent;
import org.hibernate.event.spi.SaveOrUpdateEventListener;
import org.hibernate.internal.CriteriaImpl.CriterionEntry;
import org.hibernate.jdbc.ReturningWork;
import org.hibernate.jdbc.Work;
import org.hibernate.jdbc.WorkExecutor;
import org.hibernate.jdbc.WorkExecutorVisitable;
import org.hibernate.loader.criteria.CriteriaLoader;
import org.hibernate.loader.custom.CustomLoader;
import org.hibernate.loader.custom.CustomQuery;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.procedure.ProcedureCall;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.stat.SessionStatistics;
import org.hibernate.stat.internal.SessionStatisticsImpl;
import org.hibernate.type.Type;

import org.jboss.logging.Logger;

/**
 * Concrete implementation of a Session.
 *
 * Exposes two interfaces:
    *
  • {@link Session} to the application
  • *
  • {@link org.hibernate.engine.spi.SessionImplementor} to other Hibernate components (SPI)
  • *
* * This class is not thread-safe. * * @author Gavin King * @author Steve Ebersole * @author Brett Meyer */ public final class SessionImpl extends AbstractSessionImpl implements EventSource { // todo : need to find a clean way to handle the "event source" role // a separate class responsible for generating/dispatching events just duplicates most of the Session methods... // passing around separate interceptor, factory, actionQueue, and persistentContext is not manageable... private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, SessionImpl.class.getName()); private static final boolean TRACE_ENABLED = LOG.isTraceEnabled(); private transient long timestamp; private transient SessionOwner sessionOwner; private transient ActionQueue actionQueue; private transient StatefulPersistenceContext persistenceContext; private transient TransactionCoordinatorImpl transactionCoordinator; private transient Interceptor interceptor; private transient EntityNameResolver entityNameResolver = new CoordinatingEntityNameResolver(); private transient ConnectionReleaseMode connectionReleaseMode; private transient FlushMode flushMode = FlushMode.AUTO; private transient CacheMode cacheMode = CacheMode.NORMAL; private transient boolean autoClear; //for EJB3 private transient boolean autoJoinTransactions = true; private transient boolean flushBeforeCompletionEnabled; private transient boolean autoCloseSessionEnabled; private transient int dontFlushFromFind; private transient LoadQueryInfluencers loadQueryInfluencers; private final transient boolean isTransactionCoordinatorShared; private transient TransactionObserver transactionObserver; private SessionEventListenerManagerImpl sessionEventsManager = new SessionEventListenerManagerImpl(); /** * Constructor used for openSession(...) processing, as well as construction * of sessions for getCurrentSession(). * * @param connection The user-supplied connection to use for this session. * @param factory The factory from which this session was obtained * @param transactionCoordinator The transaction coordinator to use, may be null to indicate that a new transaction * coordinator should get created. * @param autoJoinTransactions Should the session automatically join JTA transactions? * @param timestamp The timestamp for this session * @param interceptor The interceptor to be applied to this session * @param flushBeforeCompletionEnabled Should we auto flush before completion of transaction * @param autoCloseSessionEnabled Should we auto close after completion of transaction * @param connectionReleaseMode The mode by which we should release JDBC connections. * @param tenantIdentifier The tenant identifier to use. May be null */ SessionImpl( final Connection connection, final SessionFactoryImpl factory, final SessionOwner sessionOwner, final TransactionCoordinatorImpl transactionCoordinator, final ActionQueue.TransactionCompletionProcesses transactionCompletionProcesses, final boolean autoJoinTransactions, final long timestamp, final Interceptor interceptor, final boolean flushBeforeCompletionEnabled, final boolean autoCloseSessionEnabled, final ConnectionReleaseMode connectionReleaseMode, final String tenantIdentifier) { super( factory, tenantIdentifier ); this.timestamp = timestamp; this.sessionOwner = sessionOwner; this.interceptor = interceptor == null ? EmptyInterceptor.INSTANCE : interceptor; this.actionQueue = new ActionQueue( this ); this.persistenceContext = new StatefulPersistenceContext( this ); this.autoCloseSessionEnabled = autoCloseSessionEnabled; this.flushBeforeCompletionEnabled = flushBeforeCompletionEnabled; if ( transactionCoordinator == null ) { this.isTransactionCoordinatorShared = false; this.connectionReleaseMode = connectionReleaseMode; this.autoJoinTransactions = autoJoinTransactions; this.transactionCoordinator = new TransactionCoordinatorImpl( connection, this ); this.transactionCoordinator.getJdbcCoordinator().getLogicalConnection().addObserver( new ConnectionObserverStatsBridge( factory ) ); } else { if ( connection != null ) { throw new SessionException( "Cannot simultaneously share transaction context and specify connection" ); } this.transactionCoordinator = transactionCoordinator; this.isTransactionCoordinatorShared = true; this.autoJoinTransactions = false; if ( transactionCompletionProcesses != null ) { actionQueue.setTransactionCompletionProcesses( transactionCompletionProcesses, true ); } if ( autoJoinTransactions ) { LOG.debug( "Session creation specified 'autoJoinTransactions', which is invalid in conjunction " + "with sharing JDBC connection between sessions; ignoring" ); } if ( connectionReleaseMode != transactionCoordinator.getJdbcCoordinator().getLogicalConnection().getConnectionReleaseMode() ) { LOG.debug( "Session creation specified 'connectionReleaseMode', which is invalid in conjunction " + "with sharing JDBC connection between sessions; ignoring" ); } this.connectionReleaseMode = transactionCoordinator.getJdbcCoordinator().getLogicalConnection().getConnectionReleaseMode(); // add a transaction observer so that we can handle delegating managed actions back to THIS session // versus the session that created (and therefore "owns") the transaction coordinator transactionObserver = new TransactionObserver() { @Override public void afterBegin(TransactionImplementor transaction) { } @Override public void beforeCompletion(TransactionImplementor transaction) { if ( isOpen() && flushBeforeCompletionEnabled ) { SessionImpl.this.managedFlush(); } beforeTransactionCompletion( transaction ); } @Override public void afterCompletion(boolean successful, TransactionImplementor transaction) { afterTransactionCompletion( transaction, successful ); if ( isOpen() && autoCloseSessionEnabled ) { managedClose(); } transactionCoordinator.removeObserver( this ); } }; transactionCoordinator.addObserver( transactionObserver ); } loadQueryInfluencers = new LoadQueryInfluencers( factory ); if (factory.getStatistics().isStatisticsEnabled()) { factory.getStatisticsImplementor().openSession(); } if ( TRACE_ENABLED ) LOG.tracef( "Opened session at timestamp: %s", timestamp ); } @Override public SharedSessionBuilder sessionWithOptions() { return new SharedSessionBuilderImpl( this ); } @Override public void clear() { errorIfClosed(); // Do not call checkTransactionSynchStatus() here -- if a delayed // afterCompletion exists, it can cause an infinite loop. pulseTransactionCoordinator(); internalClear(); } private void internalClear() { persistenceContext.clear(); actionQueue.clear(); final ClearEvent event = new ClearEvent( this ); for ( ClearEventListener listener : listeners( EventType.CLEAR ) ) { listener.onClear( event ); } } @Override public long getTimestamp() { checkTransactionSynchStatus(); return timestamp; } @Override public Connection close() throws HibernateException { LOG.trace( "Closing session" ); if ( isClosed() ) { throw new SessionException( "Session was already closed" ); } if ( factory.getStatistics().isStatisticsEnabled() ) { factory.getStatisticsImplementor().closeSession(); } getEventListenerManager().end(); try { if ( !isTransactionCoordinatorShared ) { return transactionCoordinator.close(); } else { if ( getActionQueue().hasBeforeTransactionActions() || getActionQueue().hasAfterTransactionActions() ) { LOG.warn( "On close, shared Session had before / after transaction actions that have not yet been processed" ); } else { transactionCoordinator.removeObserver( transactionObserver ); } return null; } } finally { setClosed(); cleanup(); } } @Override public ConnectionReleaseMode getConnectionReleaseMode() { return connectionReleaseMode; } @Override public boolean shouldAutoJoinTransaction() { return autoJoinTransactions; } @Override public boolean isAutoCloseSessionEnabled() { return autoCloseSessionEnabled; } @Override public boolean isOpen() { checkTransactionSynchStatus(); return !isClosed(); } @Override public boolean isFlushModeNever() { return FlushMode.isManualFlushMode( getFlushMode() ); } @Override public boolean isFlushBeforeCompletionEnabled() { return flushBeforeCompletionEnabled; } @Override public void managedFlush() { if ( isClosed() ) { LOG.trace( "Skipping auto-flush due to session closed" ); return; } LOG.trace( "Automatically flushing session" ); flush(); } @Override public boolean shouldAutoClose() { if ( isClosed() ) { return false; } else if ( sessionOwner != null ) { return sessionOwner.shouldAutoCloseSession(); } else { return isAutoCloseSessionEnabled(); } } @Override public void managedClose() { LOG.trace( "Automatically closing session" ); close(); } @Override public Connection connection() throws HibernateException { errorIfClosed(); return transactionCoordinator.getJdbcCoordinator().getLogicalConnection().getConnection(); } @Override public boolean isConnected() { checkTransactionSynchStatus(); return !isClosed() && transactionCoordinator.getJdbcCoordinator().getLogicalConnection().isOpen(); } @Override public boolean isTransactionInProgress() { checkTransactionSynchStatus(); return !isClosed() && transactionCoordinator.isTransactionInProgress(); } @Override public Connection disconnect() throws HibernateException { errorIfClosed(); LOG.debug( "Disconnecting session" ); transactionCoordinator.getJdbcCoordinator().releaseResources(); return transactionCoordinator.getJdbcCoordinator().getLogicalConnection().manualDisconnect(); } @Override public void reconnect(Connection conn) throws HibernateException { errorIfClosed(); LOG.debug( "Reconnecting session" ); checkTransactionSynchStatus(); transactionCoordinator.getJdbcCoordinator().getLogicalConnection().manualReconnect( conn ); } @Override public void setAutoClear(boolean enabled) { errorIfClosed(); autoClear = enabled; } @Override public void disableTransactionAutoJoin() { errorIfClosed(); autoJoinTransactions = false; } /** * Check if there is a Hibernate or JTA transaction in progress and, * if there is not, flush if necessary, make sure the connection has * been committed (if it is not in autocommit mode) and run the after * completion processing * * @param success Was the operation a success */ public void afterOperation(boolean success) { if ( ! transactionCoordinator.isTransactionInProgress() ) { transactionCoordinator.afterNonTransactionalQuery( success ); } } @Override public void afterTransactionBegin(TransactionImplementor hibernateTransaction) { errorIfClosed(); interceptor.afterTransactionBegin( hibernateTransaction ); } @Override public void beforeTransactionCompletion(TransactionImplementor hibernateTransaction) { LOG.trace( "before transaction completion" ); actionQueue.beforeTransactionCompletion(); try { interceptor.beforeTransactionCompletion( hibernateTransaction ); } catch (Throwable t) { LOG.exceptionInBeforeTransactionCompletionInterceptor( t ); } } @Override public void afterTransactionCompletion(TransactionImplementor hibernateTransaction, boolean successful) { LOG.trace( "after transaction completion" ); persistenceContext.afterTransactionCompletion(); actionQueue.afterTransactionCompletion( successful ); getEventListenerManager().transactionCompletion( successful ); try { interceptor.afterTransactionCompletion( hibernateTransaction ); } catch (Throwable t) { LOG.exceptionInAfterTransactionCompletionInterceptor( t ); } if ( autoClear ) { internalClear(); } } @Override public String onPrepareStatement(String sql) { errorIfClosed(); sql = interceptor.onPrepareStatement( sql ); if ( sql == null || sql.length() == 0 ) { throw new AssertionFailure( "Interceptor.onPrepareStatement() returned null or empty string." ); } return sql; } @Override public SessionEventListenerManagerImpl getEventListenerManager() { return sessionEventsManager; } @Override public void addEventListeners(SessionEventListener... listeners) { getEventListenerManager().addListener( listeners ); } @Override public void startPrepareStatement() { getEventListenerManager().jdbcPrepareStatementStart(); } @Override public void endPrepareStatement() { getEventListenerManager().jdbcPrepareStatementEnd(); } @Override public void startStatementExecution() { getEventListenerManager().jdbcExecuteStatementStart(); } @Override public void endStatementExecution() { getEventListenerManager().jdbcExecuteStatementEnd(); } @Override public void startBatchExecution() { getEventListenerManager().jdbcExecuteBatchStart(); } @Override public void endBatchExecution() { getEventListenerManager().jdbcExecuteBatchEnd(); } /** * clear all the internal collections, just * to help the garbage collector, does not * clear anything that is needed during the * afterTransactionCompletion() phase */ private void cleanup() { persistenceContext.clear(); } @Override public LockMode getCurrentLockMode(Object object) throws HibernateException { errorIfClosed(); checkTransactionSynchStatus(); if ( object == null ) { throw new NullPointerException( "null object passed to getCurrentLockMode()" ); } if ( object instanceof HibernateProxy ) { object = ( (HibernateProxy) object ).getHibernateLazyInitializer().getImplementation(this); if ( object == null ) { return LockMode.NONE; } } EntityEntry e = persistenceContext.getEntry(object); if ( e == null ) { throw new TransientObjectException( "Given object not associated with the session" ); } if ( e.getStatus() != Status.MANAGED ) { throw new ObjectDeletedException( "The given object was deleted", e.getId(), e.getPersister().getEntityName() ); } return e.getLockMode(); } @Override public Object getEntityUsingInterceptor(EntityKey key) throws HibernateException { errorIfClosed(); // todo : should this get moved to PersistentContext? // logically, is PersistentContext the "thing" to which an interceptor gets attached? final Object result = persistenceContext.getEntity(key); if ( result == null ) { final Object newObject = interceptor.getEntity( key.getEntityName(), key.getIdentifier() ); if ( newObject != null ) { lock( newObject, LockMode.NONE ); } return newObject; } else { return result; } } private void checkNoUnresolvedActionsBeforeOperation() { if ( persistenceContext.getCascadeLevel() == 0 && actionQueue.hasUnresolvedEntityInsertActions() ) { throw new IllegalStateException( "There are delayed insert actions before operation as cascade level 0." ); } } private void checkNoUnresolvedActionsAfterOperation() { if ( persistenceContext.getCascadeLevel() == 0 ) { actionQueue.checkNoUnresolvedActionsAfterOperation(); } delayedAfterCompletion(); } private void delayedAfterCompletion() { transactionCoordinator.getSynchronizationCallbackCoordinator().processAnyDelayedAfterCompletion(); } // saveOrUpdate() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public void saveOrUpdate(Object object) throws HibernateException { saveOrUpdate( null, object ); } @Override public void saveOrUpdate(String entityName, Object obj) throws HibernateException { fireSaveOrUpdate( new SaveOrUpdateEvent( entityName, obj, this ) ); } private void fireSaveOrUpdate(SaveOrUpdateEvent event) { errorIfClosed(); checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); for ( SaveOrUpdateEventListener listener : listeners( EventType.SAVE_UPDATE ) ) { listener.onSaveOrUpdate( event ); } checkNoUnresolvedActionsAfterOperation(); } private Iterable listeners(EventType type) { return eventListenerGroup( type ).listeners(); } private EventListenerGroup eventListenerGroup(EventType type) { return factory.getServiceRegistry().getService( EventListenerRegistry.class ).getEventListenerGroup( type ); } // save() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public Serializable save(Object obj) throws HibernateException { return save( null, obj ); } @Override public Serializable save(String entityName, Object object) throws HibernateException { return fireSave( new SaveOrUpdateEvent( entityName, object, this ) ); } private Serializable fireSave(SaveOrUpdateEvent event) { errorIfClosed(); checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); for ( SaveOrUpdateEventListener listener : listeners( EventType.SAVE ) ) { listener.onSaveOrUpdate( event ); } checkNoUnresolvedActionsAfterOperation(); return event.getResultId(); } // update() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public void update(Object obj) throws HibernateException { update( null, obj ); } @Override public void update(String entityName, Object object) throws HibernateException { fireUpdate( new SaveOrUpdateEvent( entityName, object, this ) ); } private void fireUpdate(SaveOrUpdateEvent event) { errorIfClosed(); checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); for ( SaveOrUpdateEventListener listener : listeners( EventType.UPDATE ) ) { listener.onSaveOrUpdate( event ); } checkNoUnresolvedActionsAfterOperation(); } // lock() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public void lock(String entityName, Object object, LockMode lockMode) throws HibernateException { fireLock( new LockEvent( entityName, object, lockMode, this ) ); } @Override public LockRequest buildLockRequest(LockOptions lockOptions) { return new LockRequestImpl(lockOptions); } @Override public void lock(Object object, LockMode lockMode) throws HibernateException { fireLock( new LockEvent( object, lockMode, this ) ); } private void fireLock(String entityName, Object object, LockOptions options) { fireLock( new LockEvent( entityName, object, options, this) ); } private void fireLock( Object object, LockOptions options) { fireLock( new LockEvent( object, options, this ) ); } private void fireLock(LockEvent event) { errorIfClosed(); checkTransactionSynchStatus(); for ( LockEventListener listener : listeners( EventType.LOCK ) ) { listener.onLock( event ); } delayedAfterCompletion(); } // persist() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public void persist(String entityName, Object object) throws HibernateException { firePersist( new PersistEvent( entityName, object, this ) ); } @Override public void persist(Object object) throws HibernateException { persist( null, object ); } @Override public void persist(String entityName, Object object, Map copiedAlready) throws HibernateException { firePersist( copiedAlready, new PersistEvent( entityName, object, this ) ); } private void firePersist(Map copiedAlready, PersistEvent event) { errorIfClosed(); checkTransactionSynchStatus(); for ( PersistEventListener listener : listeners( EventType.PERSIST ) ) { listener.onPersist( event, copiedAlready ); } delayedAfterCompletion(); } private void firePersist(PersistEvent event) { errorIfClosed(); checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); for ( PersistEventListener listener : listeners( EventType.PERSIST ) ) { listener.onPersist( event ); } checkNoUnresolvedActionsAfterOperation(); } // persistOnFlush() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public void persistOnFlush(String entityName, Object object) throws HibernateException { firePersistOnFlush( new PersistEvent( entityName, object, this ) ); } public void persistOnFlush(Object object) throws HibernateException { persist( null, object ); } @Override public void persistOnFlush(String entityName, Object object, Map copiedAlready) throws HibernateException { firePersistOnFlush( copiedAlready, new PersistEvent( entityName, object, this ) ); } private void firePersistOnFlush(Map copiedAlready, PersistEvent event) { errorIfClosed(); checkTransactionSynchStatus(); for ( PersistEventListener listener : listeners( EventType.PERSIST_ONFLUSH ) ) { listener.onPersist( event, copiedAlready ); } delayedAfterCompletion(); } private void firePersistOnFlush(PersistEvent event) { errorIfClosed(); checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); for ( PersistEventListener listener : listeners( EventType.PERSIST_ONFLUSH ) ) { listener.onPersist( event ); } checkNoUnresolvedActionsAfterOperation(); } // merge() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public Object merge(String entityName, Object object) throws HibernateException { return fireMerge( new MergeEvent( entityName, object, this ) ); } @Override public Object merge(Object object) throws HibernateException { return merge( null, object ); } @Override public void merge(String entityName, Object object, Map copiedAlready) throws HibernateException { fireMerge( copiedAlready, new MergeEvent( entityName, object, this ) ); } private Object fireMerge(MergeEvent event) { errorIfClosed(); checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); for ( MergeEventListener listener : listeners( EventType.MERGE ) ) { listener.onMerge( event ); } checkNoUnresolvedActionsAfterOperation(); return event.getResult(); } private void fireMerge(Map copiedAlready, MergeEvent event) { errorIfClosed(); checkTransactionSynchStatus(); for ( MergeEventListener listener : listeners( EventType.MERGE ) ) { listener.onMerge( event, copiedAlready ); } delayedAfterCompletion(); } // delete() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public void delete(Object object) throws HibernateException { fireDelete( new DeleteEvent( object, this ) ); } @Override public void delete(String entityName, Object object) throws HibernateException { fireDelete( new DeleteEvent( entityName, object, this ) ); } @Override public void delete(String entityName, Object object, boolean isCascadeDeleteEnabled, Set transientEntities) throws HibernateException { fireDelete( new DeleteEvent( entityName, object, isCascadeDeleteEnabled, this ), transientEntities ); } @Override public void removeOrphanBeforeUpdates(String entityName, Object child) { // TODO: The removeOrphan concept is a temporary "hack" for HHH-6484. This should be removed once action/task // ordering is improved. fireDelete( new DeleteEvent( entityName, child, false, true, this ) ); } private void fireDelete(DeleteEvent event) { errorIfClosed(); checkTransactionSynchStatus(); for ( DeleteEventListener listener : listeners( EventType.DELETE ) ) { listener.onDelete( event ); } delayedAfterCompletion(); } private void fireDelete(DeleteEvent event, Set transientEntities) { errorIfClosed(); checkTransactionSynchStatus(); for ( DeleteEventListener listener : listeners( EventType.DELETE ) ) { listener.onDelete( event, transientEntities ); } delayedAfterCompletion(); } // load()/get() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public void load(Object object, Serializable id) throws HibernateException { LoadEvent event = new LoadEvent(id, object, this); fireLoad( event, LoadEventListener.RELOAD ); } @Override public Object load(Class entityClass, Serializable id) throws HibernateException { return this.byId( entityClass ).getReference( id ); } @Override public Object load(String entityName, Serializable id) throws HibernateException { return this.byId( entityName ).getReference( id ); } @Override public Object get(Class entityClass, Serializable id) throws HibernateException { return this.byId( entityClass ).load( id ); } @Override public Object get(String entityName, Serializable id) throws HibernateException { return this.byId( entityName ).load( id ); } /** * Load the data for the object with the specified id into a newly created object. * This is only called when lazily initializing a proxy. * Do NOT return a proxy. */ @Override public Object immediateLoad(String entityName, Serializable id) throws HibernateException { if ( LOG.isDebugEnabled() ) { EntityPersister persister = getFactory().getEntityPersister(entityName); LOG.debugf( "Initializing proxy: %s", MessageHelper.infoString( persister, id, getFactory() ) ); } LoadEvent event = new LoadEvent(id, entityName, true, this); fireLoad(event, LoadEventListener.IMMEDIATE_LOAD); return event.getResult(); } @Override public Object internalLoad(String entityName, Serializable id, boolean eager, boolean nullable) throws HibernateException { // todo : remove LoadEventListener.LoadType type = nullable ? LoadEventListener.INTERNAL_LOAD_NULLABLE : eager ? LoadEventListener.INTERNAL_LOAD_EAGER : LoadEventListener.INTERNAL_LOAD_LAZY; LoadEvent event = new LoadEvent(id, entityName, true, this); fireLoad( event, type ); if ( !nullable ) { UnresolvableObjectException.throwIfNull( event.getResult(), id, entityName ); } return event.getResult(); } @Override public Object load(Class entityClass, Serializable id, LockMode lockMode) throws HibernateException { return this.byId( entityClass ).with( new LockOptions( lockMode ) ).getReference( id ); } @Override public Object load(Class entityClass, Serializable id, LockOptions lockOptions) throws HibernateException { return this.byId( entityClass ).with( lockOptions ).getReference( id ); } @Override public Object load(String entityName, Serializable id, LockMode lockMode) throws HibernateException { return this.byId( entityName ).with( new LockOptions( lockMode ) ).getReference( id ); } @Override public Object load(String entityName, Serializable id, LockOptions lockOptions) throws HibernateException { return this.byId( entityName ).with( lockOptions ).getReference( id ); } @Override public Object get(Class entityClass, Serializable id, LockMode lockMode) throws HibernateException { return this.byId( entityClass ).with( new LockOptions( lockMode ) ).load( id ); } @Override public Object get(Class entityClass, Serializable id, LockOptions lockOptions) throws HibernateException { return this.byId( entityClass ).with( lockOptions ).load( id ); } @Override public Object get(String entityName, Serializable id, LockMode lockMode) throws HibernateException { return this.byId( entityName ).with( new LockOptions( lockMode ) ).load( id ); } @Override public Object get(String entityName, Serializable id, LockOptions lockOptions) throws HibernateException { return this.byId( entityName ).with( lockOptions ).load( id ); } @Override public IdentifierLoadAccessImpl byId(String entityName) { return new IdentifierLoadAccessImpl( entityName ); } @Override public IdentifierLoadAccessImpl byId(Class entityClass) { return new IdentifierLoadAccessImpl( entityClass ); } @Override public NaturalIdLoadAccess byNaturalId(String entityName) { return new NaturalIdLoadAccessImpl( entityName ); } @Override public NaturalIdLoadAccess byNaturalId(Class entityClass) { return new NaturalIdLoadAccessImpl( entityClass ); } @Override public SimpleNaturalIdLoadAccess bySimpleNaturalId(String entityName) { return new SimpleNaturalIdLoadAccessImpl( entityName ); } @Override public SimpleNaturalIdLoadAccess bySimpleNaturalId(Class entityClass) { return new SimpleNaturalIdLoadAccessImpl( entityClass ); } private void fireLoad(LoadEvent event, LoadType loadType) { errorIfClosed(); checkTransactionSynchStatus(); for ( LoadEventListener listener : listeners( EventType.LOAD ) ) { listener.onLoad( event, loadType ); } delayedAfterCompletion(); } private void fireResolveNaturalId(ResolveNaturalIdEvent event) { errorIfClosed(); checkTransactionSynchStatus(); for ( ResolveNaturalIdEventListener listener : listeners( EventType.RESOLVE_NATURAL_ID ) ) { listener.onResolveNaturalId( event ); } delayedAfterCompletion(); } // refresh() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public void refresh(Object object) throws HibernateException { refresh( null, object ); } @Override public void refresh(String entityName, Object object) throws HibernateException { fireRefresh( new RefreshEvent( entityName, object, this ) ); } @Override public void refresh(Object object, LockMode lockMode) throws HibernateException { fireRefresh( new RefreshEvent( object, lockMode, this ) ); } @Override public void refresh(Object object, LockOptions lockOptions) throws HibernateException { refresh( null, object, lockOptions ); } @Override public void refresh(String entityName, Object object, LockOptions lockOptions) throws HibernateException { fireRefresh( new RefreshEvent( entityName, object, lockOptions, this ) ); } @Override public void refresh(String entityName, Object object, Map refreshedAlready) throws HibernateException { fireRefresh( refreshedAlready, new RefreshEvent( entityName, object, this ) ); } private void fireRefresh(RefreshEvent event) { errorIfClosed(); checkTransactionSynchStatus(); for ( RefreshEventListener listener : listeners( EventType.REFRESH ) ) { listener.onRefresh( event ); } delayedAfterCompletion(); } private void fireRefresh(Map refreshedAlready, RefreshEvent event) { errorIfClosed(); checkTransactionSynchStatus(); for ( RefreshEventListener listener : listeners( EventType.REFRESH ) ) { listener.onRefresh( event, refreshedAlready ); } delayedAfterCompletion(); } // replicate() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public void replicate(Object obj, ReplicationMode replicationMode) throws HibernateException { fireReplicate( new ReplicateEvent( obj, replicationMode, this ) ); } @Override public void replicate(String entityName, Object obj, ReplicationMode replicationMode) throws HibernateException { fireReplicate( new ReplicateEvent( entityName, obj, replicationMode, this ) ); } private void fireReplicate(ReplicateEvent event) { errorIfClosed(); checkTransactionSynchStatus(); for ( ReplicateEventListener listener : listeners( EventType.REPLICATE ) ) { listener.onReplicate( event ); } delayedAfterCompletion(); } // evict() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** * remove any hard references to the entity that are held by the infrastructure * (references held by application or other persistent instances are okay) */ @Override public void evict(Object object) throws HibernateException { fireEvict( new EvictEvent( object, this ) ); } private void fireEvict(EvictEvent event) { errorIfClosed(); checkTransactionSynchStatus(); for ( EvictEventListener listener : listeners( EventType.EVICT ) ) { listener.onEvict( event ); } delayedAfterCompletion(); } /** * detect in-memory changes, determine if the changes are to tables * named in the query and, if so, complete execution the flush */ protected boolean autoFlushIfRequired(Set querySpaces) throws HibernateException { errorIfClosed(); if ( ! isTransactionInProgress() ) { // do not auto-flush while outside a transaction return false; } AutoFlushEvent event = new AutoFlushEvent( querySpaces, this ); for ( AutoFlushEventListener listener : listeners( EventType.AUTO_FLUSH ) ) { listener.onAutoFlush( event ); } return event.isFlushRequired(); } @Override public boolean isDirty() throws HibernateException { errorIfClosed(); checkTransactionSynchStatus(); LOG.debug( "Checking session dirtiness" ); if ( actionQueue.areInsertionsOrDeletionsQueued() ) { LOG.debug( "Session dirty (scheduled updates and insertions)" ); return true; } DirtyCheckEvent event = new DirtyCheckEvent( this ); for ( DirtyCheckEventListener listener : listeners( EventType.DIRTY_CHECK ) ) { listener.onDirtyCheck( event ); } delayedAfterCompletion(); return event.isDirty(); } @Override public void flush() throws HibernateException { errorIfClosed(); checkTransactionSynchStatus(); if ( persistenceContext.getCascadeLevel() > 0 ) { throw new HibernateException("Flush during cascade is dangerous"); } FlushEvent flushEvent = new FlushEvent( this ); for ( FlushEventListener listener : listeners( EventType.FLUSH ) ) { listener.onFlush( flushEvent ); } delayedAfterCompletion(); } @Override public void forceFlush(EntityEntry entityEntry) throws HibernateException { errorIfClosed(); if ( LOG.isDebugEnabled() ) { LOG.debugf( "Flushing to force deletion of re-saved object: %s", MessageHelper.infoString( entityEntry.getPersister(), entityEntry.getId(), getFactory() ) ); } if ( persistenceContext.getCascadeLevel() > 0 ) { throw new ObjectDeletedException( "deleted object would be re-saved by cascade (remove deleted object from associations)", entityEntry.getId(), entityEntry.getPersister().getEntityName() ); } flush(); } @Override public List list(String query, QueryParameters queryParameters) throws HibernateException { errorIfClosed(); checkTransactionSynchStatus(); queryParameters.validateParameters(); HQLQueryPlan plan = queryParameters.getQueryPlan(); if (plan == null) { plan = getHQLQueryPlan( query, false ); } autoFlushIfRequired( plan.getQuerySpaces() ); List results = Collections.EMPTY_LIST; boolean success = false; dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called try { results = plan.performList( queryParameters, this ); success = true; } finally { dontFlushFromFind--; afterOperation(success); delayedAfterCompletion(); } return results; } @Override public int executeUpdate(String query, QueryParameters queryParameters) throws HibernateException { errorIfClosed(); checkTransactionSynchStatus(); queryParameters.validateParameters(); HQLQueryPlan plan = getHQLQueryPlan( query, false ); autoFlushIfRequired( plan.getQuerySpaces() ); boolean success = false; int result = 0; try { result = plan.performExecuteUpdate( queryParameters, this ); success = true; } finally { afterOperation(success); delayedAfterCompletion(); } return result; } @Override public int executeNativeUpdate(NativeSQLQuerySpecification nativeQuerySpecification, QueryParameters queryParameters) throws HibernateException { errorIfClosed(); checkTransactionSynchStatus(); queryParameters.validateParameters(); NativeSQLQueryPlan plan = getNativeSQLQueryPlan( nativeQuerySpecification ); autoFlushIfRequired( plan.getCustomQuery().getQuerySpaces() ); boolean success = false; int result = 0; try { result = plan.performExecuteUpdate(queryParameters, this); success = true; } finally { afterOperation(success); delayedAfterCompletion(); } return result; } @Override public Iterator iterate(String query, QueryParameters queryParameters) throws HibernateException { errorIfClosed(); checkTransactionSynchStatus(); queryParameters.validateParameters(); HQLQueryPlan plan = getHQLQueryPlan( query, true ); autoFlushIfRequired( plan.getQuerySpaces() ); dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called try { return plan.performIterate( queryParameters, this ); } finally { delayedAfterCompletion(); dontFlushFromFind--; } } @Override public ScrollableResults scroll(String query, QueryParameters queryParameters) throws HibernateException { errorIfClosed(); checkTransactionSynchStatus(); HQLQueryPlan plan = getHQLQueryPlan( query, false ); autoFlushIfRequired( plan.getQuerySpaces() ); dontFlushFromFind++; try { return plan.performScroll( queryParameters, this ); } finally { delayedAfterCompletion(); dontFlushFromFind--; } } @Override public Query createFilter(Object collection, String queryString) { errorIfClosed(); checkTransactionSynchStatus(); CollectionFilterImpl filter = new CollectionFilterImpl( queryString, collection, this, getFilterQueryPlan( collection, queryString, null, false ).getParameterMetadata() ); filter.setComment( queryString ); delayedAfterCompletion(); return filter; } @Override public Query getNamedQuery(String queryName) throws MappingException { errorIfClosed(); checkTransactionSynchStatus(); Query query = super.getNamedQuery( queryName ); delayedAfterCompletion(); return query; } @Override public Object instantiate(String entityName, Serializable id) throws HibernateException { return instantiate( factory.getEntityPersister( entityName ), id ); } /** * give the interceptor an opportunity to override the default instantiation */ @Override public Object instantiate(EntityPersister persister, Serializable id) throws HibernateException { errorIfClosed(); checkTransactionSynchStatus(); Object result = interceptor.instantiate( persister.getEntityName(), persister.getEntityMetamodel().getEntityMode(), id ); if ( result == null ) { result = persister.instantiate( id, this ); } delayedAfterCompletion(); return result; } @Override public void setFlushMode(FlushMode flushMode) { errorIfClosed(); checkTransactionSynchStatus(); LOG.tracev( "Setting flush mode to: {0}", flushMode ); this.flushMode = flushMode; } @Override public FlushMode getFlushMode() { checkTransactionSynchStatus(); return flushMode; } @Override public CacheMode getCacheMode() { checkTransactionSynchStatus(); return cacheMode; } @Override public void setCacheMode(CacheMode cacheMode) { errorIfClosed(); checkTransactionSynchStatus(); LOG.tracev( "Setting cache mode to: {0}", cacheMode ); this.cacheMode= cacheMode; } @Override public Transaction getTransaction() throws HibernateException { errorIfClosed(); return transactionCoordinator.getTransaction(); } @Override public Transaction beginTransaction() throws HibernateException { errorIfClosed(); Transaction result = getTransaction(); result.begin(); return result; } @Override public EntityPersister getEntityPersister(final String entityName, final Object object) { errorIfClosed(); if (entityName==null) { return factory.getEntityPersister( guessEntityName( object ) ); } else { // try block is a hack around fact that currently tuplizers are not // given the opportunity to resolve a subclass entity name. this // allows the (we assume custom) interceptor the ability to // influence this decision if we were not able to based on the // given entityName try { return factory.getEntityPersister( entityName ).getSubclassEntityPersister( object, getFactory() ); } catch( HibernateException e ) { try { return getEntityPersister( null, object ); } catch( HibernateException e2 ) { throw e; } } } } // not for internal use: @Override public Serializable getIdentifier(Object object) throws HibernateException { errorIfClosed(); checkTransactionSynchStatus(); if ( object instanceof HibernateProxy ) { LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer(); if ( li.getSession() != this ) { throw new TransientObjectException( "The proxy was not associated with this session" ); } return li.getIdentifier(); } else { EntityEntry entry = persistenceContext.getEntry(object); if ( entry == null ) { throw new TransientObjectException( "The instance was not associated with this session" ); } return entry.getId(); } } /** * Get the id value for an object that is actually associated with the session. This * is a bit stricter than getEntityIdentifierIfNotUnsaved(). */ @Override public Serializable getContextEntityIdentifier(Object object) { errorIfClosed(); if ( object instanceof HibernateProxy ) { return getProxyIdentifier( object ); } else { EntityEntry entry = persistenceContext.getEntry(object); return entry != null ? entry.getId() : null; } } private Serializable getProxyIdentifier(Object proxy) { return ( (HibernateProxy) proxy ).getHibernateLazyInitializer().getIdentifier(); } private FilterQueryPlan getFilterQueryPlan( Object collection, String filter, QueryParameters parameters, boolean shallow) throws HibernateException { if ( collection == null ) { throw new NullPointerException( "null collection passed to filter" ); } CollectionEntry entry = persistenceContext.getCollectionEntryOrNull( collection ); final CollectionPersister roleBeforeFlush = (entry == null) ? null : entry.getLoadedPersister(); FilterQueryPlan plan = null; if ( roleBeforeFlush == null ) { // if it was previously unreferenced, we need to flush in order to // get its state into the database in order to execute query flush(); entry = persistenceContext.getCollectionEntryOrNull( collection ); CollectionPersister roleAfterFlush = (entry == null) ? null : entry.getLoadedPersister(); if ( roleAfterFlush == null ) { throw new QueryException( "The collection was unreferenced" ); } plan = factory.getQueryPlanCache().getFilterQueryPlan( filter, roleAfterFlush.getRole(), shallow, getEnabledFilters() ); } else { // otherwise, we only need to flush if there are in-memory changes // to the queried tables plan = factory.getQueryPlanCache().getFilterQueryPlan( filter, roleBeforeFlush.getRole(), shallow, getEnabledFilters() ); if ( autoFlushIfRequired( plan.getQuerySpaces() ) ) { // might need to run a different filter entirely after the flush // because the collection role may have changed entry = persistenceContext.getCollectionEntryOrNull( collection ); CollectionPersister roleAfterFlush = (entry == null) ? null : entry.getLoadedPersister(); if ( roleBeforeFlush != roleAfterFlush ) { if ( roleAfterFlush == null ) { throw new QueryException( "The collection was dereferenced" ); } plan = factory.getQueryPlanCache().getFilterQueryPlan( filter, roleAfterFlush.getRole(), shallow, getEnabledFilters() ); } } } if ( parameters != null ) { parameters.getPositionalParameterValues()[0] = entry.getLoadedKey(); parameters.getPositionalParameterTypes()[0] = entry.getLoadedPersister().getKeyType(); } return plan; } @Override public List listFilter(Object collection, String filter, QueryParameters queryParameters) throws HibernateException { errorIfClosed(); checkTransactionSynchStatus(); FilterQueryPlan plan = getFilterQueryPlan( collection, filter, queryParameters, false ); List results = Collections.EMPTY_LIST; boolean success = false; dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called try { results = plan.performList( queryParameters, this ); success = true; } finally { dontFlushFromFind--; afterOperation(success); delayedAfterCompletion(); } return results; } @Override public Iterator iterateFilter(Object collection, String filter, QueryParameters queryParameters) throws HibernateException { errorIfClosed(); checkTransactionSynchStatus(); FilterQueryPlan plan = getFilterQueryPlan( collection, filter, queryParameters, true ); Iterator itr = plan.performIterate( queryParameters, this ); delayedAfterCompletion(); return itr; } @Override public Criteria createCriteria(Class persistentClass, String alias) { errorIfClosed(); checkTransactionSynchStatus(); return new CriteriaImpl( persistentClass.getName(), alias, this ); } @Override public Criteria createCriteria(String entityName, String alias) { errorIfClosed(); checkTransactionSynchStatus(); return new CriteriaImpl(entityName, alias, this); } @Override public Criteria createCriteria(Class persistentClass) { errorIfClosed(); checkTransactionSynchStatus(); return new CriteriaImpl( persistentClass.getName(), this ); } @Override public Criteria createCriteria(String entityName) { errorIfClosed(); checkTransactionSynchStatus(); return new CriteriaImpl(entityName, this); } @Override public ScrollableResults scroll(Criteria criteria, ScrollMode scrollMode) { // TODO: Is this guaranteed to always be CriteriaImpl? CriteriaImpl criteriaImpl = (CriteriaImpl) criteria; errorIfClosed(); checkTransactionSynchStatus(); String entityName = criteriaImpl.getEntityOrClassName(); CriteriaLoader loader = new CriteriaLoader( getOuterJoinLoadable(entityName), factory, criteriaImpl, entityName, getLoadQueryInfluencers() ); autoFlushIfRequired( loader.getQuerySpaces() ); dontFlushFromFind++; try { return loader.scroll(this, scrollMode); } finally { delayedAfterCompletion(); dontFlushFromFind--; } } @Override public List list(Criteria criteria) throws HibernateException { // TODO: Is this guaranteed to always be CriteriaImpl? CriteriaImpl criteriaImpl = (CriteriaImpl) criteria; final NaturalIdLoadAccess naturalIdLoadAccess = this.tryNaturalIdLoadAccess( criteriaImpl ); if ( naturalIdLoadAccess != null ) { // EARLY EXIT! return Arrays.asList( naturalIdLoadAccess.load() ); } errorIfClosed(); checkTransactionSynchStatus(); String[] implementors = factory.getImplementors( criteriaImpl.getEntityOrClassName() ); int size = implementors.length; CriteriaLoader[] loaders = new CriteriaLoader[size]; Set spaces = new HashSet(); for( int i=0; i naturalIdValues = naturalIdentifier.getNaturalIdValues(); final int[] naturalIdentifierProperties = entityPersister.getNaturalIdentifierProperties(); // Verify the NaturalIdentifier criterion includes all naturalId properties, first check that the property counts match if ( naturalIdentifierProperties.length != naturalIdValues.size() ) { return null; } final String[] propertyNames = entityPersister.getPropertyNames(); final NaturalIdLoadAccess naturalIdLoader = this.byNaturalId( entityName ); // Build NaturalIdLoadAccess and in the process verify all naturalId properties were specified for ( int i = 0; i < naturalIdentifierProperties.length; i++ ) { final String naturalIdProperty = propertyNames[naturalIdentifierProperties[i]]; final Object naturalIdValue = naturalIdValues.get( naturalIdProperty ); if ( naturalIdValue == null ) { // A NaturalId property is missing from the critera query, can't use NaturalIdLoadAccess return null; } naturalIdLoader.using( naturalIdProperty, naturalIdValue ); } // Critera query contains a valid naturalId, use the new API LOG.warn( "Session.byNaturalId(" + entityName + ") should be used for naturalId queries instead of Restrictions.naturalId() from a Criteria" ); return naturalIdLoader; } private OuterJoinLoadable getOuterJoinLoadable(String entityName) throws MappingException { EntityPersister persister = factory.getEntityPersister(entityName); if ( !(persister instanceof OuterJoinLoadable) ) { throw new MappingException( "class persister is not OuterJoinLoadable: " + entityName ); } return ( OuterJoinLoadable ) persister; } @Override public boolean contains(Object object) { errorIfClosed(); checkTransactionSynchStatus(); if ( object instanceof HibernateProxy ) { //do not use proxiesByKey, since not all //proxies that point to this session's //instances are in that collection! LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer(); if ( li.isUninitialized() ) { //if it is an uninitialized proxy, pointing //with this session, then when it is accessed, //the underlying instance will be "contained" return li.getSession()==this; } else { //if it is initialized, see if the underlying //instance is contained, since we need to //account for the fact that it might have been //evicted object = li.getImplementation(); } } // A session is considered to contain an entity only if the entity has // an entry in the session's persistence context and the entry reports // that the entity has not been removed EntityEntry entry = persistenceContext.getEntry( object ); delayedAfterCompletion(); return entry != null && entry.getStatus() != Status.DELETED && entry.getStatus() != Status.GONE; } @Override public Query createQuery(String queryString) { errorIfClosed(); checkTransactionSynchStatus(); return super.createQuery( queryString ); } @Override public SQLQuery createSQLQuery(String sql) { errorIfClosed(); checkTransactionSynchStatus(); return super.createSQLQuery( sql ); } @Override public ProcedureCall createStoredProcedureCall(String procedureName) { errorIfClosed(); checkTransactionSynchStatus(); return super.createStoredProcedureCall( procedureName ); } @Override public ProcedureCall createStoredProcedureCall(String procedureName, String... resultSetMappings) { errorIfClosed(); checkTransactionSynchStatus(); return super.createStoredProcedureCall( procedureName, resultSetMappings ); } @Override public ProcedureCall createStoredProcedureCall(String procedureName, Class... resultClasses) { errorIfClosed(); checkTransactionSynchStatus(); return super.createStoredProcedureCall( procedureName, resultClasses ); } @Override public ScrollableResults scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) throws HibernateException { errorIfClosed(); checkTransactionSynchStatus(); if ( LOG.isTraceEnabled() ) { LOG.tracev( "Scroll SQL query: {0}", customQuery.getSQL() ); } CustomLoader loader = new CustomLoader( customQuery, getFactory() ); autoFlushIfRequired( loader.getQuerySpaces() ); dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called try { return loader.scroll(queryParameters, this); } finally { delayedAfterCompletion(); dontFlushFromFind--; } } // basically just an adapted copy of find(CriteriaImpl) @Override public List listCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) throws HibernateException { errorIfClosed(); checkTransactionSynchStatus(); if ( LOG.isTraceEnabled() ) { LOG.tracev( "SQL query: {0}", customQuery.getSQL() ); } CustomLoader loader = new CustomLoader( customQuery, getFactory() ); autoFlushIfRequired( loader.getQuerySpaces() ); dontFlushFromFind++; boolean success = false; try { List results = loader.list(this, queryParameters); success = true; return results; } finally { dontFlushFromFind--; delayedAfterCompletion(); afterOperation(success); } } @Override public SessionFactoryImplementor getSessionFactory() { checkTransactionSynchStatus(); return factory; } @Override public void initializeCollection(PersistentCollection collection, boolean writing) throws HibernateException { errorIfClosed(); checkTransactionSynchStatus(); InitializeCollectionEvent event = new InitializeCollectionEvent( collection, this ); for ( InitializeCollectionEventListener listener : listeners( EventType.INIT_COLLECTION ) ) { listener.onInitializeCollection( event ); } delayedAfterCompletion(); } @Override public String bestGuessEntityName(Object object) { if (object instanceof HibernateProxy) { LazyInitializer initializer = ( ( HibernateProxy ) object ).getHibernateLazyInitializer(); // it is possible for this method to be called during flush processing, // so make certain that we do not accidentally initialize an uninitialized proxy if ( initializer.isUninitialized() ) { return initializer.getEntityName(); } object = initializer.getImplementation(); } EntityEntry entry = persistenceContext.getEntry(object); if (entry==null) { return guessEntityName(object); } else { return entry.getPersister().getEntityName(); } } @Override public String getEntityName(Object object) { errorIfClosed(); checkTransactionSynchStatus(); if (object instanceof HibernateProxy) { if ( !persistenceContext.containsProxy( object ) ) { throw new TransientObjectException("proxy was not associated with the session"); } object = ( (HibernateProxy) object ).getHibernateLazyInitializer().getImplementation(); } EntityEntry entry = persistenceContext.getEntry(object); if ( entry == null ) { throwTransientObjectException( object ); } return entry.getPersister().getEntityName(); } private void throwTransientObjectException(Object object) throws HibernateException { throw new TransientObjectException( "object references an unsaved transient instance - save the transient instance before flushing: " + guessEntityName(object) ); } @Override public String guessEntityName(Object object) throws HibernateException { errorIfClosed(); return entityNameResolver.resolveEntityName( object ); } @Override public void cancelQuery() throws HibernateException { errorIfClosed(); getTransactionCoordinator().getJdbcCoordinator().cancelLastQuery(); } @Override public Interceptor getInterceptor() { checkTransactionSynchStatus(); return interceptor; } @Override public int getDontFlushFromFind() { return dontFlushFromFind; } @Override public String toString() { StringBuilder buf = new StringBuilder(500) .append( "SessionImpl(" ); if ( !isClosed() ) { buf.append(persistenceContext) .append(";") .append(actionQueue); } else { buf.append(""); } return buf.append(')').toString(); } @Override public ActionQueue getActionQueue() { errorIfClosed(); checkTransactionSynchStatus(); return actionQueue; } @Override public PersistenceContext getPersistenceContext() { errorIfClosed(); checkTransactionSynchStatus(); return persistenceContext; } @Override public SessionStatistics getStatistics() { checkTransactionSynchStatus(); return new SessionStatisticsImpl(this); } @Override public boolean isEventSource() { checkTransactionSynchStatus(); return true; } @Override public boolean isDefaultReadOnly() { return persistenceContext.isDefaultReadOnly(); } @Override public void setDefaultReadOnly(boolean defaultReadOnly) { persistenceContext.setDefaultReadOnly( defaultReadOnly ); } @Override public boolean isReadOnly(Object entityOrProxy) { errorIfClosed(); checkTransactionSynchStatus(); return persistenceContext.isReadOnly( entityOrProxy ); } @Override public void setReadOnly(Object entity, boolean readOnly) { errorIfClosed(); checkTransactionSynchStatus(); persistenceContext.setReadOnly( entity, readOnly ); } @Override public void doWork(final Work work) throws HibernateException { WorkExecutorVisitable realWork = new WorkExecutorVisitable() { @Override public Void accept(WorkExecutor workExecutor, Connection connection) throws SQLException { workExecutor.executeWork( work, connection ); return null; } }; doWork( realWork ); } @Override public T doReturningWork(final ReturningWork work) throws HibernateException { WorkExecutorVisitable realWork = new WorkExecutorVisitable() { @Override public T accept(WorkExecutor workExecutor, Connection connection) throws SQLException { return workExecutor.executeReturningWork( work, connection ); } }; return doWork( realWork ); } private T doWork(WorkExecutorVisitable work) throws HibernateException { return transactionCoordinator.getJdbcCoordinator().coordinateWork( work ); } @Override public void afterScrollOperation() { // nothing to do in a stateful session } @Override public TransactionCoordinator getTransactionCoordinator() { errorIfClosed(); return transactionCoordinator; } @Override public LoadQueryInfluencers getLoadQueryInfluencers() { return loadQueryInfluencers; } // filter support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public Filter getEnabledFilter(String filterName) { checkTransactionSynchStatus(); return loadQueryInfluencers.getEnabledFilter( filterName ); } @Override public Filter enableFilter(String filterName) { errorIfClosed(); checkTransactionSynchStatus(); return loadQueryInfluencers.enableFilter( filterName ); } @Override public void disableFilter(String filterName) { errorIfClosed(); checkTransactionSynchStatus(); loadQueryInfluencers.disableFilter( filterName ); } @Override public Object getFilterParameterValue(String filterParameterName) { errorIfClosed(); checkTransactionSynchStatus(); return loadQueryInfluencers.getFilterParameterValue( filterParameterName ); } @Override public Type getFilterParameterType(String filterParameterName) { errorIfClosed(); checkTransactionSynchStatus(); return loadQueryInfluencers.getFilterParameterType( filterParameterName ); } @Override public Map getEnabledFilters() { errorIfClosed(); checkTransactionSynchStatus(); return loadQueryInfluencers.getEnabledFilters(); } // internal fetch profile support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public String getFetchProfile() { checkTransactionSynchStatus(); return loadQueryInfluencers.getInternalFetchProfile(); } @Override public void setFetchProfile(String fetchProfile) { errorIfClosed(); checkTransactionSynchStatus(); loadQueryInfluencers.setInternalFetchProfile( fetchProfile ); } // fetch profile support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public boolean isFetchProfileEnabled(String name) throws UnknownProfileException { return loadQueryInfluencers.isFetchProfileEnabled( name ); } @Override public void enableFetchProfile(String name) throws UnknownProfileException { loadQueryInfluencers.enableFetchProfile( name ); } @Override public void disableFetchProfile(String name) throws UnknownProfileException { loadQueryInfluencers.disableFetchProfile( name ); } private void checkTransactionSynchStatus() { pulseTransactionCoordinator(); delayedAfterCompletion(); } private void pulseTransactionCoordinator() { if ( !isClosed() ) { transactionCoordinator.pulse(); } } /** * Used by JDK serialization... * * @param ois The input stream from which we are being read... * @throws IOException Indicates a general IO stream exception * @throws ClassNotFoundException Indicates a class resolution issue */ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { LOG.trace( "Deserializing session" ); ois.defaultReadObject(); entityNameResolver = new CoordinatingEntityNameResolver(); connectionReleaseMode = ConnectionReleaseMode.parse( ( String ) ois.readObject() ); autoClear = ois.readBoolean(); autoJoinTransactions = ois.readBoolean(); flushMode = FlushMode.valueOf( ( String ) ois.readObject() ); cacheMode = CacheMode.valueOf( ( String ) ois.readObject() ); flushBeforeCompletionEnabled = ois.readBoolean(); autoCloseSessionEnabled = ois.readBoolean(); interceptor = ( Interceptor ) ois.readObject(); factory = SessionFactoryImpl.deserialize( ois ); sessionOwner = ( SessionOwner ) ois.readObject(); transactionCoordinator = TransactionCoordinatorImpl.deserialize( ois, this ); persistenceContext = StatefulPersistenceContext.deserialize( ois, this ); actionQueue = ActionQueue.deserialize( ois, this ); loadQueryInfluencers = (LoadQueryInfluencers) ois.readObject(); // LoadQueryInfluencers.getEnabledFilters() tries to validate each enabled // filter, which will fail when called before FilterImpl.afterDeserialize( factory ); // Instead lookup the filter by name and then call FilterImpl.afterDeserialize( factory ). for ( String filterName : loadQueryInfluencers.getEnabledFilterNames() ) { ((FilterImpl) loadQueryInfluencers.getEnabledFilter( filterName )).afterDeserialize( factory ); } } /** * Used by JDK serialization... * * @param oos The output stream to which we are being written... * @throws IOException Indicates a general IO stream exception */ private void writeObject(ObjectOutputStream oos) throws IOException { if ( ! transactionCoordinator.getJdbcCoordinator().isReadyForSerialization() ) { throw new IllegalStateException( "Cannot serialize a session while connected" ); } LOG.trace( "Serializing session" ); oos.defaultWriteObject(); oos.writeObject( connectionReleaseMode.toString() ); oos.writeBoolean( autoClear ); oos.writeBoolean( autoJoinTransactions ); oos.writeObject( flushMode.toString() ); oos.writeObject( cacheMode.name() ); oos.writeBoolean( flushBeforeCompletionEnabled ); oos.writeBoolean( autoCloseSessionEnabled ); // we need to writeObject() on this since interceptor is user defined oos.writeObject( interceptor ); factory.serialize( oos ); oos.writeObject( sessionOwner ); transactionCoordinator.serialize( oos ); persistenceContext.serialize( oos ); actionQueue.serialize( oos ); // todo : look at optimizing these... oos.writeObject( loadQueryInfluencers ); } @Override public TypeHelper getTypeHelper() { return getSessionFactory().getTypeHelper(); } @Override public LobHelper getLobHelper() { if ( lobHelper == null ) { lobHelper = new LobHelperImpl( this ); } return lobHelper; } private transient LobHelperImpl lobHelper; private static class LobHelperImpl implements LobHelper { private final SessionImpl session; private LobHelperImpl(SessionImpl session) { this.session = session; } @Override public Blob createBlob(byte[] bytes) { return lobCreator().createBlob( bytes ); } private LobCreator lobCreator() { // Always use NonContextualLobCreator. If ContextualLobCreator is // used both here and in WrapperOptions, return NonContextualLobCreator.INSTANCE; } @Override public Blob createBlob(InputStream stream, long length) { return lobCreator().createBlob( stream, length ); } @Override public Clob createClob(String string) { return lobCreator().createClob( string ); } @Override public Clob createClob(Reader reader, long length) { return lobCreator().createClob( reader, length ); } @Override public NClob createNClob(String string) { return lobCreator().createNClob( string ); } @Override public NClob createNClob(Reader reader, long length) { return lobCreator().createNClob( reader, length ); } } private static class SharedSessionBuilderImpl extends SessionFactoryImpl.SessionBuilderImpl implements SharedSessionBuilder { private final SessionImpl session; private boolean shareTransactionContext; private SharedSessionBuilderImpl(SessionImpl session) { super( session.factory ); this.session = session; super.owner( session.sessionOwner ); super.tenantIdentifier( session.getTenantIdentifier() ); } @Override public SessionBuilder tenantIdentifier(String tenantIdentifier) { // todo : is this always true? Or just in the case of sharing JDBC resources? throw new SessionException( "Cannot redefine tenant identifier on child session" ); } @Override protected TransactionCoordinatorImpl getTransactionCoordinator() { return shareTransactionContext ? session.transactionCoordinator : super.getTransactionCoordinator(); } @Override protected ActionQueue.TransactionCompletionProcesses getTransactionCompletionProcesses() { return shareTransactionContext ? session.getActionQueue().getTransactionCompletionProcesses() : super.getTransactionCompletionProcesses(); } @Override public SharedSessionBuilder interceptor() { return interceptor( session.interceptor ); } @Override public SharedSessionBuilder connection() { this.shareTransactionContext = true; return this; } @Override public SharedSessionBuilder connectionReleaseMode() { return connectionReleaseMode( session.connectionReleaseMode ); } @Override public SharedSessionBuilder autoJoinTransactions() { return autoJoinTransactions( session.autoJoinTransactions ); } @Override public SharedSessionBuilder autoClose() { return autoClose( session.autoCloseSessionEnabled ); } @Override public SharedSessionBuilder flushBeforeCompletion() { return flushBeforeCompletion( session.flushBeforeCompletionEnabled ); } /** * @deprecated Use {@link #connection()} instead */ @Override @Deprecated public SharedSessionBuilder transactionContext() { return connection(); } @Override public SharedSessionBuilder interceptor(Interceptor interceptor) { return (SharedSessionBuilder) super.interceptor( interceptor ); } @Override public SharedSessionBuilder noInterceptor() { return (SharedSessionBuilder) super.noInterceptor(); } @Override public SharedSessionBuilder connection(Connection connection) { return (SharedSessionBuilder) super.connection( connection ); } @Override public SharedSessionBuilder connectionReleaseMode(ConnectionReleaseMode connectionReleaseMode) { return (SharedSessionBuilder) super.connectionReleaseMode( connectionReleaseMode ); } @Override public SharedSessionBuilder autoJoinTransactions(boolean autoJoinTransactions) { return (SharedSessionBuilder) super.autoJoinTransactions( autoJoinTransactions ); } @Override public SharedSessionBuilder autoClose(boolean autoClose) { return (SharedSessionBuilder) super.autoClose( autoClose ); } @Override public SharedSessionBuilder flushBeforeCompletion(boolean flushBeforeCompletion) { return (SharedSessionBuilder) super.flushBeforeCompletion( flushBeforeCompletion ); } @Override public SharedSessionBuilder eventListeners(SessionEventListener... listeners) { super.eventListeners( listeners ); return this; } @Override public SessionBuilder clearEventListeners() { super.clearEventListeners(); return this; } } private class CoordinatingEntityNameResolver implements EntityNameResolver { @Override public String resolveEntityName(Object entity) { String entityName = interceptor.getEntityName( entity ); if ( entityName != null ) { return entityName; } for ( EntityNameResolver resolver : factory.iterateEntityNameResolvers() ) { entityName = resolver.resolveEntityName( entity ); if ( entityName != null ) { break; } } if ( entityName != null ) { return entityName; } // the old-time stand-by... return entity.getClass().getName(); } } private class LockRequestImpl implements LockRequest { private final LockOptions lockOptions; private LockRequestImpl(LockOptions lo) { lockOptions = new LockOptions(); LockOptions.copy(lo, lockOptions); } @Override public LockMode getLockMode() { return lockOptions.getLockMode(); } @Override public LockRequest setLockMode(LockMode lockMode) { lockOptions.setLockMode(lockMode); return this; } @Override public int getTimeOut() { return lockOptions.getTimeOut(); } @Override public LockRequest setTimeOut(int timeout) { lockOptions.setTimeOut(timeout); return this; } @Override public boolean getScope() { return lockOptions.getScope(); } @Override public LockRequest setScope(boolean scope) { lockOptions.setScope(scope); return this; } @Override public void lock(String entityName, Object object) throws HibernateException { fireLock( entityName, object, lockOptions ); } @Override public void lock(Object object) throws HibernateException { fireLock( object, lockOptions ); } } private class IdentifierLoadAccessImpl implements IdentifierLoadAccess { private final EntityPersister entityPersister; private LockOptions lockOptions; private IdentifierLoadAccessImpl(EntityPersister entityPersister) { this.entityPersister = entityPersister; } private IdentifierLoadAccessImpl(String entityName) { this( locateEntityPersister( entityName ) ); } private IdentifierLoadAccessImpl(Class entityClass) { this( entityClass.getName() ); } @Override public final IdentifierLoadAccessImpl with(LockOptions lockOptions) { this.lockOptions = lockOptions; return this; } @Override public final Object getReference(Serializable id) { if ( this.lockOptions != null ) { LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), lockOptions, SessionImpl.this ); fireLoad( event, LoadEventListener.LOAD ); return event.getResult(); } LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), false, SessionImpl.this ); boolean success = false; try { fireLoad( event, LoadEventListener.LOAD ); if ( event.getResult() == null ) { getFactory().getEntityNotFoundDelegate().handleEntityNotFound( entityPersister.getEntityName(), id ); } success = true; return event.getResult(); } finally { afterOperation( success ); } } @Override public final Object load(Serializable id) { if ( this.lockOptions != null ) { LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), lockOptions, SessionImpl.this ); fireLoad( event, LoadEventListener.GET ); return event.getResult(); } LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), false, SessionImpl.this ); boolean success = false; try { fireLoad( event, LoadEventListener.GET ); success = true; } catch (ObjectNotFoundException e) { // if session cache contains proxy for non-existing object } finally { afterOperation( success ); } return event.getResult(); } } private EntityPersister locateEntityPersister(String entityName) { final EntityPersister entityPersister = factory.getEntityPersister( entityName ); if ( entityPersister == null ) { throw new HibernateException( "Unable to locate persister: " + entityName ); } return entityPersister; } private abstract class BaseNaturalIdLoadAccessImpl { private final EntityPersister entityPersister; private LockOptions lockOptions; private boolean synchronizationEnabled = true; private BaseNaturalIdLoadAccessImpl(EntityPersister entityPersister) { this.entityPersister = entityPersister; if ( ! entityPersister.hasNaturalIdentifier() ) { throw new HibernateException( String.format( "Entity [%s] did not define a natural id", entityPersister.getEntityName() ) ); } } private BaseNaturalIdLoadAccessImpl(String entityName) { this( locateEntityPersister( entityName ) ); } private BaseNaturalIdLoadAccessImpl(Class entityClass) { this( entityClass.getName() ); } public BaseNaturalIdLoadAccessImpl with(LockOptions lockOptions) { this.lockOptions = lockOptions; return this; } protected void synchronizationEnabled(boolean synchronizationEnabled) { this.synchronizationEnabled = synchronizationEnabled; } protected final Serializable resolveNaturalId(Map naturalIdParameters) { performAnyNeededCrossReferenceSynchronizations(); final ResolveNaturalIdEvent event = new ResolveNaturalIdEvent( naturalIdParameters, entityPersister, SessionImpl.this ); fireResolveNaturalId( event ); if ( event.getEntityId() == PersistenceContext.NaturalIdHelper.INVALID_NATURAL_ID_REFERENCE ) { return null; } else { return event.getEntityId(); } } protected void performAnyNeededCrossReferenceSynchronizations() { if ( ! synchronizationEnabled ) { // synchronization (this process) was disabled return; } if ( entityPersister.getEntityMetamodel().hasImmutableNaturalId() ) { // only mutable natural-ids need this processing return; } if ( ! isTransactionInProgress() ) { // not in a transaction so skip synchronization return; } final boolean debugEnabled = LOG.isDebugEnabled(); for ( Serializable pk : getPersistenceContext().getNaturalIdHelper().getCachedPkResolutions( entityPersister ) ) { final EntityKey entityKey = generateEntityKey( pk, entityPersister ); final Object entity = getPersistenceContext().getEntity( entityKey ); final EntityEntry entry = getPersistenceContext().getEntry( entity ); if ( entry == null ) { if ( debugEnabled ) { LOG.debug( "Cached natural-id/pk resolution linked to null EntityEntry in persistence context : " + MessageHelper.infoString( entityPersister, pk, getFactory() ) ); } continue; } if ( !entry.requiresDirtyCheck( entity ) ) { continue; } // MANAGED is the only status we care about here... if ( entry.getStatus() != Status.MANAGED ) { continue; } getPersistenceContext().getNaturalIdHelper().handleSynchronization( entityPersister, pk, entity ); } } protected final IdentifierLoadAccess getIdentifierLoadAccess() { final IdentifierLoadAccessImpl identifierLoadAccess = new IdentifierLoadAccessImpl( entityPersister ); if ( this.lockOptions != null ) { identifierLoadAccess.with( lockOptions ); } return identifierLoadAccess; } protected EntityPersister entityPersister() { return entityPersister; } } private class NaturalIdLoadAccessImpl extends BaseNaturalIdLoadAccessImpl implements NaturalIdLoadAccess { private final Map naturalIdParameters = new LinkedHashMap(); private NaturalIdLoadAccessImpl(EntityPersister entityPersister) { super(entityPersister); } private NaturalIdLoadAccessImpl(String entityName) { this( locateEntityPersister( entityName ) ); } private NaturalIdLoadAccessImpl(Class entityClass) { this( entityClass.getName() ); } @Override public NaturalIdLoadAccessImpl with(LockOptions lockOptions) { return (NaturalIdLoadAccessImpl) super.with( lockOptions ); } @Override public NaturalIdLoadAccess using(String attributeName, Object value) { naturalIdParameters.put( attributeName, value ); return this; } @Override public NaturalIdLoadAccessImpl setSynchronizationEnabled(boolean synchronizationEnabled) { super.synchronizationEnabled( synchronizationEnabled ); return this; } @Override public final Object getReference() { final Serializable entityId = resolveNaturalId( this.naturalIdParameters ); if ( entityId == null ) { return null; } return this.getIdentifierLoadAccess().getReference( entityId ); } @Override public final Object load() { final Serializable entityId = resolveNaturalId( this.naturalIdParameters ); if ( entityId == null ) { return null; } try { return this.getIdentifierLoadAccess().load( entityId ); } catch (EntityNotFoundException enf) { // OK } catch (ObjectNotFoundException nf) { // OK } return null; } } private class SimpleNaturalIdLoadAccessImpl extends BaseNaturalIdLoadAccessImpl implements SimpleNaturalIdLoadAccess { private final String naturalIdAttributeName; private SimpleNaturalIdLoadAccessImpl(EntityPersister entityPersister) { super(entityPersister); if ( entityPersister.getNaturalIdentifierProperties().length != 1 ) { throw new HibernateException( String.format( "Entity [%s] did not define a simple natural id", entityPersister.getEntityName() ) ); } final int naturalIdAttributePosition = entityPersister.getNaturalIdentifierProperties()[0]; this.naturalIdAttributeName = entityPersister.getPropertyNames()[ naturalIdAttributePosition ]; } private SimpleNaturalIdLoadAccessImpl(String entityName) { this( locateEntityPersister( entityName ) ); } private SimpleNaturalIdLoadAccessImpl(Class entityClass) { this( entityClass.getName() ); } @Override public final SimpleNaturalIdLoadAccessImpl with(LockOptions lockOptions) { return (SimpleNaturalIdLoadAccessImpl) super.with( lockOptions ); } private Map getNaturalIdParameters(Object naturalIdValue) { return Collections.singletonMap( naturalIdAttributeName, naturalIdValue ); } @Override public SimpleNaturalIdLoadAccessImpl setSynchronizationEnabled(boolean synchronizationEnabled) { super.synchronizationEnabled( synchronizationEnabled ); return this; } @Override public Object getReference(Object naturalIdValue) { final Serializable entityId = resolveNaturalId( getNaturalIdParameters( naturalIdValue ) ); if ( entityId == null ) { return null; } return this.getIdentifierLoadAccess().getReference( entityId ); } @Override public Object load(Object naturalIdValue) { final Serializable entityId = resolveNaturalId( getNaturalIdParameters( naturalIdValue ) ); if ( entityId == null ) { return null; } try { return this.getIdentifierLoadAccess().load( entityId ); } catch (EntityNotFoundException enf) { // OK } catch (ObjectNotFoundException nf) { // OK } return null; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy