/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
 * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
 */
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.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.persistence.CacheRetrieveMode;
import javax.persistence.CacheStoreMode;
import javax.persistence.EntityGraph;
import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.PersistenceException;
import javax.persistence.PessimisticLockScope;
import javax.persistence.StoredProcedureQuery;
import javax.persistence.TransactionRequiredException;
import javax.persistence.Tuple;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaDelete;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.CriteriaUpdate;
import javax.persistence.criteria.Selection;

import org.hibernate.CacheMode;
import org.hibernate.Criteria;
import org.hibernate.Filter;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.IdentifierLoadAccess;
import org.hibernate.JDBCException;
import org.hibernate.LobHelper;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.MultiIdentifierLoadAccess;
import org.hibernate.NaturalIdLoadAccess;
import org.hibernate.ObjectDeletedException;
import org.hibernate.ObjectNotFoundException;
import org.hibernate.QueryException;
import org.hibernate.ReplicationMode;
import org.hibernate.ScrollMode;
import org.hibernate.Session;
import org.hibernate.SessionEventListener;
import org.hibernate.SessionException;
import org.hibernate.SharedSessionBuilder;
import org.hibernate.SimpleNaturalIdLoadAccess;
import org.hibernate.TransientObjectException;
import org.hibernate.TypeHelper;
import org.hibernate.TypeMismatchException;
import org.hibernate.UnknownProfileException;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.criterion.NaturalIdentifier;
import org.hibernate.engine.internal.StatefulPersistenceContext;
import org.hibernate.engine.jdbc.LobCreator;
import org.hibernate.engine.jdbc.NonContextualLobCreator;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
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.NamedQueryDefinition;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SessionOwner;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.engine.spi.TypedValue;
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.graph.spi.EntityGraphImplementor;
import org.hibernate.internal.CriteriaImpl.CriterionEntry;
import org.hibernate.internal.log.DeprecationLogger;
import org.hibernate.jdbc.ReturningWork;
import org.hibernate.jdbc.Work;
import org.hibernate.jdbc.WorkExecutor;
import org.hibernate.jdbc.WorkExecutorVisitable;
import org.hibernate.jpa.AvailableSettings;
import org.hibernate.jpa.QueryHints;
import org.hibernate.jpa.graph.internal.EntityGraphImpl;
import org.hibernate.jpa.internal.util.CacheModeHelper;
import org.hibernate.jpa.internal.util.ConfigurationHelper;
import org.hibernate.jpa.internal.util.FlushModeTypeHelper;
import org.hibernate.jpa.internal.util.LockModeTypeHelper;
import org.hibernate.jpa.spi.CriteriaQueryTupleTransformer;
import org.hibernate.jpa.spi.HibernateEntityManagerImplementor;
import org.hibernate.loader.criteria.CriteriaLoader;
import org.hibernate.loader.custom.CustomLoader;
import org.hibernate.loader.custom.CustomQuery;
import org.hibernate.metamodel.spi.MetamodelImplementor;
import org.hibernate.param.CollectionFilterKeyParameterSpecification;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.MultiLoadOptions;
import org.hibernate.persister.entity.OuterJoinLoadable;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.procedure.ProcedureCall;
import org.hibernate.procedure.ProcedureCallMemento;
import org.hibernate.procedure.UnknownSqlResultSetMappingException;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode;
import org.hibernate.query.Query;
import org.hibernate.query.criteria.internal.compile.CompilableCriteria;
import org.hibernate.query.criteria.internal.compile.CriteriaCompiler;
import org.hibernate.query.criteria.internal.expression.CompoundSelectionImpl;
import org.hibernate.query.internal.CollectionFilterImpl;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.query.spi.ScrollableResultsImplementor;
import org.hibernate.resource.transaction.TransactionRequiredForJoinException;
import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl;
import org.hibernate.resource.transaction.backend.jta.internal.synchronization.AfterCompletionAction;
import org.hibernate.resource.transaction.backend.jta.internal.synchronization.ExceptionMapper;
import org.hibernate.resource.transaction.backend.jta.internal.synchronization.ManagedFlushChecker;
import org.hibernate.resource.transaction.spi.TransactionCoordinator;
import org.hibernate.resource.transaction.spi.TransactionStatus;
import org.hibernate.stat.SessionStatistics;
import org.hibernate.stat.internal.SessionStatisticsImpl;

import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_SCOPE;
import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT;
import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE;
import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_STORE_MODE;

Concrete implementation of a Session.

Exposes two interfaces:

This class is not thread-safe.
Author:Gavin King, Steve Ebersole, Brett Meyer, Chris Cranford
/** * Concrete implementation of a Session. * <p/> * Exposes two interfaces:<ul> * <li>{@link org.hibernate.Session} to the application</li> * <li>{@link org.hibernate.engine.spi.SessionImplementor} to other Hibernate components (SPI)</li> * </ul> * <p/> * This class is not thread-safe. * * @author Gavin King * @author Steve Ebersole * @author Brett Meyer * @author Chris Cranford */
public final class SessionImpl extends AbstractSessionImpl implements EventSource, SessionImplementor, HibernateEntityManagerImplementor { private static final EntityManagerMessageLogger log = HEMLogging.messageLogger( SessionImpl.class ); private static final boolean TRACE_ENABLED = log.isTraceEnabled(); private static final String[] ENTITY_MANAGER_SPECIFIC_PROPERTIES = { JPA_LOCK_SCOPE, JPA_LOCK_TIMEOUT, AvailableSettings.FLUSH_MODE, JPA_SHARED_CACHE_RETRIEVE_MODE, JPA_SHARED_CACHE_STORE_MODE, QueryHints.SPEC_HINT_TIMEOUT }; private transient SessionOwner sessionOwner; private Map<String, Object> properties = new HashMap<>(); private transient ActionQueue actionQueue; private transient StatefulPersistenceContext persistenceContext; private transient LoadQueryInfluencers loadQueryInfluencers; // todo : (5.2) HEM always initialized this. Is that really needed? private LockOptions lockOptions = new LockOptions(); private boolean autoClear; private boolean autoClose; private boolean queryParametersValidationEnabled; private transient int dontFlushFromFind; private transient boolean disallowOutOfTransactionUpdateOperations; private transient ExceptionMapper exceptionMapper; private transient ManagedFlushChecker managedFlushChecker; private transient AfterCompletionAction afterCompletionAction; private transient LoadEvent loadEvent; //cached LoadEvent instance private transient boolean discardOnClose; private transient TransactionObserver transactionObserver; public SessionImpl(SessionFactoryImpl factory, SessionCreationOptions options) { super( factory, options ); this.actionQueue = new ActionQueue( this ); this.persistenceContext = new StatefulPersistenceContext( this ); this.sessionOwner = options.getSessionOwner(); initializeFromSessionOwner( sessionOwner ); this.autoClear = options.shouldAutoClear(); this.autoClose = options.shouldAutoClose(); this.queryParametersValidationEnabled = options.isQueryParametersValidationEnabled(); this.disallowOutOfTransactionUpdateOperations = !factory.getSessionFactoryOptions().isAllowOutOfTransactionUpdateOperations(); this.discardOnClose = getFactory().getSessionFactoryOptions().isReleaseResourcesOnCloseEnabled(); if ( options instanceof SharedSessionCreationOptions && ( (SharedSessionCreationOptions) options ).isTransactionCoordinatorShared() ) { final SharedSessionCreationOptions sharedOptions = (SharedSessionCreationOptions) options; if ( sharedOptions.getTransactionCompletionProcesses() != null ) { actionQueue.setTransactionCompletionProcesses( sharedOptions.getTransactionCompletionProcesses(), true ); } } loadQueryInfluencers = new LoadQueryInfluencers( factory ); if ( getFactory().getStatistics().isStatisticsEnabled() ) { getFactory().getStatistics().openSession(); } // NOTE : pulse() already handles auto-join-ability correctly getTransactionCoordinator().pulse(); setDefaultProperties(); applyProperties(); if ( TRACE_ENABLED ) { log.tracef( "Opened Session [%s] at timestamp: %s", getSessionIdentifier(), getTimestamp() ); } } private void setDefaultProperties() { properties.putIfAbsent( AvailableSettings.FLUSH_MODE, getHibernateFlushMode().name() ); properties.putIfAbsent( JPA_LOCK_SCOPE, PessimisticLockScope.EXTENDED.name() ); properties.putIfAbsent( JPA_LOCK_TIMEOUT, LockOptions.WAIT_FOREVER ); properties.putIfAbsent( JPA_SHARED_CACHE_RETRIEVE_MODE, CacheModeHelper.DEFAULT_RETRIEVE_MODE ); properties.putIfAbsent( JPA_SHARED_CACHE_STORE_MODE, CacheModeHelper.DEFAULT_STORE_MODE ); } private void applyProperties() { applyEntityManagerSpecificProperties(); setHibernateFlushMode( ConfigurationHelper.getFlushMode( properties.get( AvailableSettings.FLUSH_MODE ), FlushMode.AUTO ) ); setLockOptions( this.properties, this.lockOptions ); getSession().setCacheMode( CacheModeHelper.interpretCacheMode( currentCacheStoreMode(), currentCacheRetrieveMode() ) ); } private void applyEntityManagerSpecificProperties() { final Map<String, Object> properties = getFactory().getProperties(); for ( String key : ENTITY_MANAGER_SPECIFIC_PROPERTIES ) { if ( properties.containsKey( key ) ) { this.properties.put( key, properties.get( key ) ); } } } protected void applyQuerySettingsAndHints(Query query) { if ( lockOptions.getLockMode() != LockMode.NONE ) { query.setLockMode( getLockMode( lockOptions.getLockMode() ) ); } Object queryTimeout; if ( (queryTimeout = getProperties().get( QueryHints.SPEC_HINT_TIMEOUT ) ) != null ) { query.setHint( QueryHints.SPEC_HINT_TIMEOUT, queryTimeout ); } Object lockTimeout; if( (lockTimeout = getProperties().get( JPA_LOCK_TIMEOUT ))!=null){ query.setHint( JPA_LOCK_TIMEOUT, lockTimeout ); } } private CacheRetrieveMode currentCacheRetrieveMode() { return determineCacheRetrieveMode( properties ); } private CacheStoreMode currentCacheStoreMode() { return determineCacheStoreMode( properties ); } private void initializeFromSessionOwner(SessionOwner sessionOwner) { if ( sessionOwner != null ) { if ( sessionOwner.getExceptionMapper() != null ) { exceptionMapper = sessionOwner.getExceptionMapper(); } else { exceptionMapper = ExceptionMapperStandardImpl.INSTANCE; } if ( sessionOwner.getAfterCompletionAction() != null ) { afterCompletionAction = sessionOwner.getAfterCompletionAction(); } else { afterCompletionAction = STANDARD_AFTER_COMPLETION_ACTION; } if ( sessionOwner.getManagedFlushChecker() != null ) { managedFlushChecker = sessionOwner.getManagedFlushChecker(); } else { managedFlushChecker = STANDARD_MANAGED_FLUSH_CHECKER; } } else { exceptionMapper = ExceptionMapperStandardImpl.INSTANCE; afterCompletionAction = STANDARD_AFTER_COMPLETION_ACTION; managedFlushChecker = STANDARD_MANAGED_FLUSH_CHECKER; } } @Override public SharedSessionBuilder sessionWithOptions() { return new SharedSessionBuilderImpl( this ); } @Override public void clear() { checkOpen(); // Do not call checkTransactionSynchStatus() here -- if a delayed // afterCompletion exists, it can cause an infinite loop. pulseTransactionCoordinator(); try { internalClear(); } catch (RuntimeException e) { throw exceptionConverter.convert( e ); } } private void internalClear() { persistenceContext.clear(); actionQueue.clear(); final ClearEvent event = new ClearEvent( this ); for ( ClearEventListener listener : listeners( EventType.CLEAR ) ) { listener.onClear( event ); } } @Override @SuppressWarnings("StatementWithEmptyBody") public void close() throws HibernateException { if ( isClosed() ) { if ( getFactory().getSessionFactoryOptions().getJpaCompliance().isJpaClosedComplianceEnabled() ) { throw new IllegalStateException( "Illegal call to #close() on already closed Session/EntityManager" ); } log.trace( "Already closed" ); return; } closeWithoutOpenChecks(); } public void closeWithoutOpenChecks() throws HibernateException { if ( TRACE_ENABLED ) { log.tracef( "Closing session [%s]", getSessionIdentifier() ); } // todo : we want this check if usage is JPA, but not native Hibernate usage if ( getSessionFactory().getSessionFactoryOptions().isJpaBootstrap() ) { // Original hibernate-entitymanager EM#close behavior checkSessionFactoryOpen(); checkOpenOrWaitingForAutoClose(); if ( discardOnClose || !isTransactionInProgress( false ) ) { super.close(); } else { //Otherwise, session auto-close will be enabled by shouldAutoCloseSession(). waitingForAutoClose = true; closed = true; } } else { super.close(); } if ( getFactory().getStatistics().isStatisticsEnabled() ) { getFactory().getStatistics().closeSession(); } } private boolean isTransactionInProgress(boolean isMarkedRollbackConsideredActive) { if ( waitingForAutoClose ) { return getSessionFactory().isOpen() && getTransactionCoordinator().isTransactionActive( isMarkedRollbackConsideredActive ); } return !isClosed() && getTransactionCoordinator().isTransactionActive( isMarkedRollbackConsideredActive ); } @Override protected boolean shouldCloseJdbcCoordinatorOnClose(boolean isTransactionCoordinatorShared) { if ( !isTransactionCoordinatorShared ) { return super.shouldCloseJdbcCoordinatorOnClose( isTransactionCoordinatorShared ); } if ( getActionQueue().hasBeforeTransactionActions() || getActionQueue().hasAfterTransactionActions() ) { log.warn( "On close, shared Session had before/after transaction actions that have not yet been processed" ); } return false; } @Override public boolean isAutoCloseSessionEnabled() { return autoClose; } @Override public boolean isQueryParametersValidationEnabled() { return queryParametersValidationEnabled; } @Override public boolean isOpen() { checkSessionFactoryOpen(); checkTransactionSynchStatus(); try { return !isClosed(); } catch (HibernateException he) { throw exceptionConverter.convert( he ); } } protected void checkSessionFactoryOpen() { if ( !getFactory().isOpen() ) { log.debug( "Forcing Session/EntityManager closed as SessionFactory/EntityManagerFactory has been closed" ); setClosed(); } } private boolean isFlushModeNever() { return FlushMode.isManualFlushMode( getHibernateFlushMode() ); } private void managedFlush() { if ( isClosed() && !waitingForAutoClose ) { log.trace( "Skipping auto-flush due to session closed" ); return; } log.trace( "Automatically flushing session" ); doFlush(); } @Override public boolean shouldAutoClose() { if ( waitingForAutoClose ) { return true; } else if ( isClosed() ) { return false; } else if ( sessionOwner != null ) { return sessionOwner.shouldAutoCloseSession(); } else { // JPA technically requires that this be a PersistentUnityTransactionType#JTA to work, // but we do not assert that here... //return isAutoCloseSessionEnabled() && getTransactionCoordinator().getTransactionCoordinatorBuilder().isJta(); return isAutoCloseSessionEnabled(); } } private void managedClose() { log.trace( "Automatically closing session" ); closeWithoutOpenChecks(); } @Override public Connection connection() throws HibernateException { checkOpenOrWaitingForAutoClose(); return getJdbcCoordinator().getLogicalConnection().getPhysicalConnection(); } @Override public Connection disconnect() throws HibernateException { checkOpen(); log.debug( "Disconnecting session" ); return getJdbcCoordinator().getLogicalConnection().manualDisconnect(); } @Override public void reconnect(Connection conn) throws HibernateException { checkOpen(); log.debug( "Reconnecting session" ); checkTransactionSynchStatus(); getJdbcCoordinator().getLogicalConnection().manualReconnect( conn ); } @Override public void setAutoClear(boolean enabled) { checkOpenOrWaitingForAutoClose(); autoClear = enabled; }
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
Params:
  • success – Was the operation a success
/** * 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 ( !isTransactionInProgress() ) { getJdbcCoordinator().afterTransaction(); } } @Override public void addEventListeners(SessionEventListener... listeners) { getEventListenerManager().addListener( listeners ); }
clear all the internal collections, just to help the garbage collector, does not clear anything that is needed during the afterTransactionCompletion() phase
/** * clear all the internal collections, just * to help the garbage collector, does not * clear anything that is needed during the * afterTransactionCompletion() phase */
@Override protected void cleanupOnClose() { persistenceContext.clear(); } @Override public LockMode getCurrentLockMode(Object object) throws HibernateException { checkOpen(); 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 { checkOpenOrWaitingForAutoClose(); // 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 = getInterceptor().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(); } @Override protected void delayedAfterCompletion() { if ( getTransactionCoordinator() instanceof JtaTransactionCoordinatorImpl ) { ( (JtaTransactionCoordinatorImpl) getTransactionCoordinator() ).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) { checkOpen(); checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); for ( SaveOrUpdateEventListener listener : listeners( EventType.SAVE_UPDATE ) ) { listener.onSaveOrUpdate( event ); } checkNoUnresolvedActionsAfterOperation(); } private <T> Iterable<T> listeners(EventType<T> type) { return eventListenerGroup( type ).listeners(); } private <T> EventListenerGroup<T> eventListenerGroup(EventType<T> type) { return getFactory().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) { checkOpen(); 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) { checkOpen(); 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) { checkOpen(); checkTransactionSynchStatus(); for ( LockEventListener listener : listeners( EventType.LOCK ) ) { listener.onLock( event ); } delayedAfterCompletion(); } // persist() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public void persist(String entityName, Object object) throws HibernateException { checkOpen(); firePersist( new PersistEvent( entityName, object, this ) ); } @Override public void persist(Object object) throws HibernateException { checkOpen(); firePersist( new PersistEvent( null, object, this ) ); } @Override public void persist(String entityName, Object object, Map copiedAlready) throws HibernateException { checkOpenOrWaitingForAutoClose(); firePersist( copiedAlready, new PersistEvent( entityName, object, this ) ); } private void firePersist(PersistEvent event) { try { checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); for ( PersistEventListener listener : listeners( EventType.PERSIST ) ) { listener.onPersist( event ); } } catch (MappingException e) { throw exceptionConverter.convert( new IllegalArgumentException( e.getMessage() ) ); } catch (RuntimeException e) { throw exceptionConverter.convert( e ); } finally { try { checkNoUnresolvedActionsAfterOperation(); } catch (RuntimeException e) { throw exceptionConverter.convert( e ); } } } private void firePersist(Map copiedAlready, PersistEvent event) { checkTransactionSynchStatus(); try { for ( PersistEventListener listener : listeners( EventType.PERSIST ) ) { listener.onPersist( event, copiedAlready ); } } catch ( MappingException e ) { throw exceptionConverter.convert( new IllegalArgumentException( e.getMessage() ) ) ; } catch ( RuntimeException e ) { throw exceptionConverter.convert( e ); } finally { delayedAfterCompletion(); } } // 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) { checkOpenOrWaitingForAutoClose(); checkTransactionSynchStatus(); for ( PersistEventListener listener : listeners( EventType.PERSIST_ONFLUSH ) ) { listener.onPersist( event, copiedAlready ); } delayedAfterCompletion(); } private void firePersistOnFlush(PersistEvent event) { checkOpen(); 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 { checkOpen(); return fireMerge( new MergeEvent( entityName, object, this ) ); } @Override public Object merge(Object object) throws HibernateException { checkOpen(); return fireMerge( new MergeEvent( null, object, this )); } @Override public void merge(String entityName, Object object, Map copiedAlready) throws HibernateException { checkOpenOrWaitingForAutoClose(); fireMerge( copiedAlready, new MergeEvent( entityName, object, this ) ); } private Object fireMerge(MergeEvent event) { try { checkTransactionSynchStatus(); checkNoUnresolvedActionsBeforeOperation(); for ( MergeEventListener listener : listeners( EventType.MERGE ) ) { listener.onMerge( event ); } checkNoUnresolvedActionsAfterOperation(); } catch ( ObjectDeletedException sse ) { throw exceptionConverter.convert( new IllegalArgumentException( sse ) ); } catch ( MappingException e ) { throw exceptionConverter.convert( new IllegalArgumentException( e.getMessage(), e ) ); } catch ( RuntimeException e ) { //including HibernateException throw exceptionConverter.convert( e ); } return event.getResult(); } private void fireMerge(Map copiedAlready, MergeEvent event) { try { checkTransactionSynchStatus(); for ( MergeEventListener listener : listeners( EventType.MERGE ) ) { listener.onMerge( event, copiedAlready ); } } catch ( ObjectDeletedException sse ) { throw exceptionConverter.convert( new IllegalArgumentException( sse ) ); } catch ( MappingException e ) { throw exceptionConverter.convert( new IllegalArgumentException( e.getMessage(), e ) ); } catch ( RuntimeException e ) { //including HibernateException throw exceptionConverter.convert( e ); } finally { delayedAfterCompletion(); } } // delete() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public void delete(Object object) throws HibernateException { checkOpen(); fireDelete( new DeleteEvent( object, this ) ); } @Override public void delete(String entityName, Object object) throws HibernateException { checkOpen(); fireDelete( new DeleteEvent( entityName, object, this ) ); } @Override public void delete(String entityName, Object object, boolean isCascadeDeleteEnabled, Set transientEntities) throws HibernateException { checkOpenOrWaitingForAutoClose(); if ( TRACE_ENABLED && persistenceContext.isRemovingOrphanBeforeUpates() ) { logRemoveOrphanBeforeUpdates( "before continuing", entityName, object ); } fireDelete( new DeleteEvent( entityName, object, isCascadeDeleteEnabled, persistenceContext.isRemovingOrphanBeforeUpates(), this ), transientEntities ); if ( TRACE_ENABLED && persistenceContext.isRemovingOrphanBeforeUpates() ) { logRemoveOrphanBeforeUpdates( "after continuing", entityName, object ); } } @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. if ( TRACE_ENABLED ) { logRemoveOrphanBeforeUpdates( "begin", entityName, child ); } persistenceContext.beginRemoveOrphanBeforeUpdates(); try { checkOpenOrWaitingForAutoClose(); fireDelete( new DeleteEvent( entityName, child, false, true, this ) ); } finally { persistenceContext.endRemoveOrphanBeforeUpdates(); if ( TRACE_ENABLED ) { logRemoveOrphanBeforeUpdates( "end", entityName, child ); } } } private void logRemoveOrphanBeforeUpdates(String timing, String entityName, Object entity) { final EntityEntry entityEntry = persistenceContext.getEntry( entity ); log.tracef( "%s remove orphan before updates: [%s]", timing, entityEntry == null ? entityName : MessageHelper.infoString( entityName, entityEntry.getId() ) ); } private void fireDelete(DeleteEvent event) { try{ checkTransactionSynchStatus(); for ( DeleteEventListener listener : listeners( EventType.DELETE ) ) { listener.onDelete( event ); } } catch ( ObjectDeletedException sse ) { throw exceptionConverter.convert( new IllegalArgumentException( sse ) ); } catch ( MappingException e ) { throw exceptionConverter.convert( new IllegalArgumentException( e.getMessage(), e ) ); } catch ( RuntimeException e ) { //including HibernateException throw exceptionConverter.convert( e ); } finally { delayedAfterCompletion(); } } private void fireDelete(DeleteEvent event, Set transientEntities) { try{ checkTransactionSynchStatus(); for ( DeleteEventListener listener : listeners( EventType.DELETE ) ) { listener.onDelete( event, transientEntities ); } } catch ( ObjectDeletedException sse ) { throw exceptionConverter.convert( new IllegalArgumentException( sse ) ); } catch ( MappingException e ) { throw exceptionConverter.convert( new IllegalArgumentException( e.getMessage(), e ) ); } catch ( RuntimeException e ) { //including HibernateException throw exceptionConverter.convert( e ); } finally { delayedAfterCompletion(); } } // load()/get() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public void load(Object object, Serializable id) throws HibernateException { LoadEvent event = loadEvent; loadEvent = null; if ( event == null ) { event = new LoadEvent( id, object, this ); } else { event.setEntityClassName( null ); event.setEntityId( id ); event.setInstanceToLoad( object ); event.setLockMode( LoadEvent.DEFAULT_LOCK_MODE ); event.setLockScope( LoadEvent.DEFAULT_LOCK_OPTIONS.getScope() ); event.setLockTimeout( LoadEvent.DEFAULT_LOCK_OPTIONS.getTimeOut() ); } fireLoad( event, LoadEventListener.RELOAD ); if ( loadEvent == null ) { event.setEntityClassName( null ); event.setEntityId( null ); event.setInstanceToLoad( null ); event.setResult( null ); loadEvent = event; } } @Override public <T> T load(Class<T> 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 <T> T get(Class<T> 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.
/** * 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().getMetamodel().entityPersister( entityName ); log.debugf( "Initializing proxy: %s", MessageHelper.infoString( persister, id, getFactory() ) ); } LoadEvent event = loadEvent; loadEvent = null; event = recycleEventInstance( event, id, entityName ); fireLoad( event, LoadEventListener.IMMEDIATE_LOAD ); Object result = event.getResult(); if ( loadEvent == null ) { event.setEntityClassName( null ); event.setEntityId( null ); event.setInstanceToLoad( null ); event.setResult( null ); loadEvent = event; } return result; } @Override public final 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 = loadEvent; loadEvent = null; event = recycleEventInstance( event, id, entityName ); fireLoad( event, type ); Object result = event.getResult(); if ( !nullable ) { UnresolvableObjectException.throwIfNull( result, id, entityName ); } if ( loadEvent == null ) { event.setEntityClassName( null ); event.setEntityId( null ); event.setInstanceToLoad( null ); event.setResult( null ); loadEvent = event; } return result; }
Helper to avoid creating many new instances of LoadEvent: it's an allocation hot spot.
/** * Helper to avoid creating many new instances of LoadEvent: it's an allocation hot spot. */
private LoadEvent recycleEventInstance(final LoadEvent event, final Serializable id, final String entityName) { if ( event == null ) { return new LoadEvent( id, entityName, true, this ); } else { event.setEntityClassName( entityName ); event.setEntityId( id ); event.setInstanceToLoad( null ); event.setLockMode( LoadEvent.DEFAULT_LOCK_MODE ); event.setLockScope( LoadEvent.DEFAULT_LOCK_OPTIONS.getScope() ); event.setLockTimeout( LoadEvent.DEFAULT_LOCK_OPTIONS.getTimeOut() ); return event; } } @Override public <T> T load(Class<T> entityClass, Serializable id, LockMode lockMode) throws HibernateException { return this.byId( entityClass ).with( new LockOptions( lockMode ) ).getReference( id ); } @Override public <T> T load(Class<T> 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 <T> T get(Class<T> entityClass, Serializable id, LockMode lockMode) throws HibernateException { return this.byId( entityClass ).with( new LockOptions( lockMode ) ).load( id ); } @Override public <T> T get(Class<T> 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 <T> IdentifierLoadAccessImpl<T> byId(Class<T> entityClass) { return new IdentifierLoadAccessImpl<T>( entityClass ); } @Override public <T> MultiIdentifierLoadAccess<T> byMultipleIds(Class<T> entityClass) { return new MultiIdentifierLoadAccessImpl<T>( locateEntityPersister( entityClass ) ); } @Override public MultiIdentifierLoadAccess byMultipleIds(String entityName) { return new MultiIdentifierLoadAccessImpl( locateEntityPersister( entityName ) ); } @Override public NaturalIdLoadAccess byNaturalId(String entityName) { return new NaturalIdLoadAccessImpl( entityName ); } @Override public <T> NaturalIdLoadAccess<T> byNaturalId(Class<T> entityClass) { return new NaturalIdLoadAccessImpl<T>( entityClass ); } @Override public SimpleNaturalIdLoadAccess bySimpleNaturalId(String entityName) { return new SimpleNaturalIdLoadAccessImpl( entityName ); } @Override public <T> SimpleNaturalIdLoadAccess<T> bySimpleNaturalId(Class<T> entityClass) { return new SimpleNaturalIdLoadAccessImpl<T>( entityClass ); } private void fireLoad(LoadEvent event, LoadType loadType) { checkOpenOrWaitingForAutoClose(); checkTransactionSynchStatus(); for ( LoadEventListener listener : listeners( EventType.LOAD ) ) { listener.onLoad( event, loadType ); } delayedAfterCompletion(); } private void fireResolveNaturalId(ResolveNaturalIdEvent event) { checkOpenOrWaitingForAutoClose(); checkTransactionSynchStatus(); for ( ResolveNaturalIdEventListener listener : listeners( EventType.RESOLVE_NATURAL_ID ) ) { listener.onResolveNaturalId( event ); } delayedAfterCompletion(); } // refresh() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override public void refresh(Object object) throws HibernateException { checkOpen(); fireRefresh( new RefreshEvent( null, object, this ) ); } @Override public void refresh(String entityName, Object object) throws HibernateException { checkOpen(); fireRefresh( new RefreshEvent( entityName, object, this ) ); } @Override public void refresh(Object object, LockMode lockMode) throws HibernateException { checkOpen(); fireRefresh( new RefreshEvent( object, lockMode, this ) ); } @Override public void refresh(Object object, LockOptions lockOptions) throws HibernateException { checkOpen(); refresh( null, object, lockOptions ); } @Override public void refresh(String entityName, Object object, LockOptions lockOptions) throws HibernateException { checkOpen(); fireRefresh( new RefreshEvent( entityName, object, lockOptions, this ) ); } @Override public void refresh(String entityName, Object object, Map refreshedAlready) throws HibernateException { checkOpenOrWaitingForAutoClose(); fireRefresh( refreshedAlready, new RefreshEvent( entityName, object, this ) ); } private void fireRefresh(RefreshEvent event) { try { if ( !getSessionFactory().getSessionFactoryOptions().isAllowRefreshDetachedEntity() ) { if ( event.getEntityName() != null ) { if ( !contains( event.getEntityName(), event.getObject() ) ) { throw new IllegalArgumentException( "Entity not managed" ); } } else { if ( !contains( event.getObject() ) ) { throw new IllegalArgumentException( "Entity not managed" ); } } } checkTransactionSynchStatus(); for ( RefreshEventListener listener : listeners( EventType.REFRESH ) ) { listener.onRefresh( event ); } } catch (RuntimeException e) { if ( !getSessionFactory().getSessionFactoryOptions().isJpaBootstrap() ) { if ( e instanceof HibernateException ) { throw e; } } //including HibernateException throw exceptionConverter.convert( e ); } finally { delayedAfterCompletion(); } } private void fireRefresh(Map refreshedAlready, RefreshEvent event) { try { checkTransactionSynchStatus(); for ( RefreshEventListener listener : listeners( EventType.REFRESH ) ) { listener.onRefresh( event, refreshedAlready ); } delayedAfterCompletion(); } catch (RuntimeException e) { throw exceptionConverter.convert( e ); } finally { 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) { checkOpen(); 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)
/** * 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) { checkOpen(); 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
/** * 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 { checkOpen(); 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 { checkOpen(); 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 { checkOpen(); doFlush(); } private void doFlush() { checkTransactionNeeded(); checkTransactionSynchStatus(); try { 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(); } catch ( RuntimeException e ) { throw exceptionConverter.convert( e ); } } @Override public void setFlushMode(FlushModeType flushModeType) { checkOpen(); setHibernateFlushMode( FlushModeTypeHelper.getFlushMode( flushModeType ) ); } @Override public void forceFlush(EntityEntry entityEntry) throws HibernateException { 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() ); } checkOpenOrWaitingForAutoClose(); doFlush(); } @Override public List list(String query, QueryParameters queryParameters) throws HibernateException { checkOpenOrWaitingForAutoClose(); checkTransactionSynchStatus(); queryParameters.validateParameters(); HQLQueryPlan plan = queryParameters.getQueryPlan(); if ( plan == null ) { plan = getQueryPlan( 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 { checkOpenOrWaitingForAutoClose(); checkTransactionSynchStatus(); queryParameters.validateParameters(); HQLQueryPlan plan = getQueryPlan( query, false ); autoFlushIfRequired( plan.getQuerySpaces() ); verifyImmutableEntityUpdate( plan ); boolean success = false; int result = 0; try { result = plan.performExecuteUpdate( queryParameters, this ); success = true; } finally { afterOperation( success ); delayedAfterCompletion(); } return result; } private void verifyImmutableEntityUpdate(HQLQueryPlan plan) { if ( plan.isUpdate() ) { for ( EntityPersister entityPersister : getSessionFactory().getMetamodel().entityPersisters().values() ) { if ( !entityPersister.isMutable() ) { List<Serializable> entityQuerySpaces = new ArrayList<>( Arrays.asList( entityPersister.getQuerySpaces() ) ); entityQuerySpaces.retainAll( plan.getQuerySpaces() ); if ( !entityQuerySpaces.isEmpty() ) { ImmutableEntityUpdateQueryHandlingMode immutableEntityUpdateQueryHandlingMode = getSessionFactory() .getSessionFactoryOptions() .getImmutableEntityUpdateQueryHandlingMode(); String querySpaces = Arrays.toString( entityQuerySpaces.toArray() ); switch ( immutableEntityUpdateQueryHandlingMode ) { case WARNING: log.immutableEntityUpdateQuery(plan.getSourceQuery(), querySpaces); break; case EXCEPTION: throw new HibernateException( "The query: [" + plan.getSourceQuery() + "] attempts to update an immutable entity: " + querySpaces ); default: throw new UnsupportedOperationException( "The "+ immutableEntityUpdateQueryHandlingMode + " is not supported!" ); } } } } } } @Override public int executeNativeUpdate( NativeSQLQuerySpecification nativeQuerySpecification, QueryParameters queryParameters) throws HibernateException { checkOpenOrWaitingForAutoClose(); checkTransactionSynchStatus(); queryParameters.validateParameters(); NativeSQLQueryPlan plan = getNativeQueryPlan( 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 { checkOpenOrWaitingForAutoClose(); checkTransactionSynchStatus(); queryParameters.validateParameters(); HQLQueryPlan plan = queryParameters.getQueryPlan(); if ( plan == null ) { plan = getQueryPlan( 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 ScrollableResultsImplementor scroll(String query, QueryParameters queryParameters) throws HibernateException { checkOpenOrWaitingForAutoClose(); checkTransactionSynchStatus(); HQLQueryPlan plan = queryParameters.getQueryPlan(); if ( plan == null ) { plan = getQueryPlan( query, false ); } autoFlushIfRequired( plan.getQuerySpaces() ); dontFlushFromFind++; try { return plan.performScroll( queryParameters, this ); } finally { delayedAfterCompletion(); dontFlushFromFind--; } } @Override public org.hibernate.query.Query createFilter(Object collection, String queryString) { checkOpen(); checkTransactionSynchStatus(); CollectionFilterImpl filter = new CollectionFilterImpl( queryString, collection, this, getFilterQueryPlan( collection, queryString, null, false ).getParameterMetadata() ); filter.setComment( queryString ); delayedAfterCompletion(); return filter; } @Override public Object instantiate(String entityName, Serializable id) throws HibernateException { return instantiate( getFactory().getMetamodel().entityPersister( entityName ), id ); }
give the interceptor an opportunity to override the default instantiation
/** * give the interceptor an opportunity to override the default instantiation */
@Override public Object instantiate(EntityPersister persister, Serializable id) throws HibernateException { checkOpenOrWaitingForAutoClose(); checkTransactionSynchStatus(); Object result = getInterceptor().instantiate( persister.getEntityName(), persister.getEntityMetamodel().getEntityMode(), id ); if ( result == null ) { result = persister.instantiate( id, this ); } delayedAfterCompletion(); return result; } @Override public EntityPersister getEntityPersister(final String entityName, final Object object) { checkOpenOrWaitingForAutoClose(); if ( entityName == null ) { return getFactory().getMetamodel().entityPersister( 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 getFactory().getMetamodel().entityPersister( 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 { checkOpen(); 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().
/** * 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) { checkOpenOrWaitingForAutoClose(); 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 = getFactory().getQueryPlanCache().getFilterQueryPlan( filter, roleAfterFlush.getRole(), shallow, getLoadQueryInfluencers().getEnabledFilters() ); } else { // otherwise, we only need to flush if there are in-memory changes // to the queried tables plan = getFactory().getQueryPlanCache().getFilterQueryPlan( filter, roleBeforeFlush.getRole(), shallow, getLoadQueryInfluencers().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 = getFactory().getQueryPlanCache().getFilterQueryPlan( filter, roleAfterFlush.getRole(), shallow, getLoadQueryInfluencers().getEnabledFilters() ); } } } if ( parameters != null ) { parameters.getNamedParameters().put( CollectionFilterKeyParameterSpecification.PARAM_KEY, new TypedValue( entry.getLoadedPersister().getKeyType(), entry.getLoadedKey() ) ); } return plan; } @Override public List listFilter(Object collection, String filter, QueryParameters queryParameters) { checkOpenOrWaitingForAutoClose(); 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) { checkOpenOrWaitingForAutoClose(); 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) { DeprecationLogger.DEPRECATION_LOGGER.deprecatedLegacyCriteria(); checkOpen(); checkTransactionSynchStatus(); return new CriteriaImpl( persistentClass.getName(), alias, this ); } @Override public Criteria createCriteria(String entityName, String alias) { DeprecationLogger.DEPRECATION_LOGGER.deprecatedLegacyCriteria(); checkOpen(); checkTransactionSynchStatus(); return new CriteriaImpl( entityName, alias, this ); } @Override public Criteria createCriteria(Class persistentClass) { DeprecationLogger.DEPRECATION_LOGGER.deprecatedLegacyCriteria(); checkOpen(); checkTransactionSynchStatus(); return new CriteriaImpl( persistentClass.getName(), this ); } @Override public Criteria createCriteria(String entityName) { DeprecationLogger.DEPRECATION_LOGGER.deprecatedLegacyCriteria(); checkOpen(); checkTransactionSynchStatus(); return new CriteriaImpl( entityName, this ); } @Override public ScrollableResultsImplementor scroll(Criteria criteria, ScrollMode scrollMode) { // TODO: Is this guaranteed to always be CriteriaImpl? CriteriaImpl criteriaImpl = (CriteriaImpl) criteria; checkOpenOrWaitingForAutoClose(); checkTransactionSynchStatus(); String entityName = criteriaImpl.getEntityOrClassName(); CriteriaLoader loader = new CriteriaLoader( getOuterJoinLoadable( entityName ), getFactory(), 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; if ( criteriaImpl.getMaxResults() != null && criteriaImpl.getMaxResults() == 0 ) { return Collections.EMPTY_LIST; } final NaturalIdLoadAccess naturalIdLoadAccess = this.tryNaturalIdLoadAccess( criteriaImpl ); if ( naturalIdLoadAccess != null ) { // EARLY EXIT! return Arrays.asList( naturalIdLoadAccess.load() ); } checkOpenOrWaitingForAutoClose(); // checkTransactionSynchStatus(); String[] implementors = getFactory().getMetamodel().getImplementors( criteriaImpl.getEntityOrClassName() ); int size = implementors.length; CriteriaLoader[] loaders = new CriteriaLoader[size]; Set spaces = new HashSet(); for ( int i = 0; i < size; i++ ) { loaders[i] = new CriteriaLoader( getOuterJoinLoadable( implementors[i] ), getFactory(), criteriaImpl, implementors[i], getLoadQueryInfluencers() ); spaces.addAll( loaders[i].getQuerySpaces() ); } autoFlushIfRequired( spaces ); List results = Collections.EMPTY_LIST; dontFlushFromFind++; boolean success = false; try { for ( int i = 0; i < size; i++ ) { final List currentResults = loaders[i].list( this ); currentResults.addAll( results ); results = currentResults; } success = true; } finally { dontFlushFromFind--; afterOperation( success ); delayedAfterCompletion(); } return results; }
Checks to see if the CriteriaImpl is a naturalId lookup that can be done via NaturalIdLoadAccess
Params:
  • criteria – The criteria to check as a complete natural identifier lookup.
Returns:A fully configured NaturalIdLoadAccess or null, if null is returned the standard CriteriaImpl execution should be performed
/** * Checks to see if the CriteriaImpl is a naturalId lookup that can be done via * NaturalIdLoadAccess * * @param criteria The criteria to check as a complete natural identifier lookup. * * @return A fully configured NaturalIdLoadAccess or null, if null is returned the standard CriteriaImpl execution * should be performed */
private NaturalIdLoadAccess tryNaturalIdLoadAccess(CriteriaImpl criteria) { // See if the criteria lookup is by naturalId if ( !criteria.isLookupByNaturalKey() ) { return null; } final String entityName = criteria.getEntityOrClassName(); final EntityPersister entityPersister = getFactory().getMetamodel().entityPersister( entityName ); // Verify the entity actually has a natural id, needed for legacy support as NaturalIdentifier criteria // queries did no natural id validation if ( !entityPersister.hasNaturalIdentifier() ) { return null; } // Since isLookupByNaturalKey is true there can be only one CriterionEntry and getCriterion() will // return an instanceof NaturalIdentifier final CriterionEntry criterionEntry = criteria.iterateExpressionEntries().next(); final NaturalIdentifier naturalIdentifier = (NaturalIdentifier) criterionEntry.getCriterion(); final Map<String, Object> 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 naturalIdentifierProperty : naturalIdentifierProperties ) { final String naturalIdProperty = propertyNames[naturalIdentifierProperty]; 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 ); } // Criteria 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 = getFactory().getMetamodel().entityPersister( entityName ); if ( !( persister instanceof OuterJoinLoadable ) ) { throw new MappingException( "class persister is not OuterJoinLoadable: " + entityName ); } return (OuterJoinLoadable) persister; } @Override public boolean contains(Object object) { checkOpen(); checkTransactionSynchStatus(); if ( object == null ) { return false; } try { 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(); if ( entry == null ) { if ( !HibernateProxy.class.isInstance( object ) && persistenceContext.getEntry( object ) == null ) { // check if it is even an entity -> if not throw an exception (per JPA) try { final String entityName = getEntityNameResolver().resolveEntityName( object ); if ( entityName == null ) { throw new IllegalArgumentException( "Could not resolve entity-name [" + object + "]" ); } getSessionFactory().getMetamodel().entityPersister( entityName ); } catch (HibernateException e) { throw new IllegalArgumentException( "Not an entity [" + object.getClass() + "]", e ); } } return false; } else { return entry.getStatus() != Status.DELETED && entry.getStatus() != Status.GONE; } } catch (MappingException e) { throw new IllegalArgumentException( e.getMessage(), e ); } catch (RuntimeException e) { throw exceptionConverter.convert( e ); } } @Override public boolean contains(String entityName, Object object) { checkOpen(); checkTransactionSynchStatus(); if ( object == null ) { return false; } try { if ( !HibernateProxy.class.isInstance( object ) && persistenceContext.getEntry( object ) == null ) { // check if it is an entity -> if not throw an exception (per JPA) try { getSessionFactory().getMetamodel().entityPersister( entityName ); } catch (HibernateException e) { throw new IllegalArgumentException( "Not an entity [" + entityName + "] : " + object ); } } 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; } catch (MappingException e) { throw new IllegalArgumentException( e.getMessage(), e ); } catch (RuntimeException e) { throw exceptionConverter.convert( e ); } } @Override public ProcedureCall createStoredProcedureCall(String procedureName) { checkOpen(); // checkTransactionSynchStatus(); return super.createStoredProcedureCall( procedureName ); } @Override public ProcedureCall createStoredProcedureCall(String procedureName, String... resultSetMappings) { checkOpen(); // checkTransactionSynchStatus(); return super.createStoredProcedureCall( procedureName, resultSetMappings ); } @Override public ProcedureCall createStoredProcedureCall(String procedureName, Class... resultClasses) { checkOpen(); // checkTransactionSynchStatus(); return super.createStoredProcedureCall( procedureName, resultClasses ); } @Override public ScrollableResultsImplementor scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) { checkOpenOrWaitingForAutoClose(); // checkTransactionSynchStatus(); if ( log.isTraceEnabled() ) { log.tracev( "Scroll SQL query: {0}", customQuery.getSQL() ); } CustomLoader loader = getFactory().getQueryPlanCache().getNativeQueryInterpreter().createCustomLoader( 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) { checkOpenOrWaitingForAutoClose(); // checkTransactionSynchStatus(); if ( log.isTraceEnabled() ) { log.tracev( "SQL query: {0}", customQuery.getSQL() ); } CustomLoader loader = getFactory().getQueryPlanCache().getNativeQueryInterpreter().createCustomLoader( 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 getFactory(); } @Override public void initializeCollection(PersistentCollection collection, boolean writing) { checkOpenOrWaitingForAutoClose(); 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) { checkOpen(); // 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 { checkOpenOrWaitingForAutoClose(); return getEntityNameResolver().resolveEntityName( object ); } @Override public void cancelQuery() throws HibernateException { checkOpen(); getJdbcCoordinator().cancelLastQuery(); } @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( "<closed>" ); } return buf.append( ')' ).toString(); } @Override public ActionQueue getActionQueue() { checkOpenOrWaitingForAutoClose(); // checkTransactionSynchStatus(); return actionQueue; } @Override public PersistenceContext getPersistenceContext() { checkOpenOrWaitingForAutoClose(); // 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) { checkOpen(); // checkTransactionSynchStatus(); return persistenceContext.isReadOnly( entityOrProxy ); } @Override public void setReadOnly(Object entity, boolean readOnly) { checkOpen(); // checkTransactionSynchStatus(); persistenceContext.setReadOnly( entity, readOnly ); } @Override public void doWork(final Work work) throws HibernateException { WorkExecutorVisitable<Void> realWork = new WorkExecutorVisitable<Void>() { @Override public Void accept(WorkExecutor<Void> workExecutor, Connection connection) throws SQLException { workExecutor.executeWork( work, connection ); return null; } }; doWork( realWork ); } @Override public <T> T doReturningWork(final ReturningWork<T> work) throws HibernateException { WorkExecutorVisitable<T> realWork = new WorkExecutorVisitable<T>() { @Override public T accept(WorkExecutor<T> workExecutor, Connection connection) throws SQLException { return workExecutor.executeReturningWork( work, connection ); } }; return doWork( realWork ); } private <T> T doWork(WorkExecutorVisitable<T> work) throws HibernateException { return getJdbcCoordinator().coordinateWork( work ); } @Override public void afterScrollOperation() { // nothing to do in a stateful session } @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) { checkOpen(); checkTransactionSynchStatus(); return loadQueryInfluencers.enableFilter( filterName ); } @Override public void disableFilter(String filterName) { checkOpen(); checkTransactionSynchStatus(); loadQueryInfluencers.disableFilter( filterName ); } // 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 ); } @Override public TypeHelper getTypeHelper() { return getSessionFactory().getTypeHelper(); } @Override public LobHelper getLobHelper() { if ( lobHelper == null ) { lobHelper = new LobHelperImpl( this ); } return lobHelper; } private transient LobHelperImpl lobHelper; @Override public void beforeTransactionCompletion() { log.tracef( "SessionImpl#beforeTransactionCompletion()" ); flushBeforeTransactionCompletion(); actionQueue.beforeTransactionCompletion(); try { getInterceptor().beforeTransactionCompletion( getCurrentTransaction() ); } catch (Throwable t) { log.exceptionInBeforeTransactionCompletionInterceptor( t ); } super.beforeTransactionCompletion(); } @Override public void afterTransactionCompletion(boolean successful, boolean delayed) { log.tracef( "SessionImpl#afterTransactionCompletion(successful=%s, delayed=%s)", successful, delayed ); if ( !isClosed() || waitingForAutoClose ) { if ( autoClear ||!successful ) { internalClear(); } } persistenceContext.afterTransactionCompletion(); actionQueue.afterTransactionCompletion( successful ); getEventListenerManager().transactionCompletion( successful ); if ( getFactory().getStatistics().isStatisticsEnabled() ) { getFactory().getStatistics().endTransaction( successful ); } try { getInterceptor().afterTransactionCompletion( getCurrentTransaction() ); } catch (Throwable t) { log.exceptionInAfterTransactionCompletionInterceptor( t ); } if ( !delayed ) { if ( shouldAutoClose() && (!isClosed() || waitingForAutoClose) ) { managedClose(); } } super.afterTransactionCompletion( successful, delayed ); } 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<T extends SharedSessionBuilder> extends SessionFactoryImpl.SessionBuilderImpl<T> implements SharedSessionBuilder<T>, SharedSessionCreationOptions { private final SessionImpl session; private boolean shareTransactionContext; private SharedSessionBuilderImpl(SessionImpl session) { super( (SessionFactoryImpl) session.getFactory() ); this.session = session; super.owner( session.sessionOwner ); super.tenantIdentifier( session.getTenantIdentifier() ); } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // SharedSessionBuilder @Override public T 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 public T interceptor() { return interceptor( session.getInterceptor() ); } @Override @SuppressWarnings("unchecked") public T connection() { this.shareTransactionContext = true; return (T) this; } @Override public T connectionReleaseMode() { return connectionReleaseMode( session.getJdbcCoordinator().getLogicalConnection().getConnectionHandlingMode().getReleaseMode() ); } @Override public T connectionHandlingMode() { return connectionHandlingMode( session.getJdbcCoordinator().getLogicalConnection().getConnectionHandlingMode() ); } @Override public T autoJoinTransactions() { return autoJoinTransactions( session.isAutoCloseSessionEnabled() ); } @Override public T flushMode() { return flushMode( session.getHibernateFlushMode() ); } @Override public T autoClose() { return autoClose( session.autoClose ); } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // SharedSessionCreationOptions @Override public boolean isTransactionCoordinatorShared() { return shareTransactionContext; } @Override public TransactionCoordinator getTransactionCoordinator() { return shareTransactionContext ? session.getTransactionCoordinator() : null; } @Override public JdbcCoordinator getJdbcCoordinator() { return shareTransactionContext ? session.getJdbcCoordinator() : null; } @Override public TransactionImplementor getTransaction() { return shareTransactionContext ? session.getCurrentTransaction() : null; } @Override public ActionQueue.TransactionCompletionProcesses getTransactionCompletionProcesses() { return shareTransactionContext ? session.getActionQueue().getTransactionCompletionProcesses() : null; } @Override public boolean isQueryParametersValidationEnabled() { return session.isQueryParametersValidationEnabled(); } } 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 ); } } @Override protected void addSharedSessionTransactionObserver(TransactionCoordinator transactionCoordinator) { this.transactionObserver = new TransactionObserver() { @Override public void afterBegin() { } @Override public void beforeCompletion() { if ( isOpen() && getHibernateFlushMode() != FlushMode.MANUAL ) { managedFlush(); } actionQueue.beforeTransactionCompletion(); try { getInterceptor().beforeTransactionCompletion( getCurrentTransaction() ); } catch (Throwable t) { log.exceptionInBeforeTransactionCompletionInterceptor( t ); } } @Override public void afterCompletion(boolean successful, boolean delayed) { afterTransactionCompletion( successful, delayed ); if ( !isClosed() && autoClose ) { managedClose(); } } }; transactionCoordinator.addObserver(transactionObserver); } @Override protected void removeSharedSessionTransactionObserver(TransactionCoordinator transactionCoordinator) { super.removeSharedSessionTransactionObserver( transactionCoordinator ); transactionCoordinator.removeObserver( transactionObserver ); } private class IdentifierLoadAccessImpl<T> implements IdentifierLoadAccess<T> { private final EntityPersister entityPersister; private LockOptions lockOptions; private CacheMode cacheMode; private IdentifierLoadAccessImpl(EntityPersister entityPersister) { this.entityPersister = entityPersister; } private IdentifierLoadAccessImpl(String entityName) { this( locateEntityPersister( entityName ) ); } private IdentifierLoadAccessImpl(Class<T> entityClass) { this( locateEntityPersister( entityClass ) ); } @Override public final IdentifierLoadAccessImpl<T> with(LockOptions lockOptions) { this.lockOptions = lockOptions; return this; } @Override public IdentifierLoadAccess<T> with(CacheMode cacheMode) { this.cacheMode = cacheMode; return this; } @Override public final T getReference(Serializable id) { CacheMode sessionCacheMode = getCacheMode(); boolean cacheModeChanged = false; if ( cacheMode != null ) { // naive check for now... // todo : account for "conceptually equal" if ( cacheMode != sessionCacheMode ) { setCacheMode( cacheMode ); cacheModeChanged = true; } } try { return doGetReference( id ); } finally { if ( cacheModeChanged ) { // change it back setCacheMode( sessionCacheMode ); } } } @SuppressWarnings("unchecked") protected T doGetReference(Serializable id) { if ( this.lockOptions != null ) { LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), lockOptions, SessionImpl.this ); fireLoad( event, LoadEventListener.LOAD ); return (T) 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 (T) event.getResult(); } finally { afterOperation( success ); } } @Override public final T load(Serializable id) { CacheMode sessionCacheMode = getCacheMode(); boolean cacheModeChanged = false; if ( cacheMode != null ) { // naive check for now... // todo : account for "conceptually equal" if ( cacheMode != sessionCacheMode ) { setCacheMode( cacheMode ); cacheModeChanged = true; } } try { return doLoad( id ); } finally { if ( cacheModeChanged ) { // change it back setCacheMode( sessionCacheMode ); } } } @Override public Optional<T> loadOptional(Serializable id) { return Optional.ofNullable( load( id ) ); } @SuppressWarnings("unchecked") protected final T doLoad(Serializable id) { if ( this.lockOptions != null ) { LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), lockOptions, SessionImpl.this ); fireLoad( event, LoadEventListener.GET ); return (T) 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 (T) event.getResult(); } } private class MultiIdentifierLoadAccessImpl<T> implements MultiIdentifierLoadAccess<T>, MultiLoadOptions { private final EntityPersister entityPersister; private LockOptions lockOptions; private CacheMode cacheMode; private Integer batchSize; private boolean sessionCheckingEnabled; private boolean returnOfDeletedEntitiesEnabled; private boolean orderedReturnEnabled = true; public MultiIdentifierLoadAccessImpl(EntityPersister entityPersister) { this.entityPersister = entityPersister; } @Override public LockOptions getLockOptions() { return lockOptions; } @Override public final MultiIdentifierLoadAccessImpl<T> with(LockOptions lockOptions) { this.lockOptions = lockOptions; return this; } @Override public MultiIdentifierLoadAccessImpl<T> with(CacheMode cacheMode) { this.cacheMode = cacheMode; return this; } @Override public Integer getBatchSize() { return batchSize; } @Override public MultiIdentifierLoadAccess<T> withBatchSize(int batchSize) { if ( batchSize < 1 ) { this.batchSize = null; } else { this.batchSize = batchSize; } return this; } @Override public boolean isSessionCheckingEnabled() { return sessionCheckingEnabled; } @Override public MultiIdentifierLoadAccess<T> enableSessionCheck(boolean enabled) { this.sessionCheckingEnabled = enabled; return this; } @Override public boolean isReturnOfDeletedEntitiesEnabled() { return returnOfDeletedEntitiesEnabled; } @Override public MultiIdentifierLoadAccess<T> enableReturnOfDeletedEntities(boolean enabled) { this.returnOfDeletedEntitiesEnabled = enabled; return this; } @Override public boolean isOrderReturnEnabled() { return orderedReturnEnabled; } @Override public MultiIdentifierLoadAccess<T> enableOrderedReturn(boolean enabled) { this.orderedReturnEnabled = enabled; return this; } @Override @SuppressWarnings("unchecked") public <K extends Serializable> List<T> multiLoad(K... ids) { CacheMode sessionCacheMode = getCacheMode(); boolean cacheModeChanged = false; if ( cacheMode != null ) { // naive check for now... // todo : account for "conceptually equal" if ( cacheMode != sessionCacheMode ) { setCacheMode( cacheMode ); cacheModeChanged = true; } } try { return entityPersister.multiLoad( ids, SessionImpl.this, this ); } finally { if ( cacheModeChanged ) { // change it back setCacheMode( sessionCacheMode ); } } } @Override @SuppressWarnings("unchecked") public <K extends Serializable> List<T> multiLoad(List<K> ids) { CacheMode sessionCacheMode = getCacheMode(); boolean cacheModeChanged = false; if ( cacheMode != null ) { // naive check for now... // todo : account for "conceptually equal" if ( cacheMode != sessionCacheMode ) { setCacheMode( cacheMode ); cacheModeChanged = true; } } try { return entityPersister.multiLoad( ids.toArray( new Serializable[ ids.size() ] ), SessionImpl.this, this ); } finally { if ( cacheModeChanged ) { // change it back setCacheMode( sessionCacheMode ); } } } } private EntityPersister locateEntityPersister(Class entityClass) { return getFactory().getMetamodel().locateEntityPersister( entityClass ); } private EntityPersister locateEntityPersister(String entityName) { return getFactory().getMetamodel().locateEntityPersister( entityName ); } private abstract class BaseNaturalIdLoadAccessImpl<T> { 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() ) ); } } public BaseNaturalIdLoadAccessImpl<T> with(LockOptions lockOptions) { this.lockOptions = lockOptions; return this; } protected void synchronizationEnabled(boolean synchronizationEnabled) { this.synchronizationEnabled = synchronizationEnabled; } protected final Serializable resolveNaturalId(Map<String, Object> 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<T> extends BaseNaturalIdLoadAccessImpl<T> implements NaturalIdLoadAccess<T> { private final Map<String, Object> naturalIdParameters = new LinkedHashMap<String, Object>(); private NaturalIdLoadAccessImpl(EntityPersister entityPersister) { super( entityPersister ); } private NaturalIdLoadAccessImpl(String entityName) { this( locateEntityPersister( entityName ) ); } private NaturalIdLoadAccessImpl(Class entityClass) { this( locateEntityPersister( entityClass ) ); } @Override public NaturalIdLoadAccessImpl<T> with(LockOptions lockOptions) { return (NaturalIdLoadAccessImpl<T>) super.with( lockOptions ); } @Override public NaturalIdLoadAccess<T> using(String attributeName, Object value) { naturalIdParameters.put( attributeName, value ); return this; } @Override public NaturalIdLoadAccessImpl<T> setSynchronizationEnabled(boolean synchronizationEnabled) { super.synchronizationEnabled( synchronizationEnabled ); return this; } @Override @SuppressWarnings("unchecked") public final T getReference() { final Serializable entityId = resolveNaturalId( this.naturalIdParameters ); if ( entityId == null ) { return null; } return (T) this.getIdentifierLoadAccess().getReference( entityId ); } @Override @SuppressWarnings("unchecked") public final T load() { final Serializable entityId = resolveNaturalId( this.naturalIdParameters ); if ( entityId == null ) { return null; } try { return (T) this.getIdentifierLoadAccess().load( entityId ); } catch (EntityNotFoundException | ObjectNotFoundException enf) { // OK } return null; } @Override public Optional<T> loadOptional() { return Optional.ofNullable( load() ); } } private class SimpleNaturalIdLoadAccessImpl<T> extends BaseNaturalIdLoadAccessImpl<T> implements SimpleNaturalIdLoadAccess<T> { 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( locateEntityPersister( entityClass ) ); } @Override public final SimpleNaturalIdLoadAccessImpl<T> with(LockOptions lockOptions) { return (SimpleNaturalIdLoadAccessImpl<T>) super.with( lockOptions ); } private Map<String, Object> getNaturalIdParameters(Object naturalIdValue) { return Collections.singletonMap( naturalIdAttributeName, naturalIdValue ); } @Override public SimpleNaturalIdLoadAccessImpl<T> setSynchronizationEnabled(boolean synchronizationEnabled) { super.synchronizationEnabled( synchronizationEnabled ); return this; } @Override @SuppressWarnings("unchecked") public T getReference(Object naturalIdValue) { final Serializable entityId = resolveNaturalId( getNaturalIdParameters( naturalIdValue ) ); if ( entityId == null ) { return null; } return (T) this.getIdentifierLoadAccess().getReference( entityId ); } @Override @SuppressWarnings("unchecked") public T load(Object naturalIdValue) { final Serializable entityId = resolveNaturalId( getNaturalIdParameters( naturalIdValue ) ); if ( entityId == null ) { return null; } try { return (T) this.getIdentifierLoadAccess().load( entityId ); } catch (EntityNotFoundException | ObjectNotFoundException e) { // OK } return null; } @Override public Optional<T> loadOptional(Serializable naturalIdValue) { return Optional.ofNullable( load( naturalIdValue ) ); } } @Override public void startTransactionBoundary() { checkOpenOrWaitingForAutoClose(); super.startTransactionBoundary(); } @Override public void afterTransactionBegin() { checkOpenOrWaitingForAutoClose(); getInterceptor().afterTransactionBegin( getCurrentTransaction() ); } @Override public void flushBeforeTransactionCompletion() { final boolean doFlush = isTransactionFlushable() && getHibernateFlushMode() != FlushMode.MANUAL; try { if ( doFlush ) { managedFlush(); } } catch (RuntimeException re) { throw exceptionMapper.mapManagedFlushFailure( "error during managed flush", re, this ); } } private boolean isTransactionFlushable() { if ( getCurrentTransaction() == null ) { // assume it is flushable - CMT, auto-commit, etc return true; } final TransactionStatus status = getCurrentTransaction().getStatus(); return status == TransactionStatus.ACTIVE || status == TransactionStatus.COMMITTING; } @Override public boolean isFlushBeforeCompletionEnabled() { return getHibernateFlushMode() != FlushMode.MANUAL; } private static final AfterCompletionAction STANDARD_AFTER_COMPLETION_ACTION = (AfterCompletionAction) (successful, session) -> { // nothing to do by default. }; public static class ManagedFlushCheckerStandardImpl implements ManagedFlushChecker { @Override public boolean shouldDoManagedFlush(SessionImplementor session) { if ( session.isClosed() ) { return false; } return session.getHibernateFlushMode() != FlushMode.MANUAL; } } private static final ManagedFlushCheckerStandardImpl STANDARD_MANAGED_FLUSH_CHECKER = new ManagedFlushCheckerStandardImpl() { }; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // HibernateEntityManager impl @Override public SessionImplementor getSession() { return this; } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // HibernateEntityManagerImplementor impl @Override public LockOptions getLockRequest(LockModeType lockModeType, Map<String, Object> properties) { LockOptions lockOptions = new LockOptions(); LockOptions.copy( this.lockOptions, lockOptions ); lockOptions.setLockMode( LockModeTypeHelper.getLockMode( lockModeType ) ); if ( properties != null ) { setLockOptions( properties, lockOptions ); } return lockOptions; } private void setLockOptions(Map<String, Object> props, LockOptions options) { Object lockScope = props.get( JPA_LOCK_SCOPE ); if ( lockScope instanceof String && PessimisticLockScope.valueOf( ( String ) lockScope ) == PessimisticLockScope.EXTENDED ) { options.setScope( true ); } else if ( lockScope instanceof PessimisticLockScope ) { boolean extended = PessimisticLockScope.EXTENDED.equals( lockScope ); options.setScope( extended ); } else if ( lockScope != null ) { throw new PersistenceException( "Unable to parse " + JPA_LOCK_SCOPE + ": " + lockScope ); } Object lockTimeout = props.get( JPA_LOCK_TIMEOUT ); int timeout = 0; boolean timeoutSet = false; if ( lockTimeout instanceof String ) { timeout = Integer.parseInt( ( String ) lockTimeout ); timeoutSet = true; } else if ( lockTimeout instanceof Number ) { timeout = ( (Number) lockTimeout ).intValue(); timeoutSet = true; } else if ( lockTimeout != null ) { throw new PersistenceException( "Unable to parse " + JPA_LOCK_TIMEOUT + ": " + lockTimeout ); } if ( timeoutSet ) { if ( timeout == LockOptions.SKIP_LOCKED ) { options.setTimeOut( LockOptions.SKIP_LOCKED ); } else if ( timeout < 0 ) { options.setTimeOut( LockOptions.WAIT_FOREVER ); } else if ( timeout == 0 ) { options.setTimeOut( LockOptions.NO_WAIT ); } else { options.setTimeOut( timeout ); } } } @Override @SuppressWarnings("unchecked") public <T> QueryImplementor<T> createQuery( String jpaqlString, Class<T> resultClass, Selection selection, QueryOptions queryOptions) { try { final QueryImplementor query = createQuery( jpaqlString ); if ( queryOptions.getValueHandlers() == null ) { if ( queryOptions.getResultMetadataValidator() != null ) { queryOptions.getResultMetadataValidator().validate( query.getReturnTypes() ); } } // determine if we need a result transformer List tupleElements = Tuple.class.equals( resultClass ) ? ( (CompoundSelectionImpl<Tuple>) selection ).getCompoundSelectionItems() : null; if ( queryOptions.getValueHandlers() != null || tupleElements != null ) { query.setResultTransformer( new CriteriaQueryTupleTransformer( queryOptions.getValueHandlers(), tupleElements ) ); } return query; } catch ( RuntimeException e ) { throw exceptionConverter.convert( e ); } } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // EntityManager impl @Override public void remove(Object entity) { checkOpen(); try { delete( entity ); } catch (MappingException e) { throw exceptionConverter.convert( new IllegalArgumentException( e.getMessage(), e ) ); } catch ( RuntimeException e ) { //including HibernateException throw exceptionConverter.convert( e ); } } @Override public <T> T find(Class<T> entityClass, Object primaryKey) { return find( entityClass, primaryKey, null, null ); } @Override public <T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties) { return find( entityClass, primaryKey, null, properties ); } @Override public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockModeType) { return find( entityClass, primaryKey, lockModeType, null ); } @Override public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockModeType, Map<String, Object> properties) { checkOpen(); LockOptions lockOptions = null; try { if ( properties != null && !properties.isEmpty() ) { getLoadQueryInfluencers().setFetchGraph( (EntityGraph) properties.get( QueryHints.HINT_FETCHGRAPH ) ); getLoadQueryInfluencers().setLoadGraph( (EntityGraph) properties.get( QueryHints.HINT_LOADGRAPH ) ); } final IdentifierLoadAccess<T> loadAccess = byId( entityClass ); loadAccess.with( determineAppropriateLocalCacheMode( properties ) ); if ( lockModeType != null ) { if ( !LockModeType.NONE.equals( lockModeType) ) { checkTransactionNeeded(); } lockOptions = buildLockOptions( lockModeType, properties ); loadAccess.with( lockOptions ); } return loadAccess.load( (Serializable) primaryKey ); } catch ( EntityNotFoundException ignored ) { // DefaultLoadEventListener.returnNarrowedProxy may throw ENFE (see HHH-7861 for details), // which find() should not throw. Find() should return null if the entity was not found. if ( log.isDebugEnabled() ) { String entityName = entityClass != null ? entityClass.getName(): null; String identifierValue = primaryKey != null ? primaryKey.toString() : null ; log.ignoringEntityNotFound( entityName, identifierValue ); } return null; } catch ( ObjectDeletedException e ) { //the spec is silent about people doing remove() find() on the same PC return null; } catch ( ObjectNotFoundException e ) { //should not happen on the entity itself with get throw new IllegalArgumentException( e.getMessage(), e ); } catch ( MappingException | TypeMismatchException | ClassCastException e ) { throw exceptionConverter.convert( new IllegalArgumentException( e.getMessage(), e ) ); } catch ( JDBCException e ) { if ( accessTransaction().getRollbackOnly() ) { // assume this is the similar to the WildFly / IronJacamar "feature" described under HHH-12472 return null; } else { throw exceptionConverter.convert( e, lockOptions ); } } catch ( RuntimeException e ) { throw exceptionConverter.convert( e, lockOptions ); } finally { getLoadQueryInfluencers().setFetchGraph( null ); getLoadQueryInfluencers().setLoadGraph( null ); } } private CacheMode determineAppropriateLocalCacheMode(Map<String, Object> localProperties) { CacheRetrieveMode retrieveMode = null; CacheStoreMode storeMode = null; if ( localProperties != null ) { retrieveMode = determineCacheRetrieveMode( localProperties ); storeMode = determineCacheStoreMode( localProperties ); } if ( retrieveMode == null ) { // use the EM setting retrieveMode = determineCacheRetrieveMode( this.properties ); } if ( storeMode == null ) { // use the EM setting storeMode = determineCacheStoreMode( this.properties ); } return CacheModeHelper.interpretCacheMode( storeMode, retrieveMode ); } private CacheRetrieveMode determineCacheRetrieveMode(Map<String, Object> settings) { return ( CacheRetrieveMode ) settings.get( JPA_SHARED_CACHE_RETRIEVE_MODE ); } private CacheStoreMode determineCacheStoreMode(Map<String, Object> settings) { return ( CacheStoreMode ) settings.get( JPA_SHARED_CACHE_STORE_MODE ); } private void checkTransactionNeeded() { if ( disallowOutOfTransactionUpdateOperations && !isTransactionInProgress() ) { throw new TransactionRequiredException( "no transaction is in progress" ); } } @Override public <T> T getReference(Class<T> entityClass, Object primaryKey) { checkOpen(); try { return byId( entityClass ).getReference( (Serializable) primaryKey ); } catch ( MappingException | TypeMismatchException | ClassCastException e ) { throw exceptionConverter.convert( new IllegalArgumentException( e.getMessage(), e ) ); } catch ( RuntimeException e ) { throw exceptionConverter.convert( e ); } } @Override public void lock(Object entity, LockModeType lockModeType) { lock( entity, lockModeType, null ); } @Override public void lock(Object entity, LockModeType lockModeType, Map<String, Object> properties) { checkOpen(); checkTransactionNeeded(); if ( !contains( entity ) ) { throw new IllegalArgumentException( "entity not in the persistence context" ); } final LockOptions lockOptions = buildLockOptions( lockModeType, properties ); try { buildLockRequest( lockOptions ).lock( entity ); } catch (RuntimeException e) { throw exceptionConverter.convert( e, lockOptions ); } } @Override public void refresh(Object entity, Map<String, Object> properties) { refresh( entity, null, properties ); } @Override public void refresh(Object entity, LockModeType lockModeType) { refresh( entity, lockModeType, null ); } @Override public void refresh(Object entity, LockModeType lockModeType, Map<String, Object> properties) { checkOpen(); final CacheMode previousCacheMode = getCacheMode(); final CacheMode refreshCacheMode = determineAppropriateLocalCacheMode( properties ); LockOptions lockOptions = null; try { setCacheMode( refreshCacheMode ); if ( !contains( entity ) ) { throw exceptionConverter.convert( new IllegalArgumentException( "Entity not managed" ) ); } if ( lockModeType != null ) { if ( !LockModeType.NONE.equals( lockModeType) ) { checkTransactionNeeded(); } lockOptions = buildLockOptions( lockModeType, properties ); refresh( entity, lockOptions ); } else { refresh( entity ); } } catch (MappingException e) { throw exceptionConverter.convert( new IllegalArgumentException( e.getMessage(), e ) ); } catch (RuntimeException e) { throw exceptionConverter.convert( e, lockOptions ); } finally { setCacheMode( previousCacheMode ); } } @Override public void detach(Object entity) { checkOpen(); try { evict( entity ); } catch (RuntimeException e) { throw exceptionConverter.convert( e ); } } @Override public LockModeType getLockMode(Object entity) { checkOpen(); if ( !isTransactionInProgress() ) { throw new TransactionRequiredException( "Call to EntityManager#getLockMode should occur within transaction according to spec" ); } if ( !contains( entity ) ) { throw exceptionConverter.convert( new IllegalArgumentException( "entity not in the persistence context" ) ); } return LockModeTypeHelper.getLockModeType( getCurrentLockMode( entity ) ); } @Override public void setProperty(String propertyName, Object value) { checkOpen(); if ( !( value instanceof Serializable ) ) { log.warnf( "Property '" + propertyName + "' is not serializable, value won't be set." ); return; } properties.put( propertyName, value ); applyProperties(); } @Override public Map<String, Object> getProperties() { return Collections.unmodifiableMap( properties ); } private CriteriaCompiler criteriaCompiler; @SuppressWarnings("WeakerAccess") protected CriteriaCompiler criteriaCompiler() { if ( criteriaCompiler == null ) { criteriaCompiler = new CriteriaCompiler( this ); } return criteriaCompiler; } @Override @SuppressWarnings("unchecked") public <T> QueryImplementor<T> createQuery(CriteriaQuery<T> criteriaQuery) { checkOpen(); try { return (QueryImplementor<T>) criteriaCompiler().compile( (CompilableCriteria) criteriaQuery ); } catch ( RuntimeException e ) { throw exceptionConverter.convert( e ); } } @Override public QueryImplementor createQuery(CriteriaUpdate criteriaUpdate) { checkOpen(); try { return criteriaCompiler().compile( (CompilableCriteria) criteriaUpdate ); } catch ( RuntimeException e ) { throw exceptionConverter.convert( e ); } } @Override public QueryImplementor createQuery(CriteriaDelete criteriaDelete) { checkOpen(); try { return criteriaCompiler().compile( (CompilableCriteria) criteriaDelete ); } catch ( RuntimeException e ) { throw exceptionConverter.convert( e ); } } @Override protected void initQueryFromNamedDefinition(Query query, NamedQueryDefinition namedQueryDefinition) { super.initQueryFromNamedDefinition( query, namedQueryDefinition ); if ( namedQueryDefinition.isCacheable() ) { query.setHint( QueryHints.HINT_CACHEABLE, true ); if ( namedQueryDefinition.getCacheRegion() != null ) { query.setHint( QueryHints.HINT_CACHE_REGION, namedQueryDefinition.getCacheRegion() ); } } if ( namedQueryDefinition.getCacheMode() != null ) { query.setHint( QueryHints.HINT_CACHE_MODE, namedQueryDefinition.getCacheMode() ); } if ( namedQueryDefinition.isReadOnly() ) { query.setHint( QueryHints.HINT_READONLY, true ); } if ( namedQueryDefinition.getTimeout() != null ) { query.setHint( QueryHints.SPEC_HINT_TIMEOUT, namedQueryDefinition.getTimeout() * 1000 ); } if ( namedQueryDefinition.getFetchSize() != null ) { query.setHint( QueryHints.HINT_FETCH_SIZE, namedQueryDefinition.getFetchSize() ); } if ( namedQueryDefinition.getComment() != null ) { query.setHint( QueryHints.HINT_COMMENT, namedQueryDefinition.getComment() ); } if ( namedQueryDefinition.getFirstResult() != null ) { query.setFirstResult( namedQueryDefinition.getFirstResult() ); } if ( namedQueryDefinition.getMaxResults() != null ) { query.setMaxResults( namedQueryDefinition.getMaxResults() ); } if ( namedQueryDefinition.getLockOptions() != null ) { if ( namedQueryDefinition.getLockOptions().getLockMode() != null ) { query.setLockMode( LockModeTypeHelper.getLockModeType( namedQueryDefinition.getLockOptions().getLockMode() ) ); } } if ( namedQueryDefinition.getFlushMode() != null ) { if ( namedQueryDefinition.getFlushMode() == FlushMode.COMMIT ) { query.setFlushMode( FlushModeType.COMMIT ); } else { query.setFlushMode( FlushModeType.AUTO ); } } } @Override public StoredProcedureQuery createNamedStoredProcedureQuery(String name) { checkOpen(); try { final ProcedureCallMemento memento = getFactory().getNamedQueryRepository().getNamedProcedureCallMemento( name ); if ( memento == null ) { throw new IllegalArgumentException( "No @NamedStoredProcedureQuery was found with that name : " + name ); } return memento.makeProcedureCall( this ); } catch ( RuntimeException e ) { throw exceptionConverter.convert( e ); } } @Override public StoredProcedureQuery createStoredProcedureQuery(String procedureName) { try { return createStoredProcedureCall( procedureName ); } catch ( RuntimeException e ) { throw exceptionConverter.convert( e ); } } @Override public StoredProcedureQuery createStoredProcedureQuery(String procedureName, Class... resultClasses) { try { return createStoredProcedureCall( procedureName, resultClasses ); } catch ( RuntimeException e ) { throw exceptionConverter.convert( e ); } } @Override public StoredProcedureQuery createStoredProcedureQuery(String procedureName, String... resultSetMappings) { checkOpen(); try { try { return createStoredProcedureCall( procedureName, resultSetMappings ); } catch (UnknownSqlResultSetMappingException unknownResultSetMapping) { throw new IllegalArgumentException( unknownResultSetMapping.getMessage(), unknownResultSetMapping ); } } catch ( RuntimeException e ) { throw exceptionConverter.convert( e ); } } @Override public void joinTransaction() { checkOpen(); joinTransaction( true ); } private void joinTransaction(boolean explicitRequest) { if ( !getTransactionCoordinator().getTransactionCoordinatorBuilder().isJta() ) { if ( explicitRequest ) { log.callingJoinTransactionOnNonJtaEntityManager(); } return; } try { getTransactionCoordinator().explicitJoin(); } catch (TransactionRequiredForJoinException e) { throw new TransactionRequiredException( e.getMessage() ); } catch (HibernateException he) { throw exceptionConverter.convert( he ); } } @Override public boolean isJoinedToTransaction() { checkOpen(); return getTransactionCoordinator().isJoined(); } @Override @SuppressWarnings("unchecked") public <T> T unwrap(Class<T> clazz) { checkOpen(); if ( Session.class.isAssignableFrom( clazz ) ) { return (T) this; } if ( SessionImplementor.class.isAssignableFrom( clazz ) ) { return (T) this; } if ( SharedSessionContractImplementor.class.isAssignableFrom( clazz ) ) { return (T) this; } if ( EntityManager.class.isAssignableFrom( clazz ) ) { return (T) this; } throw new PersistenceException( "Hibernate cannot unwrap " + clazz ); } @Override public Object getDelegate() { checkOpen(); return this; } @Override public SessionFactoryImplementor getEntityManagerFactory() { checkOpen(); return getFactory(); } @Override public CriteriaBuilder getCriteriaBuilder() { checkOpen(); return getFactory().getCriteriaBuilder(); } @Override public MetamodelImplementor getMetamodel() { checkOpen(); return getFactory().getMetamodel(); } @Override public <T> EntityGraph<T> createEntityGraph(Class<T> rootType) { checkOpen(); return new EntityGraphImpl<T>( null, getMetamodel().entity( rootType ), getEntityManagerFactory() ); } @Override public EntityGraph<?> createEntityGraph(String graphName) { checkOpen(); final EntityGraph named = getEntityManagerFactory().findEntityGraphByName( graphName ); if ( named == null ) { return null; } if ( EntityGraphImplementor.class.isInstance( named ) ) { return ( (EntityGraphImplementor) named ).makeMutableCopy(); } else { return named; } } @Override @SuppressWarnings("unchecked") public EntityGraph<?> getEntityGraph(String graphName) { checkOpen(); final EntityGraph named = getEntityManagerFactory().findEntityGraphByName( graphName ); if ( named == null ) { throw new IllegalArgumentException( "Could not locate EntityGraph with given name : " + graphName ); } return named; } @Override public <T> List<EntityGraph<? super T>> getEntityGraphs(Class<T> entityClass) { checkOpen(); return getEntityManagerFactory().findEntityGraphsByType( entityClass ); }
Used by JDK serialization...
Params:
  • oos – The output stream to which we are being written...
Throws:
  • IOException – Indicates a general IO stream exception
/** * 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 ( TRACE_ENABLED ) { log.tracef( "Serializing Session [%s]", getSessionIdentifier() ); } oos.defaultWriteObject(); persistenceContext.serialize( oos ); actionQueue.serialize( oos ); oos.writeObject( loadQueryInfluencers ); }
Used by JDK serialization...
Params:
  • ois – The input stream from which we are being read...
Throws:
/** * 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, SQLException { if ( TRACE_ENABLED ) { log.tracef( "Deserializing Session [%s]", getSessionIdentifier() ); } ois.defaultReadObject(); 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( getFactory() ); } initializeFromSessionOwner( null ); this.disallowOutOfTransactionUpdateOperations = !getFactory().getSessionFactoryOptions().isAllowOutOfTransactionUpdateOperations(); this.discardOnClose = getFactory().getSessionFactoryOptions().isReleaseResourcesOnCloseEnabled(); } }