diff --git a/hibernate-core/src/main/java/org/hibernate/SessionBuilder.java b/hibernate-core/src/main/java/org/hibernate/SessionBuilder.java
index a064ede186bc..703b5b9be449 100644
--- a/hibernate-core/src/main/java/org/hibernate/SessionBuilder.java
+++ b/hibernate-core/src/main/java/org/hibernate/SessionBuilder.java
@@ -8,6 +8,7 @@
import java.util.TimeZone;
import java.util.function.UnaryOperator;
+import org.hibernate.engine.creation.CommonBuilder;
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
import org.hibernate.resource.jdbc.spi.StatementInspector;
@@ -18,7 +19,7 @@
*
* @see SessionFactory#withOptions()
*/
-public interface SessionBuilder {
+public interface SessionBuilder extends CommonBuilder {
/**
* Opens a session with the specified options.
*
@@ -26,41 +27,13 @@ public interface SessionBuilder {
*/
Session openSession();
- /**
- * Adds a specific interceptor to the session options.
- *
- * @param interceptor The interceptor to use.
- *
- * @return {@code this}, for method chaining
- */
+ @Override
SessionBuilder interceptor(Interceptor interceptor);
- /**
- * Signifies that no {@link Interceptor} should be used.
- *
- * By default, if no {@code Interceptor} is explicitly specified, the
- * {@code Interceptor} associated with the {@link SessionFactory} is
- * inherited by the new {@link Session}.
- *
- * Calling {@link #interceptor(Interceptor)} with null has the same effect.
- *
- * @return {@code this}, for method chaining
- */
+ @Override
SessionBuilder noInterceptor();
- /**
- * Applies the given statement inspection function to the session.
- *
- * @param operator An operator which accepts a SQL string, returning
- * a processed SQL string to be used by Hibernate
- * instead of the given original SQL. Alternatively.
- * the operator may work by side effect, and simply
- * return the original SQL.
- *
- * @return {@code this}, for method chaining
- *
- * @since 7.0
- */
+ @Override
SessionBuilder statementInspector(UnaryOperator operator);
/**
@@ -163,60 +136,13 @@ public interface SessionBuilder {
* @return {@code this}, for method chaining
* @since 6.4
*/
+ @Override
SessionBuilder tenantIdentifier(Object tenantIdentifier);
- /**
- * Specify a {@linkplain Session#isDefaultReadOnly read-only mode}
- * for the session. If a session is created in read-only mode, then
- * {@link Connection#setReadOnly} is called when a JDBC connection
- * is obtained.
- *
- * Furthermore, if read/write replication is in use, then:
- *
- *
a read-only session will connect to a read-only replica, but
- *
a non-read-only session will connect to a writable replica.
- *
- *
- * When read/write replication is in use, it's strongly recommended
- * that the session be created with the {@linkplain #initialCacheMode
- * initial cache mode} set to {@link CacheMode#GET}, to avoid writing
- * stale data read from a read-only replica to the second-level cache.
- * Hibernate cannot possibly guarantee that data read from a read-only
- * replica is up to date.
- *
- * When read/write replication is in use, it's possible that an item
- * read from the second-level cache might refer to data which does not
- * yet exist in the read-only replica. In this situation, an exception
- * occurs when the association is fetched. To completely avoid this
- * possibility, the {@linkplain #initialCacheMode initial cache mode}
- * must be set to {@link CacheMode#IGNORE}. However, it's also usually
- * possible to structure data access code in a way which eliminates
- * this possibility.
- *
- * If a session is created in read-only mode, then it cannot be
- * changed to read-write mode, and any call to
- * {@link Session#setDefaultReadOnly(boolean)} with fail. On the
- * other hand, if a session is created in read-write mode, then it
- * may later be switched to read-only mode, but all database access
- * is directed to the writable replica.
- *
- * @return {@code this}, for method chaining
- * @since 7.2
- *
- * @see org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider#getReadOnlyConnection(Object)
- * @see org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider#releaseReadOnlyConnection(Object, Connection)
- */
- @Incubating
+ @Override
SessionBuilder readOnly(boolean readOnly);
- /**
- * Specify the initial {@link CacheMode} for the session.
- *
- * @return {@code this}, for method chaining
- * @since 7.2
- *
- * @see SharedSessionContract#getCacheMode()
- */
+ @Override
SessionBuilder initialCacheMode(CacheMode cacheMode);
/**
diff --git a/hibernate-core/src/main/java/org/hibernate/SharedSessionBuilder.java b/hibernate-core/src/main/java/org/hibernate/SharedSessionBuilder.java
index ad4374c1363e..7983ae2f6fff 100644
--- a/hibernate-core/src/main/java/org/hibernate/SharedSessionBuilder.java
+++ b/hibernate-core/src/main/java/org/hibernate/SharedSessionBuilder.java
@@ -4,6 +4,7 @@
*/
package org.hibernate;
+import org.hibernate.engine.creation.CommonSharedBuilder;
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
import org.hibernate.resource.jdbc.spi.StatementInspector;
@@ -18,20 +19,12 @@
*
* @see Session#sessionWithOptions()
*/
-public interface SharedSessionBuilder extends SessionBuilder {
+public interface SharedSessionBuilder extends SessionBuilder, CommonSharedBuilder {
- /**
- * Signifies that the connection from the original session should be used to create the new session.
- *
- * @return {@code this}, for method chaining
- */
+ @Override
SharedSessionBuilder connection();
- /**
- * Signifies the interceptor from the original session should be used to create the new session.
- *
- * @return {@code this}, for method chaining
- */
+ @Override
SharedSessionBuilder interceptor();
/**
@@ -76,7 +69,7 @@ public interface SharedSessionBuilder extends SessionBuilder {
SharedSessionBuilder statementInspector(StatementInspector statementInspector);
@Override
- SessionBuilder statementInspector(UnaryOperator operator);
+ SharedSessionBuilder statementInspector(UnaryOperator operator);
@Override @Deprecated
SharedSessionBuilder connectionHandlingMode(PhysicalConnectionHandlingMode mode);
diff --git a/hibernate-core/src/main/java/org/hibernate/SharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/SharedSessionContract.java
index bf1ced5dff72..36c692e338ac 100644
--- a/hibernate-core/src/main/java/org/hibernate/SharedSessionContract.java
+++ b/hibernate-core/src/main/java/org/hibernate/SharedSessionContract.java
@@ -26,6 +26,18 @@
* @author Steve Ebersole
*/
public interface SharedSessionContract extends QueryProducer, AutoCloseable, Serializable {
+
+ /**
+ * Obtain a {@link StatelessSession} builder with the ability to copy certain
+ * information from this session.
+ *
+ * @return the session builder
+ *
+ * @since 7.2
+ */
+ @Incubating
+ SharedStatelessSessionBuilder statelessWithOptions();
+
/**
* Obtain the tenant identifier associated with this session, as a string.
*
diff --git a/hibernate-core/src/main/java/org/hibernate/SharedStatelessSessionBuilder.java b/hibernate-core/src/main/java/org/hibernate/SharedStatelessSessionBuilder.java
new file mode 100644
index 000000000000..8243586d1341
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/SharedStatelessSessionBuilder.java
@@ -0,0 +1,58 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate;
+
+import org.hibernate.engine.creation.CommonSharedBuilder;
+
+import java.util.function.UnaryOperator;
+
+/**
+ * Allows for creation of a {@linkplain StatelessSession stateless session} sharing the
+ * underpinnings of another {@linkplain Session stateful} or {@linkplain StatelessSession stateless}
+ * session.
+ *
+ * @see Session#statelessWithOptions()
+ * @see StatelessSession#statelessWithOptions()
+ *
+ * @since 7.2
+ *
+ * @author Steve Ebersole
+ */
+@Incubating
+public interface SharedStatelessSessionBuilder extends CommonSharedBuilder {
+ /**
+ * Open the stateless session.
+ */
+ StatelessSession open();
+
+ @Override
+ SharedStatelessSessionBuilder connection();
+
+ @Override
+ SharedStatelessSessionBuilder interceptor();
+
+ @Override
+ SharedStatelessSessionBuilder interceptor(Interceptor interceptor);
+
+ @Override
+ SharedStatelessSessionBuilder noInterceptor();
+
+ SharedStatelessSessionBuilder statementInspector(UnaryOperator operator);
+
+ @Override
+ SharedStatelessSessionBuilder statementInspector();
+
+ @Override
+ SharedStatelessSessionBuilder noStatementInspector();
+
+ @Override
+ SharedStatelessSessionBuilder tenantIdentifier(Object tenantIdentifier);
+
+ @Override
+ SharedStatelessSessionBuilder readOnly(boolean readOnly);
+
+ @Override
+ SharedStatelessSessionBuilder initialCacheMode(CacheMode cacheMode);
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/StatelessSessionBuilder.java b/hibernate-core/src/main/java/org/hibernate/StatelessSessionBuilder.java
index 37d10c9d7e53..6f8658497490 100644
--- a/hibernate-core/src/main/java/org/hibernate/StatelessSessionBuilder.java
+++ b/hibernate-core/src/main/java/org/hibernate/StatelessSessionBuilder.java
@@ -7,6 +7,7 @@
import java.sql.Connection;
import java.util.function.UnaryOperator;
+import org.hibernate.engine.creation.CommonBuilder;
import org.hibernate.resource.jdbc.spi.StatementInspector;
/**
@@ -16,7 +17,7 @@
*
* @see SessionFactory#withStatelessOptions()
*/
-public interface StatelessSessionBuilder {
+public interface StatelessSessionBuilder extends CommonBuilder {
/**
* Opens a session with the specified options.
*
@@ -24,110 +25,34 @@ public interface StatelessSessionBuilder {
*/
StatelessSession openStatelessSession();
- /**
- * Adds a specific connection to the session options.
- *
- * @param connection The connection to use.
- *
- * @return {@code this}, for method chaining
- */
+ @Override
StatelessSessionBuilder connection(Connection connection);
- /**
- * Specifies the connection handling modes for the session.
- *
- * Note that if {@link ConnectionAcquisitionMode#IMMEDIATELY} is specified,
- * then the release mode must be {@link ConnectionReleaseMode#ON_CLOSE}.
- *
- * @return {@code this}, for method chaining
- *
- * @since 7.2
- */
+ @Override
StatelessSessionBuilder connectionHandling(ConnectionAcquisitionMode acquisitionMode, ConnectionReleaseMode releaseMode);
- /**
- * Define the tenant identifier to be associated with the opened session.
- *
- * @param tenantIdentifier The tenant identifier.
- *
- * @return {@code this}, for method chaining
- * @deprecated Use {@link #tenantIdentifier(Object)} instead
- */
- @Deprecated(since = "6.4", forRemoval = true)
- StatelessSessionBuilder tenantIdentifier(String tenantIdentifier);
-
- /**
- * Define the tenant identifier to be associated with the opened session.
- *
- * @param tenantIdentifier The tenant identifier.
- *
- * @return {@code this}, for method chaining
- * @since 6.4
- */
+ @Override
StatelessSessionBuilder tenantIdentifier(Object tenantIdentifier);
- /**
- * Specify a read-only mode for the stateless session. If a session
- * is created in read-only mode, then {@link Connection#setReadOnly}
- * is called when a JDBC connection is obtained.
- *
- * Furthermore, if read/write replication is in use, then:
- *
- *
a read-only session will connect to a read-only replica, but
- *
a non-read-only session will connect to a writable replica.
- *
- *
- * When read/write replication is in use, it's strongly recommended
- * that the session be created with the {@linkplain #initialCacheMode
- * initial cache mode} set to {@link CacheMode#GET}, to avoid writing
- * stale data read from a read-only replica to the second-level cache.
- * Hibernate cannot possibly guarantee that data read from a read-only
- * replica is up to date. It's also possible for a read-only session to
- *
- * When read/write replication is in use, it's possible that an item
- * read from the second-level cache might refer to data which does not
- * yet exist in the read-only replica. In this situation, an exception
- * occurs when the association is fetched. To completely avoid this
- * possibility, the {@linkplain #initialCacheMode initial cache mode}
- * must be set to {@link CacheMode#IGNORE}. However, it's also usually
- * possible to structure data access code in a way which eliminates
- * this possibility.
- *
- * @return {@code this}, for method chaining
- * @since 7.2
- *
- * @see org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider#getReadOnlyConnection(Object)
- * @see org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider#releaseReadOnlyConnection(Object, Connection)
- */
- @Incubating
+ @Incubating @Override
StatelessSessionBuilder readOnly(boolean readOnly);
- /**
- * Specify the initial {@link CacheMode} for the session.
- *
- * @return {@code this}, for method chaining
- * @since 7.2
- *
- * @see SharedSessionContract#getCacheMode()
- */
+ @Incubating @Override
StatelessSessionBuilder initialCacheMode(CacheMode cacheMode);
+ @Override
+ StatelessSessionBuilder statementInspector(UnaryOperator operator);
+
/**
- * Applies the given statement inspection function to the session.
+ * Define the tenant identifier to be associated with the opened session.
*
- * @param operator An operator which accepts a SQL string, returning
- * a processed SQL string to be used by Hibernate
- * instead of the given original SQL. Alternatively,
- * the operator may work by side effect and simply
- * return the original SQL.
+ * @param tenantIdentifier The tenant identifier.
*
* @return {@code this}, for method chaining
- *
- * @apiNote This operation exposes the SPI type
- * {@link StatementInspector}
- * and is therefore a layer-breaker.
+ * @deprecated Use {@link #tenantIdentifier(Object)} instead
*/
- StatelessSessionBuilder statementInspector(UnaryOperator operator);
+ @Deprecated(since = "6.4", forRemoval = true)
+ StatelessSessionBuilder tenantIdentifier(String tenantIdentifier);
/**
* Applies the given {@link StatementInspector} to the session.
diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIncrementVersionProcess.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIncrementVersionProcess.java
index 6ca5276cff37..4857eb6fcf80 100644
--- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIncrementVersionProcess.java
+++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIncrementVersionProcess.java
@@ -5,7 +5,7 @@
package org.hibernate.action.internal;
import org.hibernate.action.spi.BeforeTransactionCompletionProcess;
-import org.hibernate.engine.spi.SessionImplementor;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.OptimisticLockHelper;
/**
@@ -33,9 +33,9 @@ public EntityIncrementVersionProcess(Object object) {
* @param session The session on which the transaction is preparing to complete.
*/
@Override
- public void doBeforeTransactionCompletion(SessionImplementor session) {
+ public void doBeforeTransactionCompletion(SharedSessionContractImplementor session) {
final var entry = session.getPersistenceContext().getEntry( object );
- // Don't increment version for an entity that is not in the PersistenceContext;
+ // Don't increment the version for an entity that is not in the PersistenceContext;
if ( entry != null ) {
OptimisticLockHelper.forceVersionIncrement( object, entry, session.asEventSource() );
}
diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityVerifyVersionProcess.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityVerifyVersionProcess.java
index 0483e8d7c02f..04986cf18bba 100644
--- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityVerifyVersionProcess.java
+++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityVerifyVersionProcess.java
@@ -6,7 +6,7 @@
import org.hibernate.action.spi.BeforeTransactionCompletionProcess;
import org.hibernate.dialect.lock.OptimisticEntityLockException;
-import org.hibernate.engine.spi.SessionImplementor;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.pretty.MessageHelper;
/**
@@ -29,9 +29,9 @@ public EntityVerifyVersionProcess(Object object) {
}
@Override
- public void doBeforeTransactionCompletion(SessionImplementor session) {
+ public void doBeforeTransactionCompletion(SharedSessionContractImplementor session) {
final var entry = session.getPersistenceContext().getEntry( object );
- // Don't check version for an entity that is not in the PersistenceContext
+ // Don't check the version for an entity that is not in the PersistenceContext
if ( entry != null ) {
final Object latestVersion = entry.getPersister().getCurrentVersion( entry.getId(), session );
if ( !entry.getVersion().equals( latestVersion ) ) {
diff --git a/hibernate-core/src/main/java/org/hibernate/action/spi/AfterTransactionCompletionProcess.java b/hibernate-core/src/main/java/org/hibernate/action/spi/AfterTransactionCompletionProcess.java
index b353908dd0de..2a763a7498bb 100644
--- a/hibernate-core/src/main/java/org/hibernate/action/spi/AfterTransactionCompletionProcess.java
+++ b/hibernate-core/src/main/java/org/hibernate/action/spi/AfterTransactionCompletionProcess.java
@@ -4,19 +4,12 @@
*/
package org.hibernate.action.spi;
-import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.engine.spi.TransactionCompletionCallbacks;
/**
* Contract representing some process that needs to occur during after transaction completion.
*
* @author Steve Ebersole
*/
-public interface AfterTransactionCompletionProcess {
- /**
- * Perform whatever processing is encapsulated here after completion of the transaction.
- *
- * @param success Did the transaction complete successfully? True means it did.
- * @param session The session on which the transaction is completing.
- */
- void doAfterTransactionCompletion(boolean success, SharedSessionContractImplementor session);
+public interface AfterTransactionCompletionProcess extends TransactionCompletionCallbacks.AfterCompletionCallback {
}
diff --git a/hibernate-core/src/main/java/org/hibernate/action/spi/BeforeTransactionCompletionProcess.java b/hibernate-core/src/main/java/org/hibernate/action/spi/BeforeTransactionCompletionProcess.java
index 7ab190edf434..58949aa06fbf 100644
--- a/hibernate-core/src/main/java/org/hibernate/action/spi/BeforeTransactionCompletionProcess.java
+++ b/hibernate-core/src/main/java/org/hibernate/action/spi/BeforeTransactionCompletionProcess.java
@@ -5,17 +5,23 @@
package org.hibernate.action.spi;
import org.hibernate.engine.spi.SessionImplementor;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.engine.spi.TransactionCompletionCallbacks;
/**
* Contract representing some process that needs to occur during before transaction completion.
*
* @author Steve Ebersole
*/
-public interface BeforeTransactionCompletionProcess {
+public interface BeforeTransactionCompletionProcess extends TransactionCompletionCallbacks.BeforeCompletionCallback {
/**
* Perform whatever processing is encapsulated here before completion of the transaction.
*
* @param session The session on which the transaction is preparing to complete.
+ * @deprecated Use {@linkplain #doBeforeTransactionCompletion(SharedSessionContractImplementor)} instead.
*/
- void doBeforeTransactionCompletion(SessionImplementor session);
+ @Deprecated(since = "7.2", forRemoval = true)
+ default void doBeforeTransactionCompletion(SessionImplementor session) {
+ doBeforeTransactionCompletion( (SharedSessionContractImplementor) session );
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/cache/internal/CollectionCacheInvalidator.java b/hibernate-core/src/main/java/org/hibernate/cache/internal/CollectionCacheInvalidator.java
index b08dba5fc91f..5cc3988a7d78 100644
--- a/hibernate-core/src/main/java/org/hibernate/cache/internal/CollectionCacheInvalidator.java
+++ b/hibernate-core/src/main/java/org/hibernate/cache/internal/CollectionCacheInvalidator.java
@@ -4,7 +4,6 @@
*/
package org.hibernate.cache.internal;
-
import org.hibernate.HibernateException;
import org.hibernate.action.internal.CollectionAction;
import org.hibernate.boot.Metadata;
@@ -23,7 +22,6 @@
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
-
import org.jboss.logging.Logger;
import static org.hibernate.cache.spi.SecondLevelCacheLogger.L2CACHE_LOGGER;
@@ -59,7 +57,9 @@ public void integrate(
@Override
public void onPostInsert(PostInsertEvent event) {
- evictCache( event.getEntity(), event.getPersister(), event.getSession(), null );
+ if ( event.getSession() instanceof EventSource eventSource ) {
+ evictCache( event.getEntity(), event.getPersister(), eventSource, null );
+ }
}
@Override
@@ -69,12 +69,16 @@ public boolean requiresPostCommitHandling(EntityPersister persister) {
@Override
public void onPostDelete(PostDeleteEvent event) {
- evictCache( event.getEntity(), event.getPersister(), event.getSession(), null );
+ if ( event.getSession() instanceof EventSource eventSource ) {
+ evictCache( event.getEntity(), event.getPersister(), eventSource, null );
+ }
}
@Override
public void onPostUpdate(PostUpdateEvent event) {
- evictCache( event.getEntity(), event.getPersister(), event.getSession(), event.getOldState() );
+ if ( event.getSession() instanceof EventSource eventSource ) {
+ evictCache( event.getEntity(), event.getPersister(), eventSource, event.getOldState() );
+ }
}
private void integrate(SessionFactoryImplementor sessionFactory) {
@@ -124,7 +128,7 @@ private void evictCollection(
final var cacheAccessStrategy = collectionPersister.getCacheAccessStrategy();
final var softLock = cacheAccessStrategy.lockRegion();
session.getActionQueue()
- .registerProcess( (success, s) -> cacheAccessStrategy.unlockRegion( softLock ) );
+ .registerCallback( (success, s) -> cacheAccessStrategy.unlockRegion( softLock ) );
}
}
}
@@ -182,7 +186,7 @@ private void evict(Object id, CollectionPersister collectionPersister, EventSour
final var evictCacheAction =
new CollectionEvictCacheAction( collectionPersister, null, id, session );
evictCacheAction.execute();
- session.getActionQueue().registerProcess( evictCacheAction.getAfterTransactionCompletionProcess() );
+ session.getActionQueue().registerCallback( evictCacheAction.getAfterTransactionCompletionProcess() );
}
//execute the same process as invalidation with collection operations
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/lock/OptimisticForceIncrementLockingStrategy.java b/hibernate-core/src/main/java/org/hibernate/dialect/lock/OptimisticForceIncrementLockingStrategy.java
index 75b96acaf823..5cf5ab687068 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/lock/OptimisticForceIncrementLockingStrategy.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/lock/OptimisticForceIncrementLockingStrategy.java
@@ -45,7 +45,7 @@ public void lock(Object id, Object version, Object object, int timeout, EventSou
}
// final EntityEntry entry = session.getPersistenceContextInternal().getEntry( object );
// Register the EntityIncrementVersionProcess action to run just prior to transaction commit.
- session.getActionQueue().registerProcess( new EntityIncrementVersionProcess( object ) );
+ session.getActionQueue().registerCallback( new EntityIncrementVersionProcess( object ) );
}
protected LockMode getLockMode() {
diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/lock/OptimisticLockingStrategy.java b/hibernate-core/src/main/java/org/hibernate/dialect/lock/OptimisticLockingStrategy.java
index d656e00c56d7..79337885d354 100644
--- a/hibernate-core/src/main/java/org/hibernate/dialect/lock/OptimisticLockingStrategy.java
+++ b/hibernate-core/src/main/java/org/hibernate/dialect/lock/OptimisticLockingStrategy.java
@@ -43,7 +43,7 @@ public void lock(Object id, Object version, Object object, int timeout, EventSou
throw new HibernateException( "[" + lockMode + "] not supported for non-versioned entities [" + lockable.getEntityName() + "]" );
}
// Register the EntityVerifyVersionProcess action to run just prior to transaction commit.
- session.getActionQueue().registerProcess( new EntityVerifyVersionProcess( object ) );
+ session.getActionQueue().registerCallback( new EntityVerifyVersionProcess( object ) );
}
protected LockMode getLockMode() {
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/CommonBuilder.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/CommonBuilder.java
new file mode 100644
index 000000000000..ff6b308a3cc6
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/CommonBuilder.java
@@ -0,0 +1,160 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.engine.creation;
+
+import org.hibernate.CacheMode;
+import org.hibernate.ConnectionAcquisitionMode;
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.Incubating;
+import org.hibernate.Interceptor;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.SharedSessionContract;
+import org.hibernate.StatelessSession;
+
+import java.sql.Connection;
+import java.util.function.UnaryOperator;
+
+/**
+ * Common options for builders of {@linkplain Session stateful}
+ * and {@linkplain StatelessSession stateless} sessions.
+ *
+ * @since 7.2
+ *
+ * @author Steve Ebersole
+ */
+@Incubating
+public interface CommonBuilder {
+
+ /**
+ * Adds a specific connection to the session options.
+ *
+ * @param connection The connection to use.
+ *
+ * @return {@code this}, for method chaining
+ */
+ CommonBuilder connection(Connection connection);
+
+ /**
+ * Specifies the connection handling modes for the session.
+ *
+ * Note that if {@link ConnectionAcquisitionMode#IMMEDIATELY} is specified,
+ * then the release mode must be {@link ConnectionReleaseMode#ON_CLOSE}.
+ *
+ * @return {@code this}, for method chaining
+ *
+ * @since 7.0
+ */
+ CommonBuilder connectionHandling(ConnectionAcquisitionMode acquisitionMode, ConnectionReleaseMode releaseMode);
+
+ /**
+ * Adds a specific interceptor to the session options.
+ *
+ * @param interceptor The interceptor to use.
+ *
+ * @return {@code this}, for method chaining
+ */
+ CommonBuilder interceptor(Interceptor interceptor);
+
+ /**
+ * Signifies that no {@link Interceptor} should be used.
+ *
+ * By default, if no {@code Interceptor} is explicitly specified, the
+ * {@code Interceptor} associated with the {@link SessionFactory} is
+ * inherited by the new session.
+ *
+ * Calling {@link #interceptor(Interceptor)} with null has the same effect.
+ *
+ * @return {@code this}, for method chaining
+ */
+ CommonBuilder noInterceptor();
+
+ /**
+ * Applies the given statement inspection function to the session.
+ *
+ * @param operator An operator which accepts a SQL string, returning
+ * a processed SQL string to be used by Hibernate instead of the given
+ * original SQL. The operator may simply return the original SQL.
+ *
+ * @return {@code this}, for method chaining
+ */
+ CommonBuilder statementInspector(UnaryOperator operator);
+
+ /**
+ * Signifies that no SQL statement inspector should be used.
+ *
+ * By default, if no inspector is explicitly specified, the
+ * inspector associated with the {@link SessionFactory} is
+ * inherited by the new session.
+ *
+ * Calling {@link #interceptor(Interceptor)} with null has the same effect.
+ *
+ * @return {@code this}, for method chaining
+ */
+ CommonBuilder noStatementInspector();
+
+ /**
+ * Define the tenant identifier to be associated with the opened session.
+ *
+ * @param tenantIdentifier The tenant identifier.
+ *
+ * @return {@code this}, for method chaining
+ */
+ CommonBuilder tenantIdentifier(Object tenantIdentifier);
+
+ /**
+ * Specify a {@linkplain Session#isDefaultReadOnly read-only mode}
+ * for the session. If a session is created in read-only mode, then
+ * {@link Connection#setReadOnly} is called when a JDBC connection
+ * is obtained.
+ *
+ * Furthermore, if read/write replication is in use, then:
+ *
+ *
a read-only session will connect to a read-only replica, but
+ *
a non-read-only session will connect to a writable replica.
+ *
+ *
+ * When read/write replication is in use, it's strongly recommended
+ * that the session be created with the {@linkplain #initialCacheMode
+ * initial cache mode} set to {@link CacheMode#GET}, to avoid writing
+ * stale data read from a read-only replica to the second-level cache.
+ * Hibernate cannot possibly guarantee that data read from a read-only
+ * replica is up to date.
+ *
+ * When read/write replication is in use, it's possible that an item
+ * read from the second-level cache might refer to data which does not
+ * yet exist in the read-only replica. In this situation, an exception
+ * occurs when the association is fetched. To completely avoid this
+ * possibility, the {@linkplain #initialCacheMode initial cache mode}
+ * must be set to {@link CacheMode#IGNORE}. However, it's also usually
+ * possible to structure data access code in a way which eliminates
+ * this possibility.
+ *
+ * If a session is created in read-only mode, then it cannot be
+ * changed to read-write mode, and any call to
+ * {@link Session#setDefaultReadOnly(boolean)} with fail. On the
+ * other hand, if a session is created in read-write mode, then it
+ * may later be switched to read-only mode, but all database access
+ * is directed to the writable replica.
+ *
+ * @return {@code this}, for method chaining
+ * @since 7.2
+ *
+ * @see org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider#getReadOnlyConnection(Object)
+ * @see org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider#releaseReadOnlyConnection(Object, Connection)
+ */
+ @Incubating
+ CommonBuilder readOnly(boolean readOnly);
+
+ /**
+ * Specify the initial {@link CacheMode} for the session.
+ *
+ * @return {@code this}, for method chaining
+ * @since 7.2
+ *
+ * @see SharedSessionContract#getCacheMode()
+ */
+ CommonBuilder initialCacheMode(CacheMode cacheMode);
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/CommonSharedBuilder.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/CommonSharedBuilder.java
new file mode 100644
index 000000000000..81777e43b8d4
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/CommonSharedBuilder.java
@@ -0,0 +1,70 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.engine.creation;
+
+import org.hibernate.CacheMode;
+import org.hibernate.Incubating;
+import org.hibernate.Interceptor;
+import org.hibernate.Session;
+import org.hibernate.StatelessSession;
+
+import java.util.function.UnaryOperator;
+
+/**
+ * Common options for builders of {@linkplain Session stateful}
+ * and {@linkplain StatelessSession stateless} sessions
+ * which share state from an underlying session.
+ *
+ * @since 7.2
+ *
+ * @author Steve Ebersole
+ */
+@Incubating
+public interface CommonSharedBuilder extends CommonBuilder {
+
+ /**
+ * Signifies that the connection from the original session should be used to create the new session.
+ *
+ * @return {@code this}, for method chaining
+ */
+ CommonSharedBuilder connection();
+
+ /**
+ * Signifies the interceptor from the original session should be used to create the new session.
+ *
+ * @return {@code this}, for method chaining
+ */
+ CommonSharedBuilder interceptor();
+
+ /**
+ * Signifies that the SQL {@linkplain org.hibernate.resource.jdbc.spi.StatementInspector statement inspector}
+ * from the original session should be used.
+ */
+ CommonSharedBuilder statementInspector();
+
+ /**
+ * Signifies that no SQL {@linkplain org.hibernate.resource.jdbc.spi.StatementInspector statement inspector}
+ * should be used.
+ */
+ CommonSharedBuilder noStatementInspector();
+
+ @Override
+ CommonSharedBuilder interceptor(Interceptor interceptor);
+
+ @Override
+ CommonSharedBuilder noInterceptor();
+
+ @Override
+ CommonSharedBuilder statementInspector(UnaryOperator operator);
+
+ @Override
+ CommonSharedBuilder readOnly(boolean readOnly);
+
+ @Override
+ CommonSharedBuilder initialCacheMode(CacheMode cacheMode);
+
+ @Override
+ CommonSharedBuilder tenantIdentifier(Object tenantIdentifier);
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/AbstractCommonBuilder.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/AbstractCommonBuilder.java
new file mode 100644
index 000000000000..66e4ed54068a
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/AbstractCommonBuilder.java
@@ -0,0 +1,113 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.engine.creation.internal;
+
+import org.hibernate.CacheMode;
+import org.hibernate.ConnectionAcquisitionMode;
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.Interceptor;
+import org.hibernate.engine.creation.CommonBuilder;
+import org.hibernate.internal.SessionFactoryImpl;
+import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
+import org.hibernate.resource.jdbc.spi.StatementInspector;
+
+import java.sql.Connection;
+import java.util.function.UnaryOperator;
+
+/**
+ * Base support for session builders.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractCommonBuilder implements CommonBuilder {
+ protected final SessionFactoryImpl sessionFactory;
+
+ protected StatementInspector statementInspector;
+ protected Interceptor interceptor;
+ protected boolean explicitNoInterceptor;
+ protected Connection connection;
+ protected PhysicalConnectionHandlingMode connectionHandlingMode;
+ protected Object tenantIdentifier;
+ protected boolean readOnly;
+ protected CacheMode cacheMode;
+
+ public AbstractCommonBuilder(SessionFactoryImpl sessionFactory) {
+ this.sessionFactory = sessionFactory;
+
+ final var options = sessionFactory.getSessionFactoryOptions();
+ statementInspector = options.getStatementInspector();
+ cacheMode = options.getInitialSessionCacheMode();
+ tenantIdentifier = sessionFactory.resolveTenantIdentifier();
+ connectionHandlingMode = options.getPhysicalConnectionHandlingMode();
+ }
+
+ protected abstract T getThis();
+
+ @Override
+ public T connection(Connection connection) {
+ this.connection = connection;
+ return getThis();
+ }
+
+ @Override
+ public T connectionHandling(ConnectionAcquisitionMode acquisitionMode, ConnectionReleaseMode releaseMode) {
+ this.connectionHandlingMode = PhysicalConnectionHandlingMode.interpret( acquisitionMode, releaseMode );
+ return getThis();
+ }
+
+ @Override
+ public T interceptor(Interceptor interceptor) {
+ if ( interceptor == null ) {
+ noInterceptor();
+ }
+ else {
+ this.interceptor = interceptor;
+ this.explicitNoInterceptor = false;
+ }
+ return getThis();
+ }
+
+ @Override
+ public T noInterceptor() {
+ this.interceptor = null;
+ this.explicitNoInterceptor = true;
+ return getThis();
+ }
+
+ @Override
+ public T tenantIdentifier(Object tenantIdentifier) {
+ this.tenantIdentifier = tenantIdentifier;
+ return getThis();
+ }
+
+ @Override
+ public T readOnly(boolean readOnly) {
+ this.readOnly = readOnly;
+ return getThis();
+ }
+
+ @Override
+ public T initialCacheMode(CacheMode cacheMode) {
+ this.cacheMode = cacheMode;
+ return getThis();
+ }
+
+ @Override
+ public T statementInspector(UnaryOperator operator) {
+ if ( operator == null ) {
+ noStatementInspector();
+ }
+ else {
+ this.statementInspector = operator::apply;
+ }
+ return getThis();
+ }
+
+ @Override
+ public T noStatementInspector() {
+ this.statementInspector = null;
+ return getThis();
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SessionBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SessionBuilderImpl.java
new file mode 100644
index 000000000000..2071d6a3bce9
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SessionBuilderImpl.java
@@ -0,0 +1,259 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.engine.creation.internal;
+
+import org.hibernate.CacheMode;
+import org.hibernate.FlushMode;
+import org.hibernate.Interceptor;
+import org.hibernate.SessionEventListener;
+import org.hibernate.engine.creation.spi.SessionBuilderImplementor;
+import org.hibernate.internal.CoreLogging;
+import org.hibernate.internal.SessionFactoryImpl;
+import org.hibernate.internal.SessionImpl;
+import org.hibernate.internal.SessionOwnerBehavior;
+import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
+import org.hibernate.resource.jdbc.spi.StatementInspector;
+import org.jboss.logging.Logger;
+
+import java.sql.Connection;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.TimeZone;
+
+import static java.util.Collections.addAll;
+
+/**
+ * SessionBuilder implementation.
+ *
+ * @author Steve Ebersole
+ */
+public class SessionBuilderImpl
+ extends AbstractCommonBuilder
+ implements SessionBuilderImplementor, SessionCreationOptions {
+ private static final Logger log = CoreLogging.logger( SessionBuilderImpl.class );
+
+ private boolean autoJoinTransactions = true;
+ private FlushMode flushMode;
+ private boolean autoClose;
+ private boolean autoClear;
+ private boolean identifierRollback;
+ private TimeZone jdbcTimeZone;
+ private final int defaultBatchFetchSize;
+ private final boolean subselectFetchEnabled;
+
+ // Lazy: defaults can be built by invoking the builder in fastSessionServices.defaultSessionEventListeners
+ // (Need a fresh build for each Session as the listener instances can't be reused across sessions)
+ // Only initialize of the builder is overriding the default.
+ private List listeners;
+
+ //todo : expose setting
+ private final SessionOwnerBehavior sessionOwnerBehavior = SessionOwnerBehavior.LEGACY_NATIVE;
+
+ public SessionBuilderImpl(SessionFactoryImpl sessionFactory) {
+ super( sessionFactory );
+
+ // set up default builder values...
+ final var options = sessionFactory.getSessionFactoryOptions();
+ statementInspector = options.getStatementInspector();
+ connectionHandlingMode = options.getPhysicalConnectionHandlingMode();
+ autoClose = options.isAutoCloseSessionEnabled();
+ defaultBatchFetchSize = options.getDefaultBatchFetchSize();
+ subselectFetchEnabled = options.isSubselectFetchEnabled();
+ identifierRollback = options.isIdentifierRollbackEnabled();
+ cacheMode = options.getInitialSessionCacheMode();
+
+ tenantIdentifier = sessionFactory.resolveTenantIdentifier();
+ jdbcTimeZone = options.getJdbcTimeZone();
+ }
+
+ @Override
+ protected SessionBuilderImplementor getThis() {
+ return this;
+ }
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // SessionCreationOptions
+
+
+ @Override
+ public boolean shouldAutoJoinTransactions() {
+ return autoJoinTransactions;
+ }
+
+ @Override
+ public FlushMode getInitialSessionFlushMode() {
+ return flushMode;
+ }
+
+ @Override
+ public boolean isSubselectFetchEnabled() {
+ return subselectFetchEnabled;
+ }
+
+ @Override
+ public int getDefaultBatchFetchSize() {
+ return defaultBatchFetchSize;
+ }
+
+ @Override
+ public boolean shouldAutoClose() {
+ return autoClose;
+ }
+
+ @Override
+ public boolean shouldAutoClear() {
+ return autoClear;
+ }
+
+ @Override
+ public Connection getConnection() {
+ return connection;
+ }
+
+ @Override
+ public Interceptor getInterceptor() {
+ return SessionFactoryImpl.configuredInterceptor( interceptor, explicitNoInterceptor,
+ sessionFactory.getSessionFactoryOptions() );
+ }
+
+ @Override
+ public StatementInspector getStatementInspector() {
+ return statementInspector;
+ }
+
+ @Override
+ public PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode() {
+ return connectionHandlingMode;
+ }
+
+ @Override
+ public String getTenantIdentifier() {
+ return tenantIdentifier != null
+ ? sessionFactory.getTenantIdentifierJavaType().toString( tenantIdentifier )
+ : null;
+ }
+
+ @Override
+ public Object getTenantIdentifierValue() {
+ return tenantIdentifier;
+ }
+
+ @Override
+ public boolean isReadOnly() {
+ return readOnly;
+ }
+
+ @Override
+ public CacheMode getInitialCacheMode() {
+ return cacheMode;
+ }
+
+ @Override
+ public boolean isIdentifierRollbackEnabled() {
+ return identifierRollback;
+ }
+
+ @Override
+ public TimeZone getJdbcTimeZone() {
+ return jdbcTimeZone;
+ }
+
+ @Override
+ public List getCustomSessionEventListener() {
+ return listeners;
+ }
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // SessionBuilder
+
+ @Override
+ public SessionImpl openSession() {
+ log.tracef( "Opening Hibernate Session. tenant=%s", tenantIdentifier );
+ return new SessionImpl( sessionFactory, this );
+ }
+
+ @Override
+ @Deprecated
+ public SessionBuilderImplementor statementInspector(StatementInspector statementInspector) {
+ this.statementInspector = statementInspector;
+ return this;
+ }
+
+ @Override
+ @Deprecated
+ public SessionBuilderImplementor connectionHandlingMode(PhysicalConnectionHandlingMode connectionHandlingMode) {
+ this.connectionHandlingMode = connectionHandlingMode;
+ return this;
+ }
+
+ @Override
+ public SessionBuilderImplementor autoJoinTransactions(boolean autoJoinTransactions) {
+ this.autoJoinTransactions = autoJoinTransactions;
+ return this;
+ }
+
+ @Override
+ public SessionBuilderImplementor autoClose(boolean autoClose) {
+ this.autoClose = autoClose;
+ return this;
+ }
+
+ @Override
+ public SessionBuilderImplementor autoClear(boolean autoClear) {
+ this.autoClear = autoClear;
+ return this;
+ }
+
+ @Override
+ public SessionBuilderImplementor flushMode(FlushMode flushMode) {
+ this.flushMode = flushMode;
+ return this;
+ }
+
+ @Override
+ @Deprecated(forRemoval = true)
+ public SessionBuilderImplementor tenantIdentifier(String tenantIdentifier) {
+ this.tenantIdentifier = tenantIdentifier;
+ return this;
+ }
+
+ @Override
+ public SessionBuilderImplementor identifierRollback(boolean identifierRollback) {
+ this.identifierRollback = identifierRollback;
+ return this;
+ }
+
+ @Override
+ public SessionBuilderImplementor eventListeners(SessionEventListener... listeners) {
+ if ( this.listeners == null ) {
+ final var baselineListeners =
+ sessionFactory.getSessionFactoryOptions().buildSessionEventListeners();
+ this.listeners = new ArrayList<>( baselineListeners.length + listeners.length );
+ addAll( this.listeners, baselineListeners );
+ }
+ addAll( this.listeners, listeners );
+ return this;
+ }
+
+ @Override
+ public SessionBuilderImplementor clearEventListeners() {
+ if ( listeners == null ) {
+ //Needs to initialize explicitly to an empty list as otherwise "null" implies the default listeners will be applied
+ listeners = new ArrayList<>( 3 );
+ }
+ else {
+ listeners.clear();
+ }
+ return this;
+ }
+
+ @Override
+ public SessionBuilderImplementor jdbcTimeZone(TimeZone timeZone) {
+ jdbcTimeZone = timeZone;
+ return this;
+ }
+
+
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionCreationOptions.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SessionCreationOptions.java
similarity index 76%
rename from hibernate-core/src/main/java/org/hibernate/internal/SessionCreationOptions.java
rename to hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SessionCreationOptions.java
index 98ee29bcb9a8..2027f4c9dabb 100644
--- a/hibernate-core/src/main/java/org/hibernate/internal/SessionCreationOptions.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SessionCreationOptions.java
@@ -2,7 +2,7 @@
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
-package org.hibernate.internal;
+package org.hibernate.engine.creation.internal;
import java.sql.Connection;
import java.util.List;
@@ -12,16 +12,17 @@
import org.hibernate.FlushMode;
import org.hibernate.Interceptor;
import org.hibernate.SessionEventListener;
+import org.hibernate.engine.creation.CommonBuilder;
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
import org.hibernate.resource.jdbc.spi.StatementInspector;
-import org.hibernate.resource.transaction.backend.jta.internal.synchronization.ExceptionMapper;
/**
+ * Options, specified through various {@linkplain CommonBuilder builders},
+ * used when creating sessions.
+ *
* @author Steve Ebersole
*/
public interface SessionCreationOptions {
- // todo : (5.2) review this. intended as a consolidation of the options needed to create a Session
- // comes from building a Session and a EntityManager
boolean shouldAutoJoinTransactions();
@@ -60,9 +61,4 @@ public interface SessionCreationOptions {
* or null if this Session is being created with the default list.
*/
List getCustomSessionEventListener();
-
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // deprecations
-
- ExceptionMapper getExceptionMapper();
}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionBuilderImpl.java
new file mode 100644
index 000000000000..3d92e28d1f49
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionBuilderImpl.java
@@ -0,0 +1,281 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.engine.creation.internal;
+
+import org.hibernate.CacheMode;
+import org.hibernate.ConnectionAcquisitionMode;
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.FlushMode;
+import org.hibernate.Interceptor;
+import org.hibernate.SessionEventListener;
+import org.hibernate.SessionException;
+import org.hibernate.Transaction;
+import org.hibernate.engine.creation.spi.SharedSessionBuilderImplementor;
+import org.hibernate.engine.internal.TransactionCompletionCallbacksImpl;
+import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
+import org.hibernate.internal.SessionFactoryImpl;
+import org.hibernate.internal.SessionImpl;
+import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
+import org.hibernate.resource.jdbc.spi.StatementInspector;
+import org.hibernate.resource.transaction.spi.TransactionCoordinator;
+
+import java.sql.Connection;
+import java.util.TimeZone;
+import java.util.function.UnaryOperator;
+
+/**
+ * @author Steve Ebersole
+ */
+public class SharedSessionBuilderImpl
+ extends SessionBuilderImpl
+ implements SharedSessionBuilderImplementor, SharedSessionCreationOptions {
+ private final SessionImpl session;
+
+ private boolean shareTransactionContext;
+ private boolean tenantIdChanged;
+ private boolean readOnlyChanged;
+
+ public SharedSessionBuilderImpl(SessionImpl session) {
+ super( (SessionFactoryImpl) session.getFactory() );
+ this.session = session;
+ super.tenantIdentifier( session.getTenantIdentifierValue() );
+ super.identifierRollback( session.isIdentifierRollbackEnabled() );
+ }
+
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // SharedSessionBuilder
+
+ @Override
+ public SessionImpl openSession() {
+ if ( session.getFactory().getSessionFactoryOptions().isMultiTenancyEnabled() ) {
+ if ( shareTransactionContext ) {
+ if ( tenantIdChanged ) {
+ throw new SessionException(
+ "Cannot redefine the tenant identifier on a child session if the connection is reused" );
+ }
+ if ( readOnlyChanged ) {
+ throw new SessionException(
+ "Cannot redefine the read-only mode on a child session if the connection is reused" );
+ }
+ }
+ }
+ return super.openSession();
+ }
+
+
+ @Override
+ @Deprecated(forRemoval = true)
+ public SharedSessionBuilderImplementor tenantIdentifier(String tenantIdentifier) {
+ tenantIdentifier( (Object) tenantIdentifier );
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor tenantIdentifier(Object tenantIdentifier) {
+ super.tenantIdentifier( tenantIdentifier );
+ tenantIdChanged = true;
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor readOnly(boolean readOnly) {
+ super.readOnly( readOnly );
+ readOnlyChanged = true;
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor connection() {
+ this.shareTransactionContext = true;
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor interceptor() {
+ interceptor = session.getInterceptor();
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor statementInspector() {
+ statementInspector = session.getJdbcSessionContext().getStatementInspector();
+ return this;
+ }
+
+ private PhysicalConnectionHandlingMode getConnectionHandlingMode() {
+ return session.getJdbcCoordinator().getLogicalConnection().getConnectionHandlingMode();
+ }
+
+ @Override
+ @Deprecated(since = "6.0")
+ public SharedSessionBuilderImplementor connectionReleaseMode() {
+ final PhysicalConnectionHandlingMode handlingMode =
+ PhysicalConnectionHandlingMode.interpret( ConnectionAcquisitionMode.AS_NEEDED,
+ getConnectionHandlingMode().getReleaseMode() );
+ connectionHandlingMode( handlingMode );
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor connectionHandlingMode() {
+ connectionHandlingMode( getConnectionHandlingMode() );
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor autoJoinTransactions() {
+ super.autoJoinTransactions( session.shouldAutoJoinTransaction() );
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor autoJoinTransactions(boolean autoJoinTransactions) {
+ super.autoJoinTransactions( autoJoinTransactions );
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor autoClose(boolean autoClose) {
+ super.autoClose( autoClose );
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor flushMode() {
+ flushMode( session.getHibernateFlushMode() );
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor autoClose() {
+ autoClose( session.isAutoCloseSessionEnabled() );
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor identifierRollback(boolean identifierRollback) {
+ super.identifierRollback( identifierRollback );
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor jdbcTimeZone(TimeZone timeZone) {
+ super.jdbcTimeZone( timeZone );
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor clearEventListeners() {
+ super.clearEventListeners();
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor flushMode(FlushMode flushMode) {
+ super.flushMode( flushMode );
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor autoClear(boolean autoClear) {
+ super.autoClear( autoClear );
+ return this;
+ }
+
+ @Override
+ @Deprecated
+ public SharedSessionBuilderImplementor statementInspector(StatementInspector statementInspector) {
+ super.statementInspector( statementInspector );
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor statementInspector(UnaryOperator operator) {
+ super.statementInspector( operator );
+ return this;
+ }
+
+ @Override
+ @Deprecated
+ public SharedSessionBuilderImplementor connectionHandlingMode(PhysicalConnectionHandlingMode connectionHandlingMode) {
+ super.connectionHandlingMode( connectionHandlingMode );
+ return this;
+ }
+
+ @Override
+ @Deprecated
+ public SharedSessionBuilderImplementor connectionHandling(ConnectionAcquisitionMode acquisitionMode, ConnectionReleaseMode releaseMode) {
+ super.connectionHandling( acquisitionMode, releaseMode );
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor eventListeners(SessionEventListener... listeners) {
+ super.eventListeners( listeners );
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor connection(Connection connection) {
+ super.connection( connection );
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor interceptor(Interceptor interceptor) {
+ super.interceptor( interceptor );
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor noInterceptor() {
+ super.noInterceptor();
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor initialCacheMode(CacheMode cacheMode) {
+ super.initialCacheMode( cacheMode );
+ return this;
+ }
+
+ @Override
+ public SharedSessionBuilderImplementor noStatementInspector() {
+ super.noStatementInspector();
+ return this;
+ }
+
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // 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 Transaction getTransaction() {
+ return shareTransactionContext ? session.getCurrentTransaction() : null;
+ }
+
+ @Override
+ public TransactionCompletionCallbacksImpl getTransactionCompletionCallbacks() {
+ return shareTransactionContext
+ ? session.getActionQueue().getTransactionCompletionCallbacks()
+ : null;
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SharedSessionCreationOptions.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionCreationOptions.java
similarity index 79%
rename from hibernate-core/src/main/java/org/hibernate/internal/SharedSessionCreationOptions.java
rename to hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionCreationOptions.java
index b66b1de904d3..72c6ccd42e4b 100644
--- a/hibernate-core/src/main/java/org/hibernate/internal/SharedSessionCreationOptions.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedSessionCreationOptions.java
@@ -2,11 +2,11 @@
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
-package org.hibernate.internal;
+package org.hibernate.engine.creation.internal;
import org.hibernate.Transaction;
+import org.hibernate.engine.internal.TransactionCompletionCallbacksImpl;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
-import org.hibernate.engine.spi.ActionQueue;
import org.hibernate.resource.transaction.spi.TransactionCoordinator;
/**
@@ -23,5 +23,5 @@ public interface SharedSessionCreationOptions extends SessionCreationOptions {
TransactionCoordinator getTransactionCoordinator();
JdbcCoordinator getJdbcCoordinator();
Transaction getTransaction();
- ActionQueue.TransactionCompletionProcesses getTransactionCompletionProcesses();
+ TransactionCompletionCallbacksImpl getTransactionCompletionCallbacks();
}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedStatelessSessionBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedStatelessSessionBuilderImpl.java
new file mode 100644
index 000000000000..27748b74cf5b
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/SharedStatelessSessionBuilderImpl.java
@@ -0,0 +1,131 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.engine.creation.internal;
+
+import org.hibernate.CacheMode;
+import org.hibernate.Interceptor;
+import org.hibernate.SessionException;
+import org.hibernate.SharedStatelessSessionBuilder;
+import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.engine.spi.StatelessSessionImplementor;
+import org.hibernate.internal.CommonSharedSessionCreationOptions;
+import org.hibernate.internal.SessionFactoryImpl;
+import org.hibernate.internal.StatelessSessionImpl;
+import org.hibernate.resource.jdbc.spi.StatementInspector;
+import org.hibernate.resource.transaction.spi.TransactionCoordinator;
+
+import java.util.Objects;
+
+/**
+ * Builder for shared {@linkplain StatelessSessionImplementor stateless} sessions.
+ * Exposes the builder state via its {@linkplain CommonSharedSessionCreationOptions} implementation
+ * for use when creating the shared stateless session.
+ *
+ * @author Steve Ebersole
+ */
+public class SharedStatelessSessionBuilderImpl
+ extends AbstractCommonBuilder
+ implements SharedStatelessSessionBuilder, CommonSharedSessionCreationOptions {
+
+ protected final SharedSessionContractImplementor original;
+ protected boolean shareTransactionContext;
+
+ public SharedStatelessSessionBuilderImpl(SharedSessionContractImplementor original) {
+ super( (SessionFactoryImpl) original.getSessionFactory() );
+ this.original = original;
+
+ this.tenantIdentifier = original.getTenantIdentifierValue();
+ this.interceptor = original.getSessionFactory().getSessionFactoryOptions().getInterceptor();
+ this.statementInspector = original.getSessionFactory().getSessionFactoryOptions().getStatementInspector();
+ }
+
+ @Override
+ protected SharedStatelessSessionBuilder getThis() {
+ return this;
+ }
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // SharedStatelessSessionBuilder
+
+ @Override
+ public StatelessSessionImplementor open() {
+ if ( original.getSessionFactory().getSessionFactoryOptions().isMultiTenancyEnabled() ) {
+ if ( shareTransactionContext ) {
+ assert original.getTenantIdentifierValue() != null;
+ if ( Objects.equals( original.getTenantIdentifierValue(), tenantIdentifier ) ) {
+ throw new SessionException( "Cannot redefine the tenant identifier on a child session if the connection is reused" );
+ }
+ }
+ }
+ return new StatelessSessionImpl( original.getSessionFactory(), this );
+ }
+
+ @Override
+ public SharedStatelessSessionBuilder connection() {
+ shareTransactionContext = true;
+ return this;
+ }
+
+ @Override
+ public SharedStatelessSessionBuilder interceptor() {
+ interceptor = original.getInterceptor();
+ return this;
+ }
+
+ @Override
+ public SharedStatelessSessionBuilder statementInspector() {
+ this.statementInspector = original.getJdbcSessionContext().getStatementInspector();
+ return this;
+ }
+
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // CommonSharedSessionCreationOptions
+
+ @Override
+ public Interceptor getInterceptor() {
+ return interceptor;
+ }
+
+ @Override
+ public StatementInspector getStatementInspector() {
+ return statementInspector;
+ }
+
+ @Override
+ public Object getTenantIdentifierValue() {
+ return tenantIdentifier;
+ }
+
+ @Override
+ public boolean isReadOnly() {
+ return readOnly;
+ }
+
+ @Override
+ public CacheMode getInitialCacheMode() {
+ return cacheMode;
+ }
+
+ @Override
+ public boolean isTransactionCoordinatorShared() {
+ return shareTransactionContext;
+ }
+
+ @Override
+ public TransactionCoordinator getTransactionCoordinator() {
+ return isTransactionCoordinatorShared()
+ ? original.getTransactionCoordinator()
+ : null;
+ }
+
+ @Override
+ public JdbcCoordinator getJdbcCoordinator() {
+ return isTransactionCoordinatorShared()
+ ? original.getJdbcCoordinator()
+ : null;
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/StatelessSessionBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/StatelessSessionBuilderImpl.java
new file mode 100644
index 000000000000..dc383f7a6190
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/internal/StatelessSessionBuilderImpl.java
@@ -0,0 +1,150 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.engine.creation.internal;
+
+import org.hibernate.CacheMode;
+import org.hibernate.FlushMode;
+import org.hibernate.Interceptor;
+import org.hibernate.SessionEventListener;
+import org.hibernate.StatelessSession;
+import org.hibernate.StatelessSessionBuilder;
+import org.hibernate.internal.SessionFactoryImpl;
+import org.hibernate.internal.StatelessSessionImpl;
+import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
+import org.hibernate.resource.jdbc.spi.StatementInspector;
+
+import java.sql.Connection;
+import java.util.List;
+import java.util.TimeZone;
+
+/**
+ * @author Steve Ebersole
+ */
+public class StatelessSessionBuilderImpl
+ extends AbstractCommonBuilder
+ implements StatelessSessionBuilder, SessionCreationOptions {
+
+ public StatelessSessionBuilderImpl(SessionFactoryImpl sessionFactory) {
+ super( sessionFactory );
+ }
+
+ @Override
+ protected StatelessSessionBuilder getThis() {
+ return this;
+ }
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // StatelessSessionBuilder
+
+ @Override
+ public StatelessSession openStatelessSession() {
+ return new StatelessSessionImpl( sessionFactory, this );
+ }
+
+ @Override
+ @Deprecated
+ public StatelessSessionBuilder tenantIdentifier(String tenantIdentifier) {
+ this.tenantIdentifier = tenantIdentifier;
+ return this;
+ }
+
+ @Override
+ @Deprecated
+ public StatelessSessionBuilder statementInspector(StatementInspector statementInspector) {
+ this.statementInspector = statementInspector;
+ return this;
+ }
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // SessionCreationOptions
+
+ @Override
+ public boolean shouldAutoJoinTransactions() {
+ return true;
+ }
+
+ @Override
+ public FlushMode getInitialSessionFlushMode() {
+ return FlushMode.ALWAYS;
+ }
+
+ @Override
+ public boolean isSubselectFetchEnabled() {
+ return false;
+ }
+
+ @Override
+ public int getDefaultBatchFetchSize() {
+ return -1;
+ }
+
+ @Override
+ public boolean shouldAutoClose() {
+ return false;
+ }
+
+ @Override
+ public boolean shouldAutoClear() {
+ return false;
+ }
+
+ @Override
+ public Connection getConnection() {
+ return connection;
+ }
+
+ @Override
+ public Interceptor getInterceptor() {
+ return SessionFactoryImpl.configuredInterceptor( interceptor, explicitNoInterceptor,
+ sessionFactory.getSessionFactoryOptions() );
+ }
+
+ @Override
+ public boolean isIdentifierRollbackEnabled() {
+ // identifier rollback is not yet implemented for StatelessSessions
+ return false;
+ }
+
+ @Override
+ public StatementInspector getStatementInspector() {
+ return statementInspector;
+ }
+
+ @Override
+ public PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode() {
+ return connectionHandlingMode;
+ }
+
+ @Override
+ public String getTenantIdentifier() {
+ return tenantIdentifier == null ? null
+ : sessionFactory.getTenantIdentifierJavaType().toString( tenantIdentifier );
+ }
+
+ @Override
+ public boolean isReadOnly() {
+ return readOnly;
+ }
+
+ @Override
+ public CacheMode getInitialCacheMode() {
+ return cacheMode;
+ }
+
+ @Override
+ public Object getTenantIdentifierValue() {
+ return tenantIdentifier;
+ }
+
+ @Override
+ public TimeZone getJdbcTimeZone() {
+ return sessionFactory.getSessionFactoryOptions().getJdbcTimeZone();
+ }
+
+ @Override
+ public List getCustomSessionEventListener() {
+ return null;
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/package-info.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/package-info.java
new file mode 100644
index 000000000000..9015b03f1fa6
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/package-info.java
@@ -0,0 +1,12 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+
+/**
+ * Support for the creation of {@linkplain org.hibernate.Session stateful}
+ * and {@linkplain org.hibernate.StatelessSession stateless} sessions.
+ *
+ * @author Steve Ebersole
+ */
+package org.hibernate.engine.creation;
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/spi/SessionBuilderImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/spi/SessionBuilderImplementor.java
new file mode 100644
index 000000000000..9fc437abdecd
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/spi/SessionBuilderImplementor.java
@@ -0,0 +1,93 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.engine.creation.spi;
+
+import org.hibernate.CacheMode;
+import org.hibernate.ConnectionAcquisitionMode;
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.FlushMode;
+import org.hibernate.Interceptor;
+import org.hibernate.SessionBuilder;
+import org.hibernate.SessionEventListener;
+import org.hibernate.engine.spi.SessionImplementor;
+import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
+import org.hibernate.resource.jdbc.spi.StatementInspector;
+
+import java.sql.Connection;
+import java.util.TimeZone;
+import java.util.function.UnaryOperator;
+
+/**
+ * Defines the internal contract between the {@link SessionBuilder} and
+ * other parts of Hibernate.
+ *
+ * @see SessionBuilder
+ *
+ * @author Gail Badner
+ */
+public interface SessionBuilderImplementor extends SessionBuilder {
+ @Override
+ SessionImplementor openSession();
+
+ @Override
+ SessionBuilderImplementor interceptor(Interceptor interceptor);
+
+ @Override
+ SessionBuilderImplementor noInterceptor();
+
+ @Override
+ SessionBuilderImplementor statementInspector(UnaryOperator operator);
+
+ @Override
+ SessionBuilderImplementor statementInspector(StatementInspector statementInspector);
+
+ @Override
+ SessionBuilderImplementor connection(Connection connection);
+
+ @Override
+ SessionBuilderImplementor connectionHandling(ConnectionAcquisitionMode acquisitionMode, ConnectionReleaseMode releaseMode);
+
+ @Override
+ SessionBuilderImplementor connectionHandlingMode(PhysicalConnectionHandlingMode mode);
+
+ @Override
+ SessionBuilderImplementor autoJoinTransactions(boolean autoJoinTransactions);
+
+ @Override
+ SessionBuilderImplementor autoClear(boolean autoClear);
+
+ @Override
+ SessionBuilderImplementor flushMode(FlushMode flushMode);
+
+ @Override
+ SessionBuilderImplementor tenantIdentifier(String tenantIdentifier);
+
+ @Override
+ SessionBuilderImplementor tenantIdentifier(Object tenantIdentifier);
+
+ @Override
+ SessionBuilderImplementor readOnly(boolean readOnly);
+
+ @Override
+ SessionBuilderImplementor initialCacheMode(CacheMode cacheMode);
+
+ @Override
+ SessionBuilderImplementor eventListeners(SessionEventListener... listeners);
+
+ @Override
+ SessionBuilderImplementor clearEventListeners();
+
+ @Override
+ SessionBuilderImplementor jdbcTimeZone(TimeZone timeZone);
+
+ @Override
+ SessionBuilderImplementor autoClose(boolean autoClose);
+
+ @Override
+ SessionBuilderImplementor identifierRollback(boolean identifierRollback);
+
+ @Override
+ SessionBuilderImplementor noStatementInspector();
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/creation/spi/SharedSessionBuilderImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/creation/spi/SharedSessionBuilderImplementor.java
new file mode 100644
index 000000000000..72b4c78b1bed
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/engine/creation/spi/SharedSessionBuilderImplementor.java
@@ -0,0 +1,109 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.engine.creation.spi;
+
+import org.hibernate.CacheMode;
+import org.hibernate.ConnectionAcquisitionMode;
+import org.hibernate.ConnectionReleaseMode;
+import org.hibernate.FlushMode;
+import org.hibernate.Interceptor;
+import org.hibernate.SessionEventListener;
+import org.hibernate.SharedSessionBuilder;
+import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
+import org.hibernate.resource.jdbc.spi.StatementInspector;
+
+import java.sql.Connection;
+import java.util.TimeZone;
+import java.util.function.UnaryOperator;
+
+/**
+ * @author Steve Ebersole
+ */
+public interface SharedSessionBuilderImplementor extends SharedSessionBuilder, SessionBuilderImplementor {
+ @Override
+ SharedSessionBuilderImplementor interceptor(Interceptor interceptor);
+
+ @Override
+ SharedSessionBuilderImplementor noInterceptor();
+
+ @Override
+ SharedSessionBuilderImplementor statementInspector(UnaryOperator operator);
+
+ @Override
+ SharedSessionBuilderImplementor statementInspector(StatementInspector statementInspector);
+
+ @Override
+ SharedSessionBuilderImplementor tenantIdentifier(Object tenantIdentifier);
+
+ @Override
+ SharedSessionBuilderImplementor readOnly(boolean readOnly);
+
+ @Override
+ SharedSessionBuilderImplementor initialCacheMode(CacheMode cacheMode);
+
+
+ @Override
+ SharedSessionBuilderImplementor connection();
+
+ @Override
+ SharedSessionBuilderImplementor interceptor();
+
+ @Override
+ SharedSessionBuilderImplementor connectionReleaseMode();
+
+ @Override
+ SharedSessionBuilderImplementor connectionHandlingMode();
+
+ @Override
+ SharedSessionBuilderImplementor autoJoinTransactions();
+
+ @Override
+ SharedSessionBuilderImplementor flushMode();
+
+ @Override
+ SharedSessionBuilderImplementor autoClose();
+
+ @Override
+ SharedSessionBuilderImplementor connectionHandlingMode(PhysicalConnectionHandlingMode mode);
+
+ @Override
+ SharedSessionBuilderImplementor connectionHandling(ConnectionAcquisitionMode acquisitionMode, ConnectionReleaseMode releaseMode);
+
+ @Override
+ SharedSessionBuilderImplementor autoClear(boolean autoClear);
+
+ @Override
+ SharedSessionBuilderImplementor flushMode(FlushMode flushMode);
+
+ @Override
+ SharedSessionBuilderImplementor tenantIdentifier(String tenantIdentifier);
+
+ @Override
+ SharedSessionBuilderImplementor eventListeners(SessionEventListener... listeners);
+
+ @Override
+ SharedSessionBuilderImplementor clearEventListeners();
+
+ @Override
+ SharedSessionBuilderImplementor jdbcTimeZone(TimeZone timeZone);
+
+ @Override
+ SharedSessionBuilderImplementor connection(Connection connection);
+
+ @Override
+ SharedSessionBuilderImplementor autoJoinTransactions(boolean autoJoinTransactions);
+
+ @Override
+ SharedSessionBuilderImplementor autoClose(boolean autoClose);
+
+ @Override
+ SharedSessionBuilderImplementor identifierRollback(boolean identifierRollback);
+
+ @Override
+ SharedSessionBuilderImplementor statementInspector();
+
+ @Override
+ SharedSessionBuilderImplementor noStatementInspector();
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/AbstractTransactionCompletionProcessQueue.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/AbstractTransactionCompletionProcessQueue.java
new file mode 100644
index 000000000000..6ee772b9d4a7
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/AbstractTransactionCompletionProcessQueue.java
@@ -0,0 +1,38 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.engine.internal;
+
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.engine.spi.TransactionCompletionCallbacks.CompletionCallback;
+
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+/**
+ * Collection of transaction completion {@linkplain CompletionCallback callbacks}.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractTransactionCompletionProcessQueue {
+ protected SharedSessionContractImplementor session;
+ // Concurrency handling required when transaction completion process is dynamically registered
+ // inside event listener (HHH-7478).
+ protected ConcurrentLinkedQueue<@NonNull T> processes = new ConcurrentLinkedQueue<>();
+
+ protected AbstractTransactionCompletionProcessQueue(SharedSessionContractImplementor session) {
+ this.session = session;
+ }
+
+ public void register(@Nullable T process) {
+ if ( process != null ) {
+ processes.add( process );
+ }
+ }
+
+ public boolean hasActions() {
+ return !processes.isEmpty();
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/AfterTransactionCompletionProcessQueue.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/AfterTransactionCompletionProcessQueue.java
new file mode 100644
index 000000000000..348561417c0a
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/AfterTransactionCompletionProcessQueue.java
@@ -0,0 +1,63 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.engine.internal;
+
+import org.hibernate.HibernateException;
+import org.hibernate.cache.CacheException;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.engine.spi.TransactionCompletionCallbacks.AfterCompletionCallback;
+import org.hibernate.internal.CoreLogging;
+import org.hibernate.internal.CoreMessageLogger;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Encapsulates behavior needed for after transaction processing
+ */
+public class AfterTransactionCompletionProcessQueue
+ extends AbstractTransactionCompletionProcessQueue {
+ private static final CoreMessageLogger LOG = CoreLogging.messageLogger( AfterTransactionCompletionProcessQueue.class );
+
+ private final Set querySpacesToInvalidate = new HashSet<>();
+
+ public AfterTransactionCompletionProcessQueue(SharedSessionContractImplementor session) {
+ super( session );
+ }
+
+ public void addSpaceToInvalidate(String space) {
+ querySpacesToInvalidate.add( space );
+ }
+
+ @Override
+ public boolean hasActions() {
+ return super.hasActions() || !querySpacesToInvalidate.isEmpty();
+ }
+
+ public void afterTransactionCompletion(boolean success) {
+ AfterCompletionCallback process;
+ while ( (process = processes.poll()) != null ) {
+ try {
+ process.doAfterTransactionCompletion( success, session );
+ }
+ catch (CacheException ce) {
+ LOG.unableToReleaseCacheLock( ce );
+ // continue loop
+ }
+ catch (Exception e) {
+ throw new HibernateException(
+ "Unable to perform afterTransactionCompletion callback: " + e.getMessage(), e );
+ }
+ }
+
+ final SessionFactoryImplementor factory = session.getFactory();
+ if ( factory.getSessionFactoryOptions().isQueryCacheEnabled() ) {
+ factory.getCache().getTimestampsCache()
+ .invalidate( querySpacesToInvalidate.toArray( new String[0] ), session );
+ }
+ querySpacesToInvalidate.clear();
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/BeforeTransactionCompletionProcessQueue.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/BeforeTransactionCompletionProcessQueue.java
new file mode 100644
index 000000000000..ae6f81e63d18
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/BeforeTransactionCompletionProcessQueue.java
@@ -0,0 +1,36 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.engine.internal;
+
+import org.hibernate.HibernateException;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.engine.spi.TransactionCompletionCallbacks.BeforeCompletionCallback;
+
+/**
+ * Encapsulates behavior needed for before transaction processing
+ */
+public class BeforeTransactionCompletionProcessQueue
+ extends AbstractTransactionCompletionProcessQueue {
+
+ public BeforeTransactionCompletionProcessQueue(SharedSessionContractImplementor session) {
+ super( session );
+ }
+
+ public void beforeTransactionCompletion() {
+ BeforeCompletionCallback process;
+ while ( (process = processes.poll()) != null ) {
+ try {
+ process.doBeforeTransactionCompletion( session );
+ }
+ catch (HibernateException he) {
+ throw he;
+ }
+ catch (Exception e) {
+ throw new HibernateException(
+ "Unable to perform beforeTransactionCompletion callback: " + e.getMessage(), e );
+ }
+ }
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/NaturalIdResolutionsImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/NaturalIdResolutionsImpl.java
index 1c0591af9d34..a6f495ea1977 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/internal/NaturalIdResolutionsImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/NaturalIdResolutionsImpl.java
@@ -320,7 +320,7 @@ private void cacheFromUpdate(
);
}
- session.asEventSource().getActionQueue().registerProcess(
+ session.asEventSource().getActionQueue().registerCallback(
(success, sess) -> {
cacheAccess.unlockItem( sess, previousCacheKey, removalLock );
if (success) {
@@ -387,7 +387,7 @@ private void cacheFromInsert(
);
}
- session.asEventSource().getActionQueue().registerProcess(
+ session.asEventSource().getActionQueue().registerCallback(
(success, sess) -> {
if ( success ) {
final boolean changed = cacheAccess.afterInsert( sess, cacheKey, id );
@@ -472,7 +472,7 @@ public void removeSharedResolution(Object id, Object naturalId, EntityMappingTyp
final var persister = locatePersisterForKey( entityDescriptor.getEntityPersister() );
final Object naturalIdCacheKey = cacheAccess.generateCacheKey( naturalId, persister, session );
if ( delayToAfterTransactionCompletion ) {
- session.asEventSource().getActionQueue().registerProcess(
+ session.asEventSource().getActionQueue().registerCallback(
(success, sess) -> {
if ( success ) {
cacheAccess.evict( naturalIdCacheKey );
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/TransactionCompletionCallbacksImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/TransactionCompletionCallbacksImpl.java
new file mode 100644
index 000000000000..4499b55ee1b2
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/TransactionCompletionCallbacksImpl.java
@@ -0,0 +1,76 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.engine.internal;
+
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.engine.spi.TransactionCompletionCallbacks;
+
+/**
+ * @author Steve Ebersole
+ */
+public class TransactionCompletionCallbacksImpl implements TransactionCompletionCallbacks {
+ private final SharedSessionContractImplementor session;
+
+ private BeforeTransactionCompletionProcessQueue beforeTransactionProcesses;
+ private AfterTransactionCompletionProcessQueue afterTransactionProcesses;
+
+ public TransactionCompletionCallbacksImpl(SharedSessionContractImplementor session) {
+ this.session = session;
+ }
+
+ @Override
+ public void registerCallback(BeforeCompletionCallback process) {
+ if ( beforeTransactionProcesses == null ) {
+ beforeTransactionProcesses = new BeforeTransactionCompletionProcessQueue( session );
+ }
+ beforeTransactionProcesses.register( process );
+ }
+
+ public boolean hasBeforeCompletionCallbacks() {
+ return beforeTransactionProcesses != null
+ && beforeTransactionProcesses.hasActions();
+ }
+
+ public void beforeTransactionCompletion() {
+ if ( beforeTransactionProcesses != null && beforeTransactionProcesses.hasActions() ) {
+ beforeTransactionProcesses.beforeTransactionCompletion();
+ }
+ }
+
+ @Override
+ public void registerCallback(AfterCompletionCallback process) {
+ if ( afterTransactionProcesses == null ) {
+ afterTransactionProcesses = new AfterTransactionCompletionProcessQueue( session );
+ }
+ afterTransactionProcesses.register( process );
+ }
+
+ public boolean hasAfterCompletionCallbacks() {
+ return afterTransactionProcesses != null && afterTransactionProcesses.hasActions();
+ }
+
+ public void afterTransactionCompletion(boolean success) {
+ if ( afterTransactionProcesses != null && afterTransactionProcesses.hasActions() ) {
+ afterTransactionProcesses.afterTransactionCompletion( success );
+ }
+ }
+
+ public void addSpaceToInvalidate(String space) {
+ if ( afterTransactionProcesses == null ) {
+ afterTransactionProcesses = new AfterTransactionCompletionProcessQueue( session );
+ }
+ afterTransactionProcesses.addSpaceToInvalidate( space );
+}
+
+ public TransactionCompletionCallbacksImpl forSharing() {
+ if ( beforeTransactionProcesses == null ) {
+ beforeTransactionProcesses = new BeforeTransactionCompletionProcessQueue( session );
+ }
+ if ( afterTransactionProcesses == null ) {
+ afterTransactionProcesses = new AfterTransactionCompletionProcessQueue( session );
+ }
+ return this;
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/AbstractDelegatingSessionBuilder.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/AbstractDelegatingSessionBuilder.java
index 6fe91e7a55e2..f77fcfb7689a 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/spi/AbstractDelegatingSessionBuilder.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/AbstractDelegatingSessionBuilder.java
@@ -13,9 +13,9 @@
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.FlushMode;
import org.hibernate.Interceptor;
-import org.hibernate.Session;
import org.hibernate.SessionBuilder;
import org.hibernate.SessionEventListener;
+import org.hibernate.engine.creation.spi.SessionBuilderImplementor;
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
import org.hibernate.resource.jdbc.spi.StatementInspector;
@@ -26,137 +26,143 @@
* @author Gunnar Morling
* @author Guillaume Smet
*/
-public abstract class AbstractDelegatingSessionBuilder implements SessionBuilder {
+public abstract class AbstractDelegatingSessionBuilder implements SessionBuilderImplementor {
- private final SessionBuilder delegate;
+ private final SessionBuilderImplementor delegate;
public AbstractDelegatingSessionBuilder(SessionBuilder delegate) {
- this.delegate = delegate;
+ this.delegate = (SessionBuilderImplementor) delegate;
}
protected SessionBuilder getThis() {
return this;
}
- protected SessionBuilder delegate() {
+ protected SessionBuilderImplementor delegate() {
return delegate;
}
@Override
- public Session openSession() {
+ public SessionImplementor openSession() {
return delegate.openSession();
}
@Override
- public SessionBuilder interceptor(Interceptor interceptor) {
+ public SessionBuilderImplementor interceptor(Interceptor interceptor) {
delegate.interceptor( interceptor );
return this;
}
@Override
- public SessionBuilder noInterceptor() {
+ public SessionBuilderImplementor noInterceptor() {
delegate.noInterceptor();
return this;
}
@Override @Deprecated
- public SessionBuilder statementInspector(StatementInspector statementInspector) {
+ public SessionBuilderImplementor statementInspector(StatementInspector statementInspector) {
delegate.statementInspector( statementInspector );
return this;
}
@Override
- public SessionBuilder statementInspector(UnaryOperator operator) {
+ public SessionBuilderImplementor statementInspector(UnaryOperator operator) {
delegate.statementInspector( operator );
return this;
}
@Override
- public SessionBuilder connection(Connection connection) {
+ public SessionBuilderImplementor noStatementInspector() {
+ delegate.noStatementInspector();
+ return this;
+ }
+
+ @Override
+ public SessionBuilderImplementor connection(Connection connection) {
delegate.connection( connection );
return this;
}
@Override
- public SessionBuilder autoJoinTransactions(boolean autoJoinTransactions) {
+ public SessionBuilderImplementor autoJoinTransactions(boolean autoJoinTransactions) {
delegate.autoJoinTransactions( autoJoinTransactions );
return this;
}
@Override
- public SessionBuilder autoClose(boolean autoClose) {
+ public SessionBuilderImplementor autoClose(boolean autoClose) {
delegate.autoClose( autoClose );
return this;
}
@Override @Deprecated(forRemoval = true)
- public SessionBuilder tenantIdentifier(String tenantIdentifier) {
+ public SessionBuilderImplementor tenantIdentifier(String tenantIdentifier) {
delegate.tenantIdentifier( tenantIdentifier );
return this;
}
@Override
- public SessionBuilder tenantIdentifier(Object tenantIdentifier) {
+ public SessionBuilderImplementor tenantIdentifier(Object tenantIdentifier) {
delegate.tenantIdentifier( tenantIdentifier );
return this;
}
@Override
- public SessionBuilder readOnly(boolean readOnly) {
+ public SessionBuilderImplementor readOnly(boolean readOnly) {
delegate.readOnly( readOnly );
return this;
}
@Override
- public SessionBuilder initialCacheMode(CacheMode cacheMode) {
+ public SessionBuilderImplementor initialCacheMode(CacheMode cacheMode) {
delegate.initialCacheMode( cacheMode );
return this;
}
@Override
- public SessionBuilder eventListeners(SessionEventListener... listeners) {
+ public SessionBuilderImplementor eventListeners(SessionEventListener... listeners) {
delegate.eventListeners( listeners );
return this;
}
@Override
- public SessionBuilder clearEventListeners() {
+ public SessionBuilderImplementor clearEventListeners() {
delegate.clearEventListeners();
return this;
}
@Override
- public SessionBuilder jdbcTimeZone(TimeZone timeZone) {
+ public SessionBuilderImplementor jdbcTimeZone(TimeZone timeZone) {
delegate.jdbcTimeZone(timeZone);
return this;
}
@Override @Deprecated
- public SessionBuilder connectionHandlingMode(PhysicalConnectionHandlingMode mode) {
+ public SessionBuilderImplementor connectionHandlingMode(PhysicalConnectionHandlingMode mode) {
delegate.connectionHandlingMode( mode );
return this;
}
@Override
- public SessionBuilder connectionHandling(ConnectionAcquisitionMode acquisitionMode, ConnectionReleaseMode releaseMode) {
+ public SessionBuilderImplementor connectionHandling(ConnectionAcquisitionMode acquisitionMode, ConnectionReleaseMode releaseMode) {
delegate.connectionHandling( acquisitionMode, releaseMode );
return this;
}
@Override
- public SessionBuilder autoClear(boolean autoClear) {
+ public SessionBuilderImplementor autoClear(boolean autoClear) {
delegate.autoClear( autoClear );
return this;
}
@Override
- public SessionBuilder flushMode(FlushMode flushMode) {
+ public SessionBuilderImplementor flushMode(FlushMode flushMode) {
delegate.flushMode( flushMode );
return this;
}
@Override
- public SessionBuilder identifierRollback(boolean identifierRollback) {
+ public SessionBuilderImplementor identifierRollback(boolean identifierRollback) {
delegate.identifierRollback( identifierRollback );
return this;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/AbstractDelegatingSessionBuilderImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/AbstractDelegatingSessionBuilderImplementor.java
index 7d6ce38f6aec..1cd8f8e490a8 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/spi/AbstractDelegatingSessionBuilderImplementor.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/AbstractDelegatingSessionBuilderImplementor.java
@@ -4,6 +4,8 @@
*/
package org.hibernate.engine.spi;
+import org.hibernate.engine.creation.spi.SessionBuilderImplementor;
+
/**
* Base class for {@link SessionBuilderImplementor} implementations that wish to implement only parts of that contract
* themselves while forwarding other method invocations to a delegate instance.
@@ -16,7 +18,4 @@ public AbstractDelegatingSessionBuilderImplementor(SessionBuilderImplementor del
super( delegate );
}
- protected SessionBuilderImplementor delegate() {
- return (SessionBuilderImplementor) super.delegate();
- }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/AbstractDelegatingSharedSessionBuilder.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/AbstractDelegatingSharedSessionBuilder.java
index 1a6de07f196c..e947fc22a6bc 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/spi/AbstractDelegatingSharedSessionBuilder.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/AbstractDelegatingSharedSessionBuilder.java
@@ -8,13 +8,13 @@
import java.util.TimeZone;
import java.util.function.UnaryOperator;
+import org.hibernate.engine.creation.CommonSharedBuilder;
import org.hibernate.CacheMode;
import org.hibernate.ConnectionAcquisitionMode;
import org.hibernate.ConnectionReleaseMode;
import org.hibernate.FlushMode;
import org.hibernate.Interceptor;
import org.hibernate.Session;
-import org.hibernate.SessionBuilder;
import org.hibernate.SessionEventListener;
import org.hibernate.SharedSessionBuilder;
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
@@ -28,7 +28,6 @@
* @author Guillaume Smet
*/
public abstract class AbstractDelegatingSharedSessionBuilder implements SharedSessionBuilder {
-
private final SharedSessionBuilder delegate;
public AbstractDelegatingSharedSessionBuilder(SharedSessionBuilder delegate) {
@@ -103,11 +102,23 @@ public SharedSessionBuilder statementInspector(StatementInspector statementInspe
}
@Override
- public SessionBuilder statementInspector(UnaryOperator operator) {
+ public SharedSessionBuilder statementInspector(UnaryOperator operator) {
delegate.statementInspector( operator );
return this;
}
+ @Override
+ public CommonSharedBuilder statementInspector() {
+ delegate.statementInspector();
+ return this;
+ }
+
+ @Override
+ public CommonSharedBuilder noStatementInspector() {
+ delegate.noStatementInspector();
+ return this;
+ }
+
@Override
public SharedSessionBuilder connection(Connection connection) {
delegate.connection( connection );
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java
index b65b407a8df3..ad6ca4f18805 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java
@@ -17,7 +17,6 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.ConcurrentLinkedQueue;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
@@ -40,8 +39,8 @@
import org.hibernate.action.spi.BeforeTransactionCompletionProcess;
import org.hibernate.action.spi.Executable;
import org.hibernate.boot.spi.SessionFactoryOptions;
-import org.hibernate.cache.CacheException;
import org.hibernate.engine.internal.NonNullableTransientDependencies;
+import org.hibernate.engine.internal.TransactionCompletionCallbacksImpl;
import org.hibernate.event.spi.EventSource;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
@@ -55,7 +54,6 @@
import org.hibernate.type.ForeignKeyDirection;
import org.hibernate.type.Type;
-import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
@@ -70,7 +68,7 @@
* @author Gail Badner
* @author Anton Marsden
*/
-public class ActionQueue {
+public class ActionQueue implements TransactionCompletionCallbacks {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( ActionQueue.class );
private final SessionImplementor session;
@@ -102,8 +100,7 @@ public class ActionQueue {
private transient boolean isTransactionCoordinatorShared;
- private AfterTransactionCompletionProcessQueue afterTransactionProcesses;
- private BeforeTransactionCompletionProcessQueue beforeTransactionProcesses;
+ private TransactionCompletionCallbacksImpl transactionCompletionCallbacks;;
// Extract this as a constant to perform efficient iterations:
// method values() otherwise allocates a new array on each invocation.
@@ -235,6 +232,7 @@ public void ensureInitialized(ActionQueue instance) {
public ActionQueue(SessionImplementor session) {
this.session = session;
isTransactionCoordinatorShared = false;
+ transactionCompletionCallbacks = new TransactionCompletionCallbacksImpl( session );
}
public void clear() {
@@ -417,20 +415,18 @@ public void addAction(BulkOperationCleanupAction action) {
}
private void registerCleanupActions(Executable executable) {
- if ( executable.getBeforeTransactionCompletionProcess() != null ) {
- if ( beforeTransactionProcesses == null ) {
- beforeTransactionProcesses = new BeforeTransactionCompletionProcessQueue( session );
- }
- beforeTransactionProcesses.register( executable.getBeforeTransactionCompletionProcess() );
+ final BeforeTransactionCompletionProcess beforeCompletionCallback = executable.getBeforeTransactionCompletionProcess();
+ if ( beforeCompletionCallback != null ) {
+ transactionCompletionCallbacks.registerCallback( beforeCompletionCallback );
}
+
if ( getSessionFactoryOptions().isQueryCacheEnabled() ) {
invalidateSpaces( executable.getPropertySpaces() );
}
- if ( executable.getAfterTransactionCompletionProcess() != null ) {
- if ( afterTransactionProcesses == null ) {
- afterTransactionProcesses = new AfterTransactionCompletionProcessQueue( session );
- }
- afterTransactionProcesses.register( executable.getAfterTransactionCompletionProcess() );
+
+ final AfterTransactionCompletionProcess afterCompletionCallback = executable.getAfterTransactionCompletionProcess();
+ if ( afterCompletionCallback != null ) {
+ transactionCompletionCallbacks.registerCallback( afterCompletionCallback );
}
}
@@ -460,18 +456,14 @@ public void checkNoUnresolvedActionsAfterOperation() throws PropertyValueExcepti
}
}
- public void registerProcess(AfterTransactionCompletionProcess process) {
- if ( afterTransactionProcesses == null ) {
- afterTransactionProcesses = new AfterTransactionCompletionProcessQueue( session );
- }
- afterTransactionProcesses.register( process );
+ @Override
+ public void registerCallback(BeforeCompletionCallback process) {
+ transactionCompletionCallbacks.registerCallback( process );
}
- public void registerProcess(BeforeTransactionCompletionProcess process) {
- if ( beforeTransactionProcesses == null ) {
- beforeTransactionProcesses = new BeforeTransactionCompletionProcessQueue( session );
- }
- beforeTransactionProcesses.register( process );
+ @Override
+ public void registerCallback(AfterCompletionCallback process) {
+ transactionCompletionCallbacks.registerCallback( process );
}
/**
@@ -542,9 +534,7 @@ private void prepareActions(@Nullable ExecutableList> queue) throws HibernateE
public void afterTransactionCompletion(boolean success) {
if ( !isTransactionCoordinatorShared ) {
// Execute completion actions only in transaction owner (aka parent session).
- if ( afterTransactionProcesses != null ) {
- afterTransactionProcesses.afterTransactionCompletion( success );
- }
+ transactionCompletionCallbacks.afterTransactionCompletion( success );
}
}
@@ -554,9 +544,7 @@ public void afterTransactionCompletion(boolean success) {
public void beforeTransactionCompletion() {
if ( !isTransactionCoordinatorShared ) {
// Execute completion actions only in transaction owner (aka parent session).
- if ( beforeTransactionProcesses != null ) {
- beforeTransactionProcesses.beforeTransactionCompletion();
- }
+ transactionCompletionCallbacks.beforeTransactionCompletion();
// Make sure to always execute pending batches before the transaction completes.
// One such pending batch could be the pessimistic version increment for an entity
session.getJdbcCoordinator().executeBatch();
@@ -646,17 +634,14 @@ private void executeActions(@Nullable Executabl
executable.execute();
}
finally {
- if ( executable.getBeforeTransactionCompletionProcess() != null ) {
- if ( beforeTransactionProcesses == null ) {
- beforeTransactionProcesses = new BeforeTransactionCompletionProcessQueue( session );
- }
- beforeTransactionProcesses.register( executable.getBeforeTransactionCompletionProcess() );
+ final BeforeTransactionCompletionProcess beforeCompletionProcess = executable.getBeforeTransactionCompletionProcess();
+ if ( beforeCompletionProcess != null ) {
+ transactionCompletionCallbacks.registerCallback( beforeCompletionProcess );
}
- if ( executable.getAfterTransactionCompletionProcess() != null ) {
- if ( afterTransactionProcesses == null ) {
- afterTransactionProcesses = new AfterTransactionCompletionProcessQueue( session );
- }
- afterTransactionProcesses.register( executable.getAfterTransactionCompletionProcess() );
+
+ final AfterTransactionCompletionProcess afterCompletionProcess = executable.getAfterTransactionCompletionProcess();
+ if ( afterCompletionProcess != null ) {
+ transactionCompletionCallbacks.registerCallback( afterCompletionProcess );
}
}
}
@@ -696,10 +681,7 @@ public > void execute(E executable) {
private void invalidateSpaces(String @Nullable [] spaces) {
if ( spaces != null && spaces.length > 0 ) {
for ( String space : spaces ) {
- if ( afterTransactionProcesses == null ) {
- afterTransactionProcesses = new AfterTransactionCompletionProcessQueue( session );
- }
- afterTransactionProcesses.addSpaceToInvalidate( space );
+ transactionCompletionCallbacks.addSpaceToInvalidate( space );
}
// Performance win: If we are processing an ExecutableList, this will only be called once
session.getFactory().getCache().getTimestampsCache().preInvalidate( spaces, session );
@@ -755,14 +737,8 @@ public int numberOfInsertions() {
return insertions == null ? 0 : insertions.size();
}
- public TransactionCompletionProcesses getTransactionCompletionProcesses() {
- if ( beforeTransactionProcesses == null ) {
- beforeTransactionProcesses = new BeforeTransactionCompletionProcessQueue( session );
- }
- if ( afterTransactionProcesses == null ) {
- afterTransactionProcesses = new AfterTransactionCompletionProcessQueue( session );
- }
- return new TransactionCompletionProcesses( beforeTransactionProcesses, afterTransactionProcesses );
+ public TransactionCompletionCallbacksImpl getTransactionCompletionCallbacks() {
+ return transactionCompletionCallbacks.forSharing();
}
/**
@@ -770,15 +746,14 @@ public TransactionCompletionProcesses getTransactionCompletionProcesses() {
* Transaction completion processes are always executed by transaction owner (primary session),
* but can be registered using secondary session too.
*
- * @param processes Transaction completion processes.
+ * @param callbacks Transaction completion callbacks.
* @param isTransactionCoordinatorShared Flag indicating shared transaction context.
*/
- public void setTransactionCompletionProcesses(
- TransactionCompletionProcesses processes,
+ public void setTransactionCompletionCallbacks(
+ TransactionCompletionCallbacksImpl callbacks,
boolean isTransactionCoordinatorShared) {
this.isTransactionCoordinatorShared = isTransactionCoordinatorShared;
- this.beforeTransactionProcesses = processes.beforeTransactionCompletionProcesses;
- this.afterTransactionProcesses = processes.afterTransactionCompletionProcesses;
+ this.transactionCompletionCallbacks = callbacks;
}
public void sortCollectionActions() {
@@ -843,14 +818,12 @@ public void clearFromFlushNeededCheck(int previousCollectionRemovalSize) {
public boolean hasAfterTransactionActions() {
return !isTransactionCoordinatorShared
- && afterTransactionProcesses != null
- && afterTransactionProcesses.hasActions();
+ && transactionCompletionCallbacks.hasAfterCompletionCallbacks();
}
public boolean hasBeforeTransactionActions() {
return !isTransactionCoordinatorShared
- && beforeTransactionProcesses != null
- && beforeTransactionProcesses.hasActions();
+ && transactionCompletionCallbacks.hasBeforeCompletionCallbacks();
}
public boolean hasAnyQueuedActions() {
@@ -980,107 +953,6 @@ public static ActionQueue deserialize(ObjectInputStream ois, EventSource session
return rtn;
}
- private abstract static class AbstractTransactionCompletionProcessQueue {
- protected SessionImplementor session;
- // Concurrency handling required when transaction completion process is dynamically registered
- // inside event listener (HHH-7478).
- protected ConcurrentLinkedQueue<@NonNull T> processes = new ConcurrentLinkedQueue<>();
-
- private AbstractTransactionCompletionProcessQueue(SessionImplementor session) {
- this.session = session;
- }
-
- public void register(@Nullable T process) {
- if ( process != null ) {
- processes.add( process );
- }
- }
-
- public boolean hasActions() {
- return !processes.isEmpty();
- }
- }
-
- /**
- * Encapsulates behavior needed for before transaction processing
- */
- private static class BeforeTransactionCompletionProcessQueue
- extends AbstractTransactionCompletionProcessQueue {
-
- private BeforeTransactionCompletionProcessQueue(SessionImplementor session) {
- super( session );
- }
-
- public void beforeTransactionCompletion() {
- BeforeTransactionCompletionProcess process;
- while ( ( process = processes.poll() ) != null ) {
- try {
- process.doBeforeTransactionCompletion( session );
- }
- catch (HibernateException he) {
- throw he;
- }
- catch (Exception e) {
- throw new HibernateException( "Unable to perform beforeTransactionCompletion callback: " + e.getMessage(), e );
- }
- }
- }
- }
-
- /**
- * Encapsulates behavior needed for after transaction processing
- */
- private static class AfterTransactionCompletionProcessQueue
- extends AbstractTransactionCompletionProcessQueue {
- private final Set querySpacesToInvalidate = new HashSet<>();
-
- private AfterTransactionCompletionProcessQueue(SessionImplementor session) {
- super( session );
- }
-
- public void addSpaceToInvalidate(String space) {
- querySpacesToInvalidate.add( space );
- }
-
- public void afterTransactionCompletion(boolean success) {
- AfterTransactionCompletionProcess process;
- while ( ( process = processes.poll() ) != null ) {
- try {
- process.doAfterTransactionCompletion( success, session );
- }
- catch (CacheException ce) {
- LOG.unableToReleaseCacheLock( ce );
- // continue loop
- }
- catch (Exception e) {
- throw new HibernateException( "Unable to perform afterTransactionCompletion callback: " + e.getMessage(), e );
- }
- }
-
- final SessionFactoryImplementor factory = session.getFactory();
- if ( factory.getSessionFactoryOptions().isQueryCacheEnabled() ) {
- factory.getCache().getTimestampsCache()
- .invalidate( querySpacesToInvalidate.toArray(new String[0]), session );
- }
- querySpacesToInvalidate.clear();
- }
- }
-
- /**
- * Wrapper class allowing to bind the same transaction completion process queues in different sessions.
- */
- public static class TransactionCompletionProcesses {
- private final BeforeTransactionCompletionProcessQueue beforeTransactionCompletionProcesses;
- private final AfterTransactionCompletionProcessQueue afterTransactionCompletionProcesses;
-
- private TransactionCompletionProcesses(
- BeforeTransactionCompletionProcessQueue beforeTransactionCompletionProcessQueue,
- AfterTransactionCompletionProcessQueue afterTransactionCompletionProcessQueue) {
- this.beforeTransactionCompletionProcesses = beforeTransactionCompletionProcessQueue;
- this.afterTransactionCompletionProcesses = afterTransactionCompletionProcessQueue;
- }
- }
-
/**
* Order the {@link #insertions} queue such that we group inserts against the same entity together (without
* violating constraints). The original order is generated by cascade order, which in turn is based on the
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/LoadQueryInfluencers.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/LoadQueryInfluencers.java
index cd495ccde8c5..804cb47f7288 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/spi/LoadQueryInfluencers.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/LoadQueryInfluencers.java
@@ -19,7 +19,7 @@
import org.hibernate.graph.GraphSemantic;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.internal.FilterImpl;
-import org.hibernate.internal.SessionCreationOptions;
+import org.hibernate.engine.creation.internal.SessionCreationOptions;
import org.hibernate.loader.ast.spi.CascadingFetchProfile;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionBuilderImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionBuilderImplementor.java
deleted file mode 100644
index 049d73d15cdb..000000000000
--- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionBuilderImplementor.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * SPDX-License-Identifier: Apache-2.0
- * Copyright Red Hat Inc. and Hibernate Authors
- */
-package org.hibernate.engine.spi;
-
-import org.hibernate.SessionBuilder;
-
-/**
- * Defines the internal contract between the {@link SessionBuilder} and
- * other parts of Hibernate.
- *
- * @see SessionBuilder
- *
- * @author Gail Badner
- */
-public interface SessionBuilderImplementor extends SessionBuilder {
-}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java
index 1a3e6f483fe9..ece114ba9ab9 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java
@@ -36,10 +36,10 @@
import org.hibernate.ReplicationMode;
import org.hibernate.SessionEventListener;
import org.hibernate.SharedSessionBuilder;
+import org.hibernate.SharedStatelessSessionBuilder;
import org.hibernate.SimpleNaturalIdLoadAccess;
import org.hibernate.Transaction;
import org.hibernate.UnknownProfileException;
-import org.hibernate.action.spi.AfterTransactionCompletionProcess;
import org.hibernate.bytecode.enhance.spi.interceptor.SessionAssociationMarkers;
import org.hibernate.cache.spi.CacheTransactionSynchronization;
import org.hibernate.collection.spi.PersistentCollection;
@@ -111,6 +111,11 @@ public T execute(Callback callback) {
return delegate.execute( callback );
}
+ @Override
+ public SharedStatelessSessionBuilder statelessWithOptions() {
+ return delegate.statelessWithOptions();
+ }
+
@Override
public String getTenantIdentifier() {
return delegate.getTenantIdentifier();
@@ -1156,8 +1161,8 @@ public ActionQueue getActionQueue() {
}
@Override
- public void registerProcess(AfterTransactionCompletionProcess process) {
- delegate.registerProcess( process );
+ public TransactionCompletionCallbacks getTransactionCompletionCallbacks() {
+ return delegate.getTransactionCompletionCallbacks();
}
@Override
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryDelegatingImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryDelegatingImpl.java
index 274015be5b4e..0a39869ab02c 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryDelegatingImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryDelegatingImpl.java
@@ -34,6 +34,7 @@
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.cache.spi.CacheImplementor;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
+import org.hibernate.engine.creation.spi.SessionBuilderImplementor;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.profile.FetchProfile;
import org.hibernate.event.service.spi.EventListenerRegistry;
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java
index 87af19367ca2..1f5625e7123d 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java
@@ -17,6 +17,7 @@
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.cache.spi.CacheImplementor;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
+import org.hibernate.engine.creation.spi.SessionBuilderImplementor;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.profile.FetchProfile;
import org.hibernate.event.service.spi.EventListenerRegistry;
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java
index bf62391fefe9..daefd65cff10 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java
@@ -73,6 +73,11 @@ default SessionImplementor getSession() {
*/
ActionQueue getActionQueue();
+ @Override
+ default TransactionCompletionCallbacks getTransactionCompletionCallbacks() {
+ return getActionQueue();
+ }
+
@Override
Object instantiate(EntityPersister persister, Object id) throws HibernateException;
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java
index b8b0195dd657..13bfb10a7ee7 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java
@@ -40,6 +40,7 @@
import org.hibernate.SessionEventListener;
import org.hibernate.SessionFactory;
import org.hibernate.SharedSessionBuilder;
+import org.hibernate.SharedStatelessSessionBuilder;
import org.hibernate.SimpleNaturalIdLoadAccess;
import org.hibernate.Transaction;
import org.hibernate.UnknownProfileException;
@@ -544,6 +545,11 @@ public Query createQuery(CriteriaUpdate updateQuery) {
return this.lazySession.get().createQuery( updateQuery );
}
+ @Override
+ public SharedStatelessSessionBuilder statelessWithOptions() {
+ return this.lazySession.get().statelessWithOptions();
+ }
+
@Override
public String getTenantIdentifier() {
return this.lazySession.get().getTenantIdentifier();
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java
index 2cc3517198a5..715f13f700e9 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java
@@ -16,7 +16,6 @@
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.StatelessSession;
-import org.hibernate.action.spi.AfterTransactionCompletionProcess;
import org.hibernate.bytecode.enhance.spi.interceptor.SessionAssociationMarkers;
import org.hibernate.dialect.Dialect;
import org.hibernate.event.spi.EventSource;
@@ -247,6 +246,14 @@ default void checkTransactionNeededForUpdateOperation(String exceptionMessage) {
*/
Transaction accessTransaction();
+ /**
+ * Access to register callbacks for transaction completion processing.
+ *
+ * @since 7.2
+ */
+ @Incubating
+ TransactionCompletionCallbacks getTransactionCompletionCallbacks();
+
/**
* Instantiate an {@link EntityKey} with the given id and for the
* entity represented by the given {@link EntityPersister}.
@@ -409,6 +416,16 @@ default EventSource asEventSource() {
throw new ClassCastException( "session is not an EventSource" );
}
+ /**
+ * Whether the session {@linkplain StatelessSessionImplementor stateless}, as opposed tp
+ * {@linkplain SessionImplementor stateful}.
+ *
+ * @apiNote Essentially, whether casting this session to {@linkplain StatelessSessionImplementor} will succeed.
+ */
+ default boolean isStateless() {
+ return false;
+ }
+
/**
* Called after each operation on a {@link org.hibernate.ScrollableResults},
* providing an opportunity for a stateless session to clear its
@@ -551,15 +568,6 @@ default boolean isStatelessSession() {
*/
void lock(String entityName, Object child, LockOptions lockOptions);
- /**
- * Registers the given process for execution after transaction completion.
- *
- * @param process The process to register
- * @since 7.0
- */
- @Incubating
- void registerProcess(AfterTransactionCompletionProcess process);
-
/**
* Attempts to load the entity from the second-level cache.
*
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java
index 5175ea06e686..e8ececa07237 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionDelegatorBaseImpl.java
@@ -18,8 +18,8 @@
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.SharedSessionContract;
+import org.hibernate.SharedStatelessSessionBuilder;
import org.hibernate.Transaction;
-import org.hibernate.action.spi.AfterTransactionCompletionProcess;
import org.hibernate.bytecode.enhance.spi.interceptor.SessionAssociationMarkers;
import org.hibernate.cache.spi.CacheTransactionSynchronization;
import org.hibernate.collection.spi.PersistentCollection;
@@ -75,6 +75,11 @@ protected SharedSessionContract delegate() {
return delegate;
}
+ @Override
+ public SharedStatelessSessionBuilder statelessWithOptions() {
+ return delegate.statelessWithOptions();
+ }
+
@Override
public String getTenantIdentifier() {
return delegate.getTenantIdentifier();
@@ -411,6 +416,11 @@ public Transaction accessTransaction() {
return delegate.accessTransaction();
}
+ @Override
+ public TransactionCompletionCallbacks getTransactionCompletionCallbacks() {
+ return delegate.getTransactionCompletionCallbacks();
+ }
+
@Override
public EntityKey generateEntityKey(Object id, EntityPersister persister) {
return delegate.generateEntityKey( id, persister );
@@ -687,11 +697,6 @@ public void lock(String entityName, Object child, LockOptions lockOptions) {
delegate.lock( entityName, child, lockOptions );
}
- @Override
- public void registerProcess(AfterTransactionCompletionProcess process) {
- delegate.registerProcess( process );
- }
-
@Override
public Object loadFromSecondLevelCache(EntityPersister persister, EntityKey entityKey, Object instanceToLoad, LockMode lockMode) {
return delegate.loadFromSecondLevelCache( persister, entityKey, instanceToLoad, lockMode );
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/StatelessSessionImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/StatelessSessionImplementor.java
new file mode 100644
index 000000000000..a5840d6d5921
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/StatelessSessionImplementor.java
@@ -0,0 +1,19 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.engine.spi;
+
+import org.hibernate.StatelessSession;
+
+/**
+ * SPI extension of StatelessSession
+ *
+ * @author Steve Ebersole
+ */
+public interface StatelessSessionImplementor extends StatelessSession, SharedSessionContractImplementor {
+ @Override
+ default boolean isStateless() {
+ return true;
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/TransactionCompletionCallbacks.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/TransactionCompletionCallbacks.java
new file mode 100644
index 000000000000..53e6401c12ad
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/TransactionCompletionCallbacks.java
@@ -0,0 +1,57 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.engine.spi;
+
+import org.hibernate.Incubating;
+
+/**
+ * Collection of {@linkplain BeforeCompletionCallback before} and {@linkplain AfterCompletionCallback after}
+ * callbacks related to transaction completion.
+ *
+ * @author Steve Ebersole
+ */
+@Incubating
+public interface TransactionCompletionCallbacks {
+ /**
+ * Commonality for {@linkplain BeforeCompletionCallback before} and
+ * {@linkplain AfterCompletionCallback after} callbacks.
+ */
+ interface CompletionCallback {
+ }
+
+ interface BeforeCompletionCallback extends CompletionCallback {
+ /**
+ * Perform whatever processing is encapsulated here before completion of the transaction.
+ *
+ * @param session The session on which the transaction is preparing to complete.
+ */
+ void doBeforeTransactionCompletion(SharedSessionContractImplementor session);
+
+ }
+
+ interface AfterCompletionCallback extends CompletionCallback {
+ /**
+ * Perform whatever processing is encapsulated here after completion of the transaction.
+ *
+ * @param success Did the transaction complete successfully? True means it did.
+ * @param session The session on which the transaction is completing.
+ */
+ void doAfterTransactionCompletion(boolean success, SharedSessionContractImplementor session);
+ }
+
+ /**
+ * Register a {@code process} (callback) to be performed at the start of transaction completion.
+ *
+ * @param process The callback.
+ */
+ void registerCallback(BeforeCompletionCallback process);
+
+ /**
+ * Register a {@code process} (callback) to be performed at the end of transaction completion.
+ *
+ * @param process The callback.
+ */
+ void registerCallback(AfterCompletionCallback process);
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLockEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLockEventListener.java
index 259a1290ec62..c4f91b9c225f 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLockEventListener.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLockEventListener.java
@@ -13,7 +13,7 @@
import org.hibernate.engine.spi.CascadingActions;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.Status;
-import org.hibernate.event.spi.AbstractEvent;
+import org.hibernate.event.spi.AbstractSessionEvent;
import org.hibernate.event.spi.LockEvent;
import org.hibernate.event.spi.LockEventListener;
import org.hibernate.internal.CoreMessageLogger;
@@ -113,7 +113,7 @@ private void cascadeOnLock(LockEvent event, EntityPersister persister, Object en
*
* @return An EntityEntry representing the entity within this session.
*/
- protected final EntityEntry reassociate(AbstractEvent event, Object object, Object id, EntityPersister persister) {
+ protected final EntityEntry reassociate(AbstractSessionEvent event, Object object, Object id, EntityPersister persister) {
if ( LOG.isTraceEnabled() ) {
LOG.trace( "Reassociating transient instance: " + infoString( persister, id, event.getFactory() ) );
diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPostLoadEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPostLoadEventListener.java
index e7130c4e8aca..a929a2362b94 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPostLoadEventListener.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultPostLoadEventListener.java
@@ -51,10 +51,10 @@ public void onPostLoad(PostLoadEvent event) {
OptimisticLockHelper.forceVersionIncrement( entity, entry, session );
break;
case OPTIMISTIC_FORCE_INCREMENT:
- session.getActionQueue().registerProcess( new EntityIncrementVersionProcess( entity ) );
+ session.getActionQueue().registerCallback( new EntityIncrementVersionProcess( entity ) );
break;
case OPTIMISTIC:
- session.getActionQueue().registerProcess( new EntityVerifyVersionProcess( entity ) );
+ session.getActionQueue().registerCallback( new EntityVerifyVersionProcess( entity ) );
break;
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultRefreshEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultRefreshEventListener.java
index 797ed7220049..80bb56daec38 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultRefreshEventListener.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultRefreshEventListener.java
@@ -233,7 +233,7 @@ private static void evictEntity(Object object, EntityPersister persister, Object
);
final SoftLock lock = cache.lockItem( source, ck, previousVersion );
cache.remove( source, ck );
- source.getActionQueue().registerProcess( (success, session) -> cache.unlockItem( session, ck, lock ) );
+ source.getActionQueue().registerCallback( (success, session) -> cache.unlockItem( session, ck, lock ) );
}
}
@@ -342,7 +342,7 @@ private static void evictCachedCollections(Type[] types, Object id, EventSource
);
final SoftLock lock = cache.lockItem( source, ck, null );
cache.remove( source, ck );
- actionQueue.registerProcess( (success, session) -> cache.unlockItem( session, ck, lock ) );
+ actionQueue.registerCallback( (success, session) -> cache.unlockItem( session, ck, lock ) );
}
}
else if ( type instanceof ComponentType compositeType ) {
diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/PostInsertEventListenerStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/event/internal/PostInsertEventListenerStandardImpl.java
index fe9ad65ad96c..224bc5866e4a 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/internal/PostInsertEventListenerStandardImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/internal/PostInsertEventListenerStandardImpl.java
@@ -18,6 +18,9 @@
public class PostInsertEventListenerStandardImpl implements PostInsertEventListener, CallbackRegistryConsumer {
private CallbackRegistry callbackRegistry;
+ public PostInsertEventListenerStandardImpl() {
+ }
+
@Override
public void injectCallbackRegistry(CallbackRegistry callbackRegistry) {
this.callbackRegistry = callbackRegistry;
diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/PostUpdateEventListenerStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/event/internal/PostUpdateEventListenerStandardImpl.java
index dd0d2bbbc233..49792534e893 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/internal/PostUpdateEventListenerStandardImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/internal/PostUpdateEventListenerStandardImpl.java
@@ -4,8 +4,8 @@
*/
package org.hibernate.event.internal;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status;
-import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.PostUpdateEvent;
import org.hibernate.event.spi.PostUpdateEventListener;
import org.hibernate.jpa.event.spi.CallbackRegistry;
@@ -29,9 +29,9 @@ public void onPostUpdate(PostUpdateEvent event) {
handlePostUpdate( event.getEntity(), event.getSession() );
}
- private void handlePostUpdate(Object entity, EventSource source) {
+ private void handlePostUpdate(Object entity, SharedSessionContractImplementor source) {
// mimic the preUpdate filter
- if ( source == null // it must be a StatelessSession
+ if ( source.isStateless()
|| source.getPersistenceContextInternal().getEntry(entity).getStatus() != Status.DELETED ) {
callbackRegistry.postUpdate(entity);
}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/PostUpsertEventListenerStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/event/internal/PostUpsertEventListenerStandardImpl.java
index 390abf11cf4c..3cbd7abc909a 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/internal/PostUpsertEventListenerStandardImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/internal/PostUpsertEventListenerStandardImpl.java
@@ -4,7 +4,7 @@
*/
package org.hibernate.event.internal;
-import org.hibernate.event.spi.EventSource;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.spi.PostUpsertEvent;
import org.hibernate.event.spi.PostUpsertEventListener;
import org.hibernate.jpa.event.spi.CallbackRegistry;
@@ -29,7 +29,7 @@ public void onPostUpsert(PostUpsertEvent event) {
handlePostUpsert( event.getEntity(), event.getSession() );
}
- private void handlePostUpsert(Object entity, EventSource source) {
+ private void handlePostUpsert(Object entity, SharedSessionContractImplementor source) {
// // mimic the preUpdate filter
// if ( source == null // it must be a StatelessSession
// || source.getPersistenceContextInternal().getEntry(entity).getStatus() != Status.DELETED ) {
diff --git a/hibernate-core/src/main/java/org/hibernate/event/package-info.java b/hibernate-core/src/main/java/org/hibernate/event/package-info.java
index 3ce6afb2502b..c237ff6009cb 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/package-info.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/package-info.java
@@ -6,7 +6,7 @@
/**
* This package defines a framework which models events occurring
* within a stateful Hibernate {@link org.hibernate.Session}. An
- * {@linkplain org.hibernate.event.spi.AbstractEvent event}
+ * {@linkplain org.hibernate.event.spi.AbstractSessionEvent event}
* represents a request by the session API for some work to be
* performed, and an event listener must respond to the event and
* do that work, usually by scheduling some sort of
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractCollectionEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractCollectionEvent.java
index 33e93d63e55f..9ffbe16cd706 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractCollectionEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractCollectionEvent.java
@@ -12,7 +12,7 @@
*
* @author Gail Badner
*/
-public abstract class AbstractCollectionEvent extends AbstractEvent {
+public abstract class AbstractCollectionEvent extends AbstractSessionEvent {
private final PersistentCollection> collection;
private final Object affectedOwner;
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractDatabaseOperationEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractDatabaseOperationEvent.java
index 8bcb94f39904..2f88ea46e12b 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractDatabaseOperationEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractDatabaseOperationEvent.java
@@ -4,19 +4,20 @@
*/
package org.hibernate.event.spi;
-import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.persister.entity.EntityPersister;
/**
- * Abstract supertype of {@link AbstractPostDatabaseOperationEvent}
- * and {@link AbstractPostDatabaseOperationEvent}.
+ * Base for events which denote database operations.
+ *
+ * @see AbstractPreDatabaseOperationEvent
+ * @see AbstractPostDatabaseOperationEvent
*
* @author Gavin King
*
* @since 7
*/
public abstract class AbstractDatabaseOperationEvent extends AbstractEvent {
-
private final Object entity;
private final Object id;
private final EntityPersister persister;
@@ -30,7 +31,7 @@ public abstract class AbstractDatabaseOperationEvent extends AbstractEvent {
* @param persister The entity's persister.
*/
public AbstractDatabaseOperationEvent(
- EventSource source,
+ SharedSessionContractImplementor source,
Object entity,
Object id,
EntityPersister persister) {
@@ -42,8 +43,6 @@ public AbstractDatabaseOperationEvent(
/**
* Retrieves the entity involved in the database operation.
- *
- * @return The entity.
*/
public Object getEntity() {
return entity;
@@ -51,8 +50,6 @@ public Object getEntity() {
/**
* The id to be used in the database operation.
- *
- * @return The id.
*/
public Object getId() {
return id;
@@ -60,20 +57,8 @@ public Object getId() {
/**
* The persister for the entity.
- *
- * @return The entity persister.
*/
public EntityPersister getPersister() {
return persister;
}
-
- /**
- * The factory which owns the persister for the entity.
- *
- * @return The factory
- */
- @Override
- public SessionFactoryImplementor getFactory() {
- return persister.getFactory();
- }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractEvent.java
index 946cf88fd40e..c5235acb77fe 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractEvent.java
@@ -5,38 +5,28 @@
package org.hibernate.event.spi;
import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import java.io.Serializable;
/**
- * Defines a base class for {@link org.hibernate.Session}-generated events.
+ * Base class for events which are generated from a {@link org.hibernate.Session}
+ * or {@linkplain org.hibernate.StatelessSession}.
*
* @author Steve Ebersole
*/
public abstract class AbstractEvent implements Serializable {
+ protected final SharedSessionContractImplementor source;
- private final EventSource session;
-
- /**
- * Constructs an event from the given event session.
- *
- * @param source The session event source.
- */
- public AbstractEvent(EventSource source) {
- this.session = source;
+ public AbstractEvent(SharedSessionContractImplementor source) {
+ this.source = source;
}
- /**
- * Returns the session event source for this event. This is the underlying
- * session from which this event was generated.
- *
- * @return The session event source.
- */
- public final EventSource getSession() {
- return session;
+ public SharedSessionContractImplementor getSession() {
+ return source;
}
public SessionFactoryImplementor getFactory() {
- return session.getFactory();
+ return source.getFactory();
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractPostDatabaseOperationEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractPostDatabaseOperationEvent.java
index 5f491566424f..83be95da9c55 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractPostDatabaseOperationEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractPostDatabaseOperationEvent.java
@@ -4,6 +4,7 @@
*/
package org.hibernate.event.spi;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.persister.entity.EntityPersister;
/**
@@ -24,7 +25,7 @@ public abstract class AbstractPostDatabaseOperationEvent extends AbstractDatabas
* @param persister The entity's persister.
*/
public AbstractPostDatabaseOperationEvent(
- EventSource source,
+ SharedSessionContractImplementor source,
Object entity,
Object id,
EntityPersister persister) {
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractPreDatabaseOperationEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractPreDatabaseOperationEvent.java
index 5f9b8054d468..24577a5fb764 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractPreDatabaseOperationEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractPreDatabaseOperationEvent.java
@@ -4,6 +4,7 @@
*/
package org.hibernate.event.spi;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.persister.entity.EntityPersister;
/**
@@ -22,7 +23,7 @@ public abstract class AbstractPreDatabaseOperationEvent extends AbstractDatabase
* @param persister The entity's persister.
*/
public AbstractPreDatabaseOperationEvent(
- EventSource source,
+ SharedSessionContractImplementor source,
Object entity,
Object id,
EntityPersister persister) {
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractSessionEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractSessionEvent.java
new file mode 100644
index 000000000000..2a826ec7a176
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractSessionEvent.java
@@ -0,0 +1,46 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.event.spi;
+
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+
+import java.io.Serializable;
+
+/**
+ * Base class for events which are generated from a {@linkplain org.hibernate.Session Session}
+ * ({@linkplain EventSource}).
+ *
+ * @author Steve Ebersole
+ */
+public abstract class AbstractSessionEvent implements Serializable {
+ protected final EventSource source;
+
+ /**
+ * Constructs an event from the given event session.
+ *
+ * @param source The session event source.
+ */
+ public AbstractSessionEvent(EventSource source) {
+ this.source = source;
+ }
+
+ /**
+ * Returns the session event source for this event. This is the underlying
+ * session from which this event was generated.
+ *
+ * @return The session event source.
+ */
+ public final EventSource getSession() {
+ return getEventSource();
+ }
+
+ public final EventSource getEventSource() {
+ return source.asEventSource();
+ }
+
+ public SessionFactoryImplementor getFactory() {
+ return source.getFactory();
+ }
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/ClearEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/ClearEvent.java
index 8f11899dad90..b10e916fbf95 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/ClearEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/ClearEvent.java
@@ -11,7 +11,7 @@
*
* @see org.hibernate.Session#clear
*/
-public class ClearEvent extends AbstractEvent {
+public class ClearEvent extends AbstractSessionEvent {
public ClearEvent(EventSource source) {
super( source );
}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/DeleteEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/DeleteEvent.java
index d6c8e786d48a..79131bfed46a 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/DeleteEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/DeleteEvent.java
@@ -14,7 +14,7 @@
*
* @see org.hibernate.Session#remove
*/
-public class DeleteEvent extends AbstractEvent {
+public class DeleteEvent extends AbstractSessionEvent {
private final Object object;
private String entityName;
private boolean cascadeDeleteEnabled;
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/DirtyCheckEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/DirtyCheckEvent.java
index 43f3bf9cb343..0e00edc50ab2 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/DirtyCheckEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/DirtyCheckEvent.java
@@ -12,7 +12,7 @@
*
* @see org.hibernate.Session#isDirty
*/
-public class DirtyCheckEvent extends AbstractEvent {
+public class DirtyCheckEvent extends AbstractSessionEvent {
private boolean dirty;
public DirtyCheckEvent(EventSource source) {
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/EvictEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/EvictEvent.java
index a30c375f33fd..2e221294369d 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/EvictEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/EvictEvent.java
@@ -13,7 +13,7 @@
* @see org.hibernate.Session#evict
* @see org.hibernate.Session#detach
*/
-public class EvictEvent extends AbstractEvent {
+public class EvictEvent extends AbstractSessionEvent {
private Object object;
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/FlushEntityEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/FlushEntityEvent.java
index 4668e0a68222..962821b38d94 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/FlushEntityEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/FlushEntityEvent.java
@@ -9,7 +9,7 @@
/**
* @author Gavin King
*/
-public class FlushEntityEvent extends AbstractEvent {
+public class FlushEntityEvent extends AbstractSessionEvent {
private Object entity;
private Object[] propertyValues;
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/FlushEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/FlushEvent.java
index bfcbb9be0558..76405ff71a33 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/FlushEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/FlushEvent.java
@@ -11,7 +11,7 @@
*
* @see org.hibernate.Session#flush
*/
-public class FlushEvent extends AbstractEvent {
+public class FlushEvent extends AbstractSessionEvent {
private int numberOfEntitiesProcessed;
private int numberOfCollectionsProcessed;
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/LoadEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/LoadEvent.java
index b7fb598e141e..e85ba703c64a 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/LoadEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/LoadEvent.java
@@ -13,7 +13,7 @@
*
* @author Steve Ebersole
*/
-public class LoadEvent extends AbstractEvent {
+public class LoadEvent extends AbstractSessionEvent {
private Object entityId;
private String entityClassName;
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/LockEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/LockEvent.java
index 00cd6211e09a..82c59955c8e4 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/LockEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/LockEvent.java
@@ -16,7 +16,7 @@
*
* @see org.hibernate.Session#lock
*/
-public class LockEvent extends AbstractEvent {
+public class LockEvent extends AbstractSessionEvent {
public static final String ILLEGAL_SKIP_LOCKED = "Skip-locked is not valid option for #lock";
private Object object;
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/MergeEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/MergeEvent.java
index b4b533335e57..85842dba2aa9 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/MergeEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/MergeEvent.java
@@ -11,7 +11,7 @@
*
* @see org.hibernate.Session#merge
*/
-public class MergeEvent extends AbstractEvent {
+public class MergeEvent extends AbstractSessionEvent {
private Object original;
private Object requestedId;
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/PersistEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/PersistEvent.java
index f7ca2c43e588..529ec492cda9 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/PersistEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/PersistEvent.java
@@ -11,7 +11,7 @@
*
* @see org.hibernate.Session#persist
*/
-public class PersistEvent extends AbstractEvent {
+public class PersistEvent extends AbstractSessionEvent {
private Object object;
private String entityName;
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/PostDeleteEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/PostDeleteEvent.java
index b254f048013a..adc9a0ddd3c6 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/PostDeleteEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/PostDeleteEvent.java
@@ -4,6 +4,7 @@
*/
package org.hibernate.event.spi;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.persister.entity.EntityPersister;
/**
@@ -19,7 +20,7 @@ public PostDeleteEvent(
Object id,
Object[] deletedState,
EntityPersister persister,
- EventSource source) {
+ SharedSessionContractImplementor source) {
super( source, entity, id, persister );
this.deletedState = deletedState;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/PostInsertEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/PostInsertEvent.java
index e6315c1e5894..8515f2afebf4 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/PostInsertEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/PostInsertEvent.java
@@ -4,6 +4,7 @@
*/
package org.hibernate.event.spi;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.persister.entity.EntityPersister;
/**
@@ -19,7 +20,7 @@ public PostInsertEvent(
Object id,
Object[] state,
EntityPersister persister,
- EventSource source) {
+ SharedSessionContractImplementor source) {
super( source, entity, id, persister );
this.state = state;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/PostLoadEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/PostLoadEvent.java
index 5c8f162352a9..688302e5b4f3 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/PostLoadEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/PostLoadEvent.java
@@ -11,7 +11,7 @@
*
* @author Kabir Khan, Gavin King
*/
-public class PostLoadEvent extends AbstractEvent {
+public class PostLoadEvent extends AbstractSessionEvent {
private Object entity;
private Object id;
private EntityPersister persister;
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/PostUpdateEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/PostUpdateEvent.java
index 78783bf134b5..2d5c36b1ea47 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/PostUpdateEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/PostUpdateEvent.java
@@ -4,6 +4,7 @@
*/
package org.hibernate.event.spi;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.persister.entity.EntityPersister;
/**
@@ -24,7 +25,7 @@ public PostUpdateEvent(
Object[] oldState,
int[] dirtyProperties,
EntityPersister persister,
- EventSource source) {
+ SharedSessionContractImplementor source) {
super( source, entity, id, persister );
this.state = state;
this.oldState = oldState;
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/PostUpsertEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/PostUpsertEvent.java
index e7e39991963c..665356d50a6f 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/PostUpsertEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/PostUpsertEvent.java
@@ -4,6 +4,7 @@
*/
package org.hibernate.event.spi;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.persister.entity.EntityPersister;
/**
@@ -22,7 +23,7 @@ public PostUpsertEvent(
Object[] state,
int[] dirtyProperties,
EntityPersister persister,
- EventSource source) {
+ SharedSessionContractImplementor source) {
super( source, entity, id, persister );
this.state = state;
this.dirtyProperties = dirtyProperties;
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/PreDeleteEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/PreDeleteEvent.java
index a8ebbdd1e881..1f2ede9cc784 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/PreDeleteEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/PreDeleteEvent.java
@@ -4,6 +4,7 @@
*/
package org.hibernate.event.spi;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.persister.entity.EntityPersister;
@@ -31,7 +32,7 @@ public PreDeleteEvent(
Object id,
Object[] deletedState,
EntityPersister persister,
- EventSource source) {
+ SharedSessionContractImplementor source) {
super( source, entity, id, persister );
this.deletedState = deletedState;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/PreInsertEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/PreInsertEvent.java
index 9c565f87d8da..b98887cce653 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/PreInsertEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/PreInsertEvent.java
@@ -4,6 +4,7 @@
*/
package org.hibernate.event.spi;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.persister.entity.EntityPersister;
/**
@@ -29,7 +30,7 @@ public PreInsertEvent(
Object id,
Object[] state,
EntityPersister persister,
- EventSource source) {
+ SharedSessionContractImplementor source) {
super( source, entity, id, persister );
this.state = state;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/PreLoadEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/PreLoadEvent.java
index dbf45d920591..2c5e0a538d4c 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/PreLoadEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/PreLoadEvent.java
@@ -11,7 +11,7 @@
*
* @author Gavin King
*/
-public class PreLoadEvent extends AbstractEvent {
+public class PreLoadEvent extends AbstractSessionEvent {
private Object entity;
private Object[] state;
private Object id;
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/PreUpdateEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/PreUpdateEvent.java
index dbfb1ef9fa43..ee1ced216738 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/PreUpdateEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/PreUpdateEvent.java
@@ -4,6 +4,7 @@
*/
package org.hibernate.event.spi;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.persister.entity.EntityPersister;
/**
@@ -33,7 +34,7 @@ public PreUpdateEvent(
Object[] state,
Object[] oldState,
EntityPersister persister,
- EventSource source) {
+ SharedSessionContractImplementor source) {
super( source, entity, id, persister );
this.state = state;
this.oldState = oldState;
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/PreUpsertEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/PreUpsertEvent.java
index 02e04e80287d..34881b88adb1 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/PreUpsertEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/PreUpsertEvent.java
@@ -4,6 +4,7 @@
*/
package org.hibernate.event.spi;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.persister.entity.EntityPersister;
/**
@@ -28,7 +29,7 @@ public PreUpsertEvent(
Object id,
Object[] state,
EntityPersister persister,
- EventSource source) {
+ SharedSessionContractImplementor source) {
super( source, entity, id, persister );
this.state = state;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/RefreshEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/RefreshEvent.java
index f542966754e5..94ce4fd22e99 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/RefreshEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/RefreshEvent.java
@@ -16,7 +16,7 @@
*
* @see org.hibernate.Session#refresh
*/
-public class RefreshEvent extends AbstractEvent {
+public class RefreshEvent extends AbstractSessionEvent {
private final Object object;
private String entityName;
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/ReplicateEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/ReplicateEvent.java
index 8e6130a7852a..b3ff5bcccd79 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/ReplicateEvent.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/ReplicateEvent.java
@@ -13,7 +13,7 @@
*
* @see org.hibernate.Session#replicate
*/
-public class ReplicateEvent extends AbstractEvent {
+public class ReplicateEvent extends AbstractSessionEvent {
private Object object;
private ReplicationMode replicationMode;
private String entityName;
diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/package-info.java b/hibernate-core/src/main/java/org/hibernate/event/spi/package-info.java
index 4ab31f4aa15c..fa68fbf1d6e6 100644
--- a/hibernate-core/src/main/java/org/hibernate/event/spi/package-info.java
+++ b/hibernate-core/src/main/java/org/hibernate/event/spi/package-info.java
@@ -7,7 +7,7 @@
* Defines the event types and event listener interfaces for
* events produced by the stateful {@link org.hibernate.Session}.
*
- * An {@linkplain org.hibernate.event.spi.AbstractEvent event}
+ * An {@linkplain org.hibernate.event.spi.AbstractSessionEvent event}
* represents a request by the session API for some work to be
* performed, and an event listener must respond to the event and
* do that work, usually by scheduling some sort of
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java
index ac6a92a7cfa6..18f743a85352 100644
--- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java
+++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java
@@ -20,6 +20,7 @@
import org.hibernate.LockMode;
import org.hibernate.SessionEventListener;
import org.hibernate.SessionException;
+import org.hibernate.SharedStatelessSessionBuilder;
import org.hibernate.Transaction;
import org.hibernate.UnknownEntityTypeException;
import org.hibernate.binder.internal.TenantIdBinder;
@@ -27,6 +28,9 @@
import org.hibernate.bytecode.enhance.spi.interceptor.SessionAssociationMarkers;
import org.hibernate.cache.spi.CacheTransactionSynchronization;
import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.creation.internal.SessionCreationOptions;
+import org.hibernate.engine.creation.internal.SharedSessionCreationOptions;
+import org.hibernate.engine.creation.internal.SharedStatelessSessionBuilderImpl;
import org.hibernate.engine.internal.SessionEventListenerManagerImpl;
import org.hibernate.engine.jdbc.LobCreator;
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
@@ -232,6 +236,11 @@ final SessionFactoryOptions getSessionFactoryOptions() {
return factoryOptions;
}
+ @Override
+ public SharedStatelessSessionBuilder statelessWithOptions() {
+ return new SharedStatelessSessionBuilderImpl( this );
+ }
+
private static boolean isTransactionCoordinatorShared(SessionCreationOptions options) {
return options instanceof SharedSessionCreationOptions sharedSessionCreationOptions
&& sharedSessionCreationOptions.isTransactionCoordinatorShared();
@@ -676,7 +685,7 @@ protected void delayedAfterCompletion() {
}
}
- protected Transaction getCurrentTransaction() {
+ public Transaction getCurrentTransaction() {
return currentHibernateTransaction;
}
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/CommonSharedSessionCreationOptions.java b/hibernate-core/src/main/java/org/hibernate/internal/CommonSharedSessionCreationOptions.java
new file mode 100644
index 000000000000..db405a783090
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/internal/CommonSharedSessionCreationOptions.java
@@ -0,0 +1,36 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.internal;
+
+import org.hibernate.CacheMode;
+import org.hibernate.Interceptor;
+import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
+import org.hibernate.resource.jdbc.spi.StatementInspector;
+import org.hibernate.resource.transaction.spi.TransactionCoordinator;
+
+/**
+ * Creation options for shared {@linkplain org.hibernate.engine.spi.SessionImplementor stateful}
+ * and {@linkplain org.hibernate.engine.spi.StatelessSessionImplementor stateless} sessions.
+ *
+ * @implNote At the moment this is only used in the creation of {@linkplain org.hibernate.engine.spi.StatelessSessionImplementor stateless} sessions.
+ *
+ * @author Steve Ebersole
+ */
+public interface CommonSharedSessionCreationOptions {
+
+ Interceptor getInterceptor();
+
+ StatementInspector getStatementInspector();
+
+ Object getTenantIdentifierValue();
+
+ boolean isReadOnly();
+
+ CacheMode getInitialCacheMode();
+
+ boolean isTransactionCoordinatorShared();
+ TransactionCoordinator getTransactionCoordinator();
+ JdbcCoordinator getJdbcCoordinator();
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/OptimisticLockHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/OptimisticLockHelper.java
index 0f978e279b08..fc3e459db815 100644
--- a/hibernate-core/src/main/java/org/hibernate/internal/OptimisticLockHelper.java
+++ b/hibernate-core/src/main/java/org/hibernate/internal/OptimisticLockHelper.java
@@ -53,7 +53,7 @@ public static void forceVersionIncrement(Object object, EntityEntry entry, Share
persister,
session
);
- session.registerProcess( new CacheCleanupProcess(
+ session.getTransactionCompletionCallbacks().registerCallback( new CacheCleanupProcess(
cacheKey,
persister,
previousVersion,
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java
index 697d9cf1fa08..a4a818008ca1 100644
--- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java
@@ -17,26 +17,19 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;
-import java.util.function.UnaryOperator;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import jakarta.persistence.TypedQuery;
-import org.hibernate.CacheMode;
-import org.hibernate.ConnectionAcquisitionMode;
-import org.hibernate.ConnectionReleaseMode;
import org.hibernate.CustomEntityDirtinessStrategy;
import org.hibernate.EntityNameResolver;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.Session;
-import org.hibernate.SessionBuilder;
-import org.hibernate.SessionEventListener;
import org.hibernate.SessionFactory;
import org.hibernate.SessionFactoryObserver;
import org.hibernate.StatelessSession;
@@ -59,13 +52,15 @@
import org.hibernate.context.spi.CurrentSessionContext;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.creation.internal.SessionBuilderImpl;
+import org.hibernate.engine.creation.internal.StatelessSessionBuilderImpl;
+import org.hibernate.engine.creation.spi.SessionBuilderImplementor;
import org.hibernate.engine.jdbc.batch.spi.BatchBuilder;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.profile.FetchProfile;
import org.hibernate.engine.spi.FilterDefinition;
-import org.hibernate.engine.spi.SessionBuilderImplementor;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
@@ -81,7 +76,6 @@
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.integrator.spi.IntegratorService;
-import org.hibernate.jpa.internal.ExceptionMapperLegacyJpaImpl;
import org.hibernate.jpa.internal.PersistenceUnitUtilImpl;
import org.hibernate.mapping.GeneratorSettings;
import org.hibernate.mapping.RootClass;
@@ -105,9 +99,6 @@
import org.hibernate.relational.SchemaManager;
import org.hibernate.relational.internal.SchemaManagerImpl;
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
-import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
-import org.hibernate.resource.jdbc.spi.StatementInspector;
-import org.hibernate.resource.transaction.backend.jta.internal.synchronization.ExceptionMapper;
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.spi.ServiceRegistryImplementor;
@@ -120,8 +111,6 @@
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.spi.TypeConfiguration;
-import org.jboss.logging.Logger;
-
import jakarta.persistence.EntityGraph;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceException;
@@ -132,7 +121,6 @@
import jakarta.persistence.TypedQueryReference;
import static jakarta.persistence.SynchronizationType.SYNCHRONIZED;
-import static java.util.Collections.addAll;
import static java.util.Collections.emptySet;
import static java.util.Collections.unmodifiableSet;
import static org.hibernate.cfg.AvailableSettings.CURRENT_SESSION_CONTEXT_CLASS;
@@ -199,8 +187,8 @@ public class SessionFactoryImpl implements SessionFactoryImplementor {
private final transient EventListenerGroups eventListenerGroups;
private final transient WrapperOptions wrapperOptions;
- private final transient SessionBuilderImpl defaultSessionOpenOptions;
- private final transient SessionBuilderImpl temporarySessionOpenOptions;
+ private final transient SessionBuilderImplementor defaultSessionOpenOptions;
+ private final transient SessionBuilderImplementor temporarySessionOpenOptions;
private final transient StatelessSessionBuilder defaultStatelessOptions;
private final transient EntityNameResolver entityNameResolver;
@@ -456,13 +444,13 @@ private void disintegrate(Exception startupException, IntegratorObserver integra
}
- private SessionBuilderImpl createDefaultSessionOpenOptionsIfPossible() {
+ private SessionBuilderImplementor createDefaultSessionOpenOptionsIfPossible() {
final var tenantIdResolver = getCurrentTenantIdentifierResolver();
// Don't store a default SessionBuilder when a CurrentTenantIdentifierResolver is provided
return tenantIdResolver == null ? withOptions() : null;
}
- private SessionBuilderImpl buildTemporarySessionOpenOptions() {
+ private SessionBuilderImplementor buildTemporarySessionOpenOptions() {
return withOptions()
.autoClose( false )
.flushMode( FlushMode.MANUAL )
@@ -535,7 +523,7 @@ public SessionImplementor openSession() {
}
@Override
- public SessionImpl openTemporarySession() {
+ public SessionImplementor openTemporarySession() {
// The temporarySessionOpenOptions can't be used in some cases;
// for example when using a TenantIdentifierResolver.
return temporarySessionOpenOptions != null
@@ -552,7 +540,7 @@ public Session getCurrentSession() {
}
@Override
- public SessionBuilderImpl withOptions() {
+ public SessionBuilderImplementor withOptions() {
return new SessionBuilderImpl( this );
}
@@ -1104,459 +1092,13 @@ public static Interceptor configuredInterceptor(Interceptor interceptor, boolean
return null;
}
- private Object resolveTenantIdentifier() {
+ public Object resolveTenantIdentifier() {
final var resolver = getCurrentTenantIdentifierResolver();
return resolver != null
? resolver.resolveCurrentTenantIdentifier()
: null;
}
- public static class SessionBuilderImpl implements SessionBuilderImplementor, SessionCreationOptions {
- private static final Logger log = CoreLogging.logger( SessionBuilderImpl.class );
-
- private final SessionFactoryImpl sessionFactory;
- private Interceptor interceptor;
- private StatementInspector statementInspector;
- private Connection connection;
- private PhysicalConnectionHandlingMode connectionHandlingMode;
- private boolean autoJoinTransactions = true;
- private FlushMode flushMode;
- private boolean autoClose;
- private boolean autoClear;
- private Object tenantIdentifier;
- private boolean readOnly;
- private CacheMode cacheMode;
- private boolean identifierRollback;
- private TimeZone jdbcTimeZone;
- private boolean explicitNoInterceptor;
- private final int defaultBatchFetchSize;
- private final boolean subselectFetchEnabled;
-
- // Lazy: defaults can be built by invoking the builder in fastSessionServices.defaultSessionEventListeners
- // (Need a fresh build for each Session as the listener instances can't be reused across sessions)
- // Only initialize of the builder is overriding the default.
- private List listeners;
-
- //todo : expose setting
- private final SessionOwnerBehavior sessionOwnerBehavior = SessionOwnerBehavior.LEGACY_NATIVE;
-
- public SessionBuilderImpl(SessionFactoryImpl sessionFactory) {
- this.sessionFactory = sessionFactory;
-
- // set up default builder values...
- final var options = sessionFactory.getSessionFactoryOptions();
- statementInspector = options.getStatementInspector();
- connectionHandlingMode = options.getPhysicalConnectionHandlingMode();
- autoClose = options.isAutoCloseSessionEnabled();
- defaultBatchFetchSize = options.getDefaultBatchFetchSize();
- subselectFetchEnabled = options.isSubselectFetchEnabled();
- identifierRollback = options.isIdentifierRollbackEnabled();
- cacheMode = options.getInitialSessionCacheMode();
-
- tenantIdentifier = sessionFactory.resolveTenantIdentifier();
- jdbcTimeZone = options.getJdbcTimeZone();
- }
-
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // SessionCreationOptions
-
- @Override
- public ExceptionMapper getExceptionMapper() {
- return sessionOwnerBehavior == SessionOwnerBehavior.LEGACY_JPA
- ? ExceptionMapperLegacyJpaImpl.INSTANCE
- : null;
- }
-
- @Override
- public boolean shouldAutoJoinTransactions() {
- return autoJoinTransactions;
- }
-
- @Override
- public FlushMode getInitialSessionFlushMode() {
- return flushMode;
- }
-
- @Override
- public boolean isSubselectFetchEnabled() {
- return subselectFetchEnabled;
- }
-
- @Override
- public int getDefaultBatchFetchSize() {
- return defaultBatchFetchSize;
- }
-
- @Override
- public boolean shouldAutoClose() {
- return autoClose;
- }
-
- @Override
- public boolean shouldAutoClear() {
- return autoClear;
- }
-
- @Override
- public Connection getConnection() {
- return connection;
- }
-
- @Override
- public Interceptor getInterceptor() {
- return configuredInterceptor( interceptor, explicitNoInterceptor, sessionFactory.getSessionFactoryOptions() );
- }
-
- @Override
- public StatementInspector getStatementInspector() {
- return statementInspector;
- }
-
- @Override
- public PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode() {
- return connectionHandlingMode;
- }
-
- @Override
- public String getTenantIdentifier() {
- return tenantIdentifier != null
- ? sessionFactory.getTenantIdentifierJavaType().toString( tenantIdentifier )
- : null;
- }
-
- @Override
- public Object getTenantIdentifierValue() {
- return tenantIdentifier;
- }
-
- @Override
- public boolean isReadOnly() {
- return readOnly;
- }
-
- @Override
- public CacheMode getInitialCacheMode() {
- return cacheMode;
- }
-
- @Override
- public boolean isIdentifierRollbackEnabled() {
- return identifierRollback;
- }
-
- @Override
- public TimeZone getJdbcTimeZone() {
- return jdbcTimeZone;
- }
-
- @Override
- public List getCustomSessionEventListener() {
- return listeners;
- }
-
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // SessionBuilder
-
- @Override
- public SessionImpl openSession() {
- log.tracef( "Opening Hibernate Session. tenant=%s", tenantIdentifier );
- return new SessionImpl( sessionFactory, this );
- }
-
- @Override
- public SessionBuilderImpl interceptor(Interceptor interceptor) {
- this.interceptor = interceptor;
- this.explicitNoInterceptor = false;
- return this;
- }
-
- @Override
- public SessionBuilderImpl noInterceptor() {
- this.interceptor = EmptyInterceptor.INSTANCE;
- this.explicitNoInterceptor = true;
- return this;
- }
-
- @Override @Deprecated
- public SessionBuilderImpl statementInspector(StatementInspector statementInspector) {
- this.statementInspector = statementInspector;
- return this;
- }
-
- @Override
- public SessionBuilderImpl statementInspector(UnaryOperator operator) {
- this.statementInspector = operator::apply;
- return this;
- }
-
- @Override
- public SessionBuilderImpl connection(Connection connection) {
- this.connection = connection;
- return this;
- }
-
- @Override @Deprecated
- public SessionBuilderImpl connectionHandlingMode(PhysicalConnectionHandlingMode connectionHandlingMode) {
- this.connectionHandlingMode = connectionHandlingMode;
- return this;
- }
-
- @Override
- public SessionBuilderImpl connectionHandling(ConnectionAcquisitionMode acquisitionMode, ConnectionReleaseMode releaseMode) {
- this.connectionHandlingMode = PhysicalConnectionHandlingMode.interpret( acquisitionMode, releaseMode);
- return this;
- }
-
- @Override
- public SessionBuilderImpl autoJoinTransactions(boolean autoJoinTransactions) {
- this.autoJoinTransactions = autoJoinTransactions;
- return this;
- }
-
- @Override
- public SessionBuilderImpl autoClose(boolean autoClose) {
- this.autoClose = autoClose;
- return this;
- }
-
- @Override
- public SessionBuilderImpl autoClear(boolean autoClear) {
- this.autoClear = autoClear;
- return this;
- }
-
- @Override
- public SessionBuilderImpl flushMode(FlushMode flushMode) {
- this.flushMode = flushMode;
- return this;
- }
-
- @Override @Deprecated(forRemoval = true)
- public SessionBuilderImpl tenantIdentifier(String tenantIdentifier) {
- this.tenantIdentifier = tenantIdentifier;
- return this;
- }
-
- @Override
- public SessionBuilderImpl tenantIdentifier(Object tenantIdentifier) {
- this.tenantIdentifier = tenantIdentifier;
- return this;
- }
-
- @Override
- public SessionBuilderImpl readOnly(boolean readOnly) {
- this.readOnly = readOnly;
- return this;
- }
-
- @Override
- public SessionBuilder initialCacheMode(CacheMode cacheMode) {
- this.cacheMode = cacheMode;
- return this;
- }
-
- @Override
- public SessionBuilderImpl identifierRollback(boolean identifierRollback) {
- this.identifierRollback = identifierRollback;
- return this;
- }
-
- @Override
- public SessionBuilderImpl eventListeners(SessionEventListener... listeners) {
- if ( this.listeners == null ) {
- final var baselineListeners =
- sessionFactory.getSessionFactoryOptions().buildSessionEventListeners();
- this.listeners = new ArrayList<>( baselineListeners.length + listeners.length );
- addAll( this.listeners, baselineListeners );
- }
- addAll( this.listeners, listeners );
- return this;
- }
-
- @Override
- public SessionBuilderImpl clearEventListeners() {
- if ( listeners == null ) {
- //Needs to initialize explicitly to an empty list as otherwise "null" implies the default listeners will be applied
- listeners = new ArrayList<>( 3 );
- }
- else {
- listeners.clear();
- }
- return this;
- }
-
- @Override
- public SessionBuilderImpl jdbcTimeZone(TimeZone timeZone) {
- jdbcTimeZone = timeZone;
- return this;
- }
- }
-
- public static class StatelessSessionBuilderImpl implements StatelessSessionBuilder, SessionCreationOptions {
- private final SessionFactoryImpl sessionFactory;
- private StatementInspector statementInspector;
- private Connection connection;
- private PhysicalConnectionHandlingMode connectionHandlingMode;
- private Object tenantIdentifier;
- private boolean readOnly;
- private CacheMode cacheMode;
-
- public StatelessSessionBuilderImpl(SessionFactoryImpl sessionFactory) {
- this.sessionFactory = sessionFactory;
- final var options = sessionFactory.getSessionFactoryOptions();
- statementInspector = options.getStatementInspector();
- cacheMode = options.getInitialSessionCacheMode();
- tenantIdentifier = sessionFactory.resolveTenantIdentifier();
- connectionHandlingMode = options.getPhysicalConnectionHandlingMode();
- }
-
- @Override
- public StatelessSession openStatelessSession() {
- return new StatelessSessionImpl( sessionFactory, this );
- }
-
- @Override
- public StatelessSessionBuilder connection(Connection connection) {
- this.connection = connection;
- return this;
- }
-
- @Override
- public StatelessSessionBuilder connectionHandling(ConnectionAcquisitionMode acquisitionMode, ConnectionReleaseMode releaseMode) {
- this.connectionHandlingMode = PhysicalConnectionHandlingMode.interpret( acquisitionMode, releaseMode);
- return this;
- }
-
- @Override @Deprecated
- public StatelessSessionBuilder tenantIdentifier(String tenantIdentifier) {
- this.tenantIdentifier = tenantIdentifier;
- return this;
- }
-
- @Override
- public StatelessSessionBuilder tenantIdentifier(Object tenantIdentifier) {
- this.tenantIdentifier = tenantIdentifier;
- return this;
- }
-
- @Override
- public StatelessSessionBuilder readOnly(boolean readOnly) {
- this.readOnly = readOnly;
- return this;
- }
-
- @Override
- public StatelessSessionBuilder initialCacheMode(CacheMode cacheMode) {
- this.cacheMode = cacheMode;
- return this;
- }
-
- @Override @Deprecated
- public StatelessSessionBuilder statementInspector(StatementInspector statementInspector) {
- this.statementInspector = statementInspector;
- return this;
- }
-
- @Override
- public StatelessSessionBuilder statementInspector(UnaryOperator operator) {
- this.statementInspector = operator::apply;
- return this;
- }
-
- @Override
- public boolean shouldAutoJoinTransactions() {
- return true;
- }
-
- @Override
- public FlushMode getInitialSessionFlushMode() {
- return FlushMode.ALWAYS;
- }
-
- @Override
- public boolean isSubselectFetchEnabled() {
- return false;
- }
-
- @Override
- public int getDefaultBatchFetchSize() {
- return -1;
- }
-
- @Override
- public boolean shouldAutoClose() {
- return false;
- }
-
- @Override
- public boolean shouldAutoClear() {
- return false;
- }
-
- @Override
- public Connection getConnection() {
- return connection;
- }
-
- @Override
- public Interceptor getInterceptor() {
- return configuredInterceptor( EmptyInterceptor.INSTANCE, false,
- sessionFactory.getSessionFactoryOptions() );
- }
-
- @Override
- public boolean isIdentifierRollbackEnabled() {
- // identifier rollback not yet implemented for StatelessSessions
- return false;
- }
-
- @Override
- public StatementInspector getStatementInspector() {
- return statementInspector;
- }
-
- @Override
- public PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode() {
- return connectionHandlingMode;
- }
-
- @Override
- public String getTenantIdentifier() {
- return tenantIdentifier == null ? null
- : sessionFactory.getTenantIdentifierJavaType().toString( tenantIdentifier );
- }
-
- @Override
- public boolean isReadOnly() {
- return readOnly;
- }
-
- @Override
- public CacheMode getInitialCacheMode() {
- return cacheMode;
- }
-
- @Override
- public Object getTenantIdentifierValue() {
- return tenantIdentifier;
- }
-
- @Override
- public TimeZone getJdbcTimeZone() {
- return sessionFactory.getSessionFactoryOptions().getJdbcTimeZone();
- }
-
- @Override
- public List getCustomSessionEventListener() {
- return null;
- }
-
- @Override
- public ExceptionMapper getExceptionMapper() {
- return null;
- }
- }
-
@Override
public CustomEntityDirtinessStrategy getCustomEntityDirtinessStrategy() {
return getSessionFactoryOptions().getCustomEntityDirtinessStrategy();
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java
index 08a3233577e3..65604023df58 100644
--- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java
@@ -23,13 +23,14 @@
import jakarta.persistence.metamodel.EntityType;
import jakarta.persistence.metamodel.Metamodel;
import org.hibernate.*;
-import org.hibernate.action.spi.AfterTransactionCompletionProcess;
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
import org.hibernate.collection.spi.PersistentCollection;
+import org.hibernate.engine.creation.internal.SessionCreationOptions;
+import org.hibernate.engine.creation.internal.SharedSessionBuilderImpl;
+import org.hibernate.engine.creation.internal.SharedSessionCreationOptions;
import org.hibernate.engine.internal.PersistenceContexts;
-import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
+import org.hibernate.engine.internal.TransactionCompletionCallbacksImpl;
import org.hibernate.engine.spi.ActionQueue;
-import org.hibernate.engine.spi.ActionQueue.TransactionCompletionProcesses;
import org.hibernate.engine.spi.EffectiveEntityGraph;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityHolder;
@@ -64,8 +65,6 @@
import org.hibernate.query.UnknownSqlResultSetMappingException;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.resource.jdbc.spi.JdbcSessionOwner;
-import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
-import org.hibernate.resource.jdbc.spi.StatementInspector;
import org.hibernate.resource.transaction.spi.TransactionCoordinator;
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
import org.hibernate.resource.transaction.spi.TransactionObserver;
@@ -79,15 +78,12 @@
import java.io.ObjectOutputStream;
import java.io.Serial;
import java.io.Serializable;
-import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.TimeZone;
-import java.util.function.UnaryOperator;
import static java.lang.Boolean.parseBoolean;
import static java.lang.Integer.parseInt;
@@ -239,9 +235,9 @@ public SessionImpl(SessionFactoryImpl factory, SessionCreationOptions options) {
private void setUpTransactionCompletionProcesses(SessionCreationOptions options) {
if ( options instanceof SharedSessionCreationOptions sharedOptions
&& sharedOptions.isTransactionCoordinatorShared() ) {
- final TransactionCompletionProcesses processes = sharedOptions.getTransactionCompletionProcesses();
- if ( processes != null ) {
- actionQueue.setTransactionCompletionProcesses( processes, true );
+ final TransactionCompletionCallbacksImpl callbacks = sharedOptions.getTransactionCompletionCallbacks();
+ if ( callbacks != null ) {
+ actionQueue.setTransactionCompletionCallbacks( callbacks, true );
}
}
}
@@ -1867,11 +1863,6 @@ public ActionQueue getActionQueue() {
return actionQueue;
}
- @Override
- public void registerProcess(AfterTransactionCompletionProcess process) {
- getActionQueue().registerProcess( process );
- }
-
@Override
public PersistenceContext getPersistenceContext() {
checkOpenOrWaitingForAutoClose();
@@ -2033,240 +2024,6 @@ public void afterTransactionCompletion(boolean successful, boolean delayed) {
super.afterTransactionCompletion( successful, delayed );
}
- private static class SharedSessionBuilderImpl
- extends SessionFactoryImpl.SessionBuilderImpl
- implements SharedSessionBuilder, SharedSessionCreationOptions {
- private final SessionImpl session;
- private boolean shareTransactionContext;
- private boolean tenantIdChanged;
- private boolean readOnlyChanged;
-
- private SharedSessionBuilderImpl(SessionImpl session) {
- super( (SessionFactoryImpl) session.getFactory() );
- this.session = session;
- super.tenantIdentifier( session.getTenantIdentifierValue() );
- super.identifierRollback( session.isIdentifierRollbackEnabled() );
- }
-
- @Override
- public SessionImpl openSession() {
- if ( session.getSessionFactoryOptions().isMultiTenancyEnabled() ) {
- if ( shareTransactionContext ) {
- if ( tenantIdChanged ) {
- throw new SessionException(
- "Cannot redefine the tenant identifier on a child session if the connection is reused" );
- }
- if ( readOnlyChanged ) {
- throw new SessionException(
- "Cannot redefine the read-only mode on a child session if the connection is reused" );
- }
- }
- }
- return super.openSession();
- }
-
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // SharedSessionBuilder
-
-
- @Override @Deprecated(forRemoval = true)
- public SharedSessionBuilderImpl tenantIdentifier(String tenantIdentifier) {
- super.tenantIdentifier( tenantIdentifier );
- tenantIdChanged = true;
- return this;
- }
-
- @Override
- public SharedSessionBuilderImpl tenantIdentifier(Object tenantIdentifier) {
- super.tenantIdentifier( tenantIdentifier );
- tenantIdChanged = true;
- return this;
- }
-
- @Override
- public SharedSessionBuilderImpl readOnly(boolean readOnly) {
- super.readOnly( readOnly );
- readOnlyChanged = true;
- return this;
- }
-
- @Override
- public SharedSessionBuilderImpl initialCacheMode(CacheMode cacheMode) {
- super.initialCacheMode( cacheMode );
- return this;
- }
-
- @Override
- public SharedSessionBuilderImpl interceptor() {
- super.interceptor( session.getInterceptor() );
- return this;
- }
-
- @Override
- public SharedSessionBuilderImpl interceptor(Interceptor interceptor) {
- super.interceptor( interceptor );
- return this;
- }
-
- @Override
- public SharedSessionBuilderImpl noInterceptor() {
- super.noInterceptor();
- return this;
- }
-
- @Override
- public SharedSessionBuilderImpl connection() {
- this.shareTransactionContext = true;
- return this;
- }
-
- @Override
- public SharedSessionBuilderImpl connection(Connection connection) {
- super.connection( connection );
- return this;
- }
-
- private PhysicalConnectionHandlingMode getConnectionHandlingMode() {
- return session.getJdbcCoordinator().getLogicalConnection().getConnectionHandlingMode();
- }
-
- @Override
- @Deprecated(since = "6.0")
- public SharedSessionBuilderImpl connectionReleaseMode() {
- final PhysicalConnectionHandlingMode handlingMode =
- PhysicalConnectionHandlingMode.interpret( ConnectionAcquisitionMode.AS_NEEDED,
- getConnectionHandlingMode().getReleaseMode() );
- connectionHandlingMode( handlingMode );
- return this;
- }
-
- @Override
- public SharedSessionBuilderImpl connectionHandlingMode() {
- connectionHandlingMode( getConnectionHandlingMode() );
- return this;
- }
-
- @Override
- public SharedSessionBuilderImpl autoJoinTransactions() {
- super.autoJoinTransactions( session.shouldAutoJoinTransaction() );
- return this;
- }
-
- @Override
- public SharedSessionBuilderImpl autoJoinTransactions(boolean autoJoinTransactions) {
- super.autoJoinTransactions( autoJoinTransactions );
- return this;
- }
-
- @Override
- public SharedSessionBuilderImpl autoClose(boolean autoClose) {
- super.autoClose( autoClose );
- return this;
- }
-
- @Override
- public SharedSessionBuilderImpl flushMode() {
- flushMode( session.getHibernateFlushMode() );
- return this;
- }
-
- @Override
- public SharedSessionBuilderImpl autoClose() {
- autoClose( session.isAutoCloseSessionEnabled() );
- return this;
- }
-
- @Override
- public SharedSessionBuilderImpl identifierRollback(boolean identifierRollback) {
- super.identifierRollback( identifierRollback );
- return this;
- }
-
- @Override
- public SharedSessionBuilderImpl jdbcTimeZone(TimeZone timeZone) {
- super.jdbcTimeZone(timeZone);
- return this;
- }
-
- @Override
- public SharedSessionBuilderImpl clearEventListeners() {
- super.clearEventListeners();
- return this;
- }
-
- @Override
- public SharedSessionBuilderImpl flushMode(FlushMode flushMode) {
- super.flushMode(flushMode);
- return this;
- }
-
- @Override
- public SharedSessionBuilderImpl autoClear(boolean autoClear) {
- super.autoClear(autoClear);
- return this;
- }
-
- @Override @Deprecated
- public SharedSessionBuilderImpl statementInspector(StatementInspector statementInspector) {
- super.statementInspector(statementInspector);
- return this;
- }
-
- @Override
- public SharedSessionBuilderImpl statementInspector(UnaryOperator operator) {
- super.statementInspector(operator);
- return this;
- }
-
- @Override @Deprecated
- public SharedSessionBuilderImpl connectionHandlingMode(PhysicalConnectionHandlingMode connectionHandlingMode) {
- super.connectionHandlingMode(connectionHandlingMode);
- return this;
- }
-
- @Override @Deprecated
- public SharedSessionBuilderImpl connectionHandling(ConnectionAcquisitionMode acquisitionMode, ConnectionReleaseMode releaseMode) {
- super.connectionHandling(acquisitionMode, releaseMode);
- return this;
- }
-
- @Override
- public SharedSessionBuilderImpl eventListeners(SessionEventListener... listeners) {
- super.eventListeners(listeners);
- return this;
- }
-
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // 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 Transaction getTransaction() {
- return shareTransactionContext ? session.getCurrentTransaction() : null;
- }
-
- @Override
- public TransactionCompletionProcesses getTransactionCompletionProcesses() {
- return shareTransactionContext
- ? session.getActionQueue().getTransactionCompletionProcesses()
- : null;
- }
- }
-
@Override
protected void addSharedSessionTransactionObserver(TransactionCoordinator transactionCoordinator) {
transactionObserver = new TransactionObserver() {
diff --git a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java
index bc0d513c842f..203783bf5356 100644
--- a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java
@@ -4,31 +4,34 @@
*/
package org.hibernate.internal;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-import java.util.function.BiConsumer;
-
+import jakarta.persistence.EntityGraph;
import jakarta.persistence.PersistenceException;
+import jakarta.transaction.SystemException;
import org.hibernate.AssertionFailure;
+import org.hibernate.CacheMode;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
+import org.hibernate.Interceptor;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
+import org.hibernate.SessionEventListener;
import org.hibernate.SessionException;
import org.hibernate.StatelessSession;
import org.hibernate.TransientObjectException;
import org.hibernate.UnresolvableObjectException;
-import org.hibernate.action.spi.AfterTransactionCompletionProcess;
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
-import org.hibernate.cache.CacheException;
import org.hibernate.cache.spi.access.SoftLock;
import org.hibernate.collection.spi.CollectionSemantics;
import org.hibernate.collection.spi.PersistentCollection;
+import org.hibernate.engine.creation.internal.SessionCreationOptions;
+import org.hibernate.engine.internal.TransactionCompletionCallbacksImpl;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.PersistenceContext;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
+import org.hibernate.engine.spi.StatelessSessionImplementor;
+import org.hibernate.engine.spi.TransactionCompletionCallbacks;
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
import org.hibernate.event.monitor.spi.DiagnosticEvent;
@@ -67,11 +70,16 @@
import org.hibernate.loader.internal.CacheLoadHelper;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
-
-import jakarta.persistence.EntityGraph;
-import jakarta.transaction.SystemException;
+import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
+import org.hibernate.resource.jdbc.spi.StatementInspector;
import org.hibernate.stat.spi.StatisticsImplementor;
+import java.sql.Connection;
+import java.util.List;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.function.BiConsumer;
+
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable;
import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable;
import static org.hibernate.engine.internal.PersistenceContexts.createPersistenceContext;
@@ -110,7 +118,7 @@
* @author Gavin King
* @author Steve Ebersole
*/
-public class StatelessSessionImpl extends AbstractSharedSessionContract implements StatelessSession {
+public class StatelessSessionImpl extends AbstractSharedSessionContract implements StatelessSessionImplementor {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( StatelessSessionImpl.class );
public static final MultiIdLoadOptions MULTI_ID_LOAD_OPTIONS = new MultiLoadOptions();
@@ -118,13 +126,33 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
private final LoadQueryInfluencers influencers;
private final PersistenceContext temporaryPersistenceContext;
private final boolean connectionProvided;
- private final List afterCompletions = new ArrayList<>();
+ private final TransactionCompletionCallbacksImpl transactionCompletionCallbacks;
private final EventListenerGroups eventListenerGroups;
public StatelessSessionImpl(SessionFactoryImpl factory, SessionCreationOptions options) {
super( factory, options );
connectionProvided = options.getConnection() != null;
+ transactionCompletionCallbacks = new TransactionCompletionCallbacksImpl( this );
+ temporaryPersistenceContext = createPersistenceContext( this );
+ influencers = new LoadQueryInfluencers( getFactory() );
+ eventListenerGroups = factory.getEventListenerGroups();
+ setUpMultitenancy( factory, influencers );
+ // a nonzero batch size forces use of write-behind
+ // therefore ignore the value of hibernate.jdbc.batch_size
+ setJdbcBatchSize( 0 );
+ }
+
+ /**
+ * Form used when creating a "shared" stateless session.
+ */
+ public StatelessSessionImpl(SessionFactoryImplementor factory, CommonSharedSessionCreationOptions options) {
+ super(
+ (SessionFactoryImpl) factory,
+ CommonSharedSessionCreationOptionsWrapper.wrapOptions( (SessionFactoryImpl) factory, options )
+ );
+ connectionProvided = false;
+ transactionCompletionCallbacks = new TransactionCompletionCallbacksImpl( this );
temporaryPersistenceContext = createPersistenceContext( this );
influencers = new LoadQueryInfluencers( getFactory() );
eventListenerGroups = factory.getEventListenerGroups();
@@ -551,12 +579,14 @@ protected Object idToUpsert(Object entity, EntityPersister persister) {
// Hibernate Reactive may need to call this
protected boolean firePreInsert(Object entity, Object id, Object[] state, EntityPersister persister) {
+ getFactory().getEventEngine().getCallbackRegistry().preCreate( entity );
+
if ( eventListenerGroups.eventListenerGroup_PRE_INSERT.isEmpty() ) {
return false;
}
else {
boolean veto = false;
- final var event = new PreInsertEvent( entity, id, state, persister, null );
+ final var event = new PreInsertEvent( entity, id, state, persister, this );
for ( var listener : eventListenerGroups.eventListenerGroup_PRE_INSERT.listeners() ) {
veto |= listener.onPreInsert( event );
}
@@ -566,12 +596,14 @@ protected boolean firePreInsert(Object entity, Object id, Object[] state, Entity
// Hibernate Reactive may need to call this
protected boolean firePreUpdate(Object entity, Object id, Object[] state, EntityPersister persister) {
+ getFactory().getEventEngine().getCallbackRegistry().preUpdate( entity );
+
if ( eventListenerGroups.eventListenerGroup_PRE_UPDATE.isEmpty() ) {
return false;
}
else {
boolean veto = false;
- final var event = new PreUpdateEvent( entity, id, state, null, persister, null );
+ final var event = new PreUpdateEvent( entity, id, state, null, persister, this );
for ( var listener : eventListenerGroups.eventListenerGroup_PRE_UPDATE.listeners() ) {
veto |= listener.onPreUpdate( event );
}
@@ -586,7 +618,7 @@ protected boolean firePreUpsert(Object entity, Object id, Object[] state, Entity
}
else {
boolean veto = false;
- final var event = new PreUpsertEvent( entity, id, state, persister, null );
+ final var event = new PreUpsertEvent( entity, id, state, persister, this );
for ( var listener : eventListenerGroups.eventListenerGroup_PRE_UPSERT.listeners() ) {
veto |= listener.onPreUpsert( event );
}
@@ -596,12 +628,14 @@ protected boolean firePreUpsert(Object entity, Object id, Object[] state, Entity
// Hibernate Reactive may need to call this
protected boolean firePreDelete(Object entity, Object id, EntityPersister persister) {
+ getFactory().getEventEngine().getCallbackRegistry().preRemove( entity );
+
if ( eventListenerGroups.eventListenerGroup_PRE_DELETE.isEmpty() ) {
return false;
}
else {
boolean veto = false;
- final var event = new PreDeleteEvent( entity, id, null, persister, null );
+ final var event = new PreDeleteEvent( entity, id, null, persister, this );
for ( var listener : eventListenerGroups.eventListenerGroup_PRE_DELETE.listeners() ) {
veto |= listener.onPreDelete( event );
}
@@ -612,28 +646,28 @@ protected boolean firePreDelete(Object entity, Object id, EntityPersister persis
// Hibernate Reactive may need to call this
protected void firePostInsert(Object entity, Object id, Object[] state, EntityPersister persister) {
eventListenerGroups.eventListenerGroup_POST_INSERT.fireLazyEventOnEachListener(
- () -> new PostInsertEvent( entity, id, state, persister, null ),
+ () -> new PostInsertEvent( entity, id, state, persister, this ),
PostInsertEventListener::onPostInsert );
}
// Hibernate Reactive may need to call this
protected void firePostUpdate(Object entity, Object id, Object[] state, EntityPersister persister) {
eventListenerGroups.eventListenerGroup_POST_UPDATE.fireLazyEventOnEachListener(
- () -> new PostUpdateEvent( entity, id, state, null, null, persister, null ),
+ () -> new PostUpdateEvent( entity, id, state, null, null, persister, this ),
PostUpdateEventListener::onPostUpdate );
}
// Hibernate Reactive may need to call this
protected void firePostUpsert(Object entity, Object id, Object[] state, EntityPersister persister) {
eventListenerGroups.eventListenerGroup_POST_UPSERT.fireLazyEventOnEachListener(
- () -> new PostUpsertEvent( entity, id, state, null, persister, null ),
+ () -> new PostUpsertEvent( entity, id, state, null, persister, this ),
PostUpsertEventListener::onPostUpsert );
}
// Hibernate Reactive may need to call this
protected void firePostDelete(Object entity, Object id, EntityPersister persister) {
eventListenerGroups.eventListenerGroup_POST_DELETE.fireLazyEventOnEachListener(
- () -> new PostDeleteEvent( entity, id, null, persister, null ),
+ () -> new PostDeleteEvent( entity, id, null, persister, this ),
PostDeleteEventListener::onPostDelete );
}
@@ -1301,40 +1335,30 @@ public void afterTransactionBegin() {
@Override
public void beforeTransactionCompletion() {
+ transactionCompletionCallbacks.beforeTransactionCompletion();
flushBeforeTransactionCompletion();
beforeTransactionCompletionEvents();
}
@Override
public void afterTransactionCompletion(boolean successful, boolean delayed) {
- processAfterCompletions( successful );
+ transactionCompletionCallbacks.afterTransactionCompletion( successful );
afterTransactionCompletionEvents( successful );
if ( shouldAutoClose() && !isClosed() ) {
managedClose();
}
}
- private void processAfterCompletions(boolean successful) {
- for ( AfterTransactionCompletionProcess completion: afterCompletions ) {
- try {
- completion.doAfterTransactionCompletion( successful, this );
- }
- catch (CacheException ce) {
- LOG.unableToReleaseCacheLock( ce );
- // continue loop
- }
- catch (Exception e) {
- throw new HibernateException( "Unable to perform afterTransactionCompletion callback: " + e.getMessage(), e );
- }
- }
- afterCompletions.clear();
- }
-
@Override
public boolean isTransactionInProgress() {
return connectionProvided || super.isTransactionInProgress();
}
+ @Override
+ public TransactionCompletionCallbacks getTransactionCompletionCallbacks() {
+ return transactionCompletionCallbacks;
+ }
+
@Override
public void flushBeforeTransactionCompletion() {
final boolean flush;
@@ -1369,7 +1393,9 @@ protected Object lockCacheItem(Object id, Object previousVersion, EntityPersiste
getTenantIdentifier()
);
final SoftLock lock = cache.lockItem( this, ck, previousVersion );
- afterCompletions.add( (success, session) -> cache.unlockItem( session, ck, lock ) );
+ transactionCompletionCallbacks.registerCallback( (success, session) -> {
+ cache.unlockItem( session, ck, lock );
+ } );
return ck;
}
else {
@@ -1393,7 +1419,9 @@ protected Object lockCacheItem(Object key, CollectionPersister persister) {
getTenantIdentifier()
);
final SoftLock lock = cache.lockItem( this, ck, null );
- afterCompletions.add( (success, session) -> cache.unlockItem( this, ck, lock ) );
+ transactionCompletionCallbacks.registerCallback( (success, session) -> {
+ cache.unlockItem( this, ck, lock );
+ } );
return ck;
}
else {
@@ -1407,11 +1435,6 @@ protected void removeCacheItem(Object ck, CollectionPersister persister) {
}
}
- @Override
- public void registerProcess(AfterTransactionCompletionProcess process) {
- afterCompletions.add( process );
- }
-
@Override
public void lock(String entityName, Object child, LockOptions lockOptions) {
final var persister = getEntityPersister( entityName, child );
@@ -1486,4 +1509,110 @@ public Integer getBatchSize() {
return null;
}
}
+
+ /**
+ * Wraps a CommonSharedSessionCreationOptions as a SessionCreationOptions to pass
+ * to AbstractSharedSessionContract during construction.
+ *
+ * @param factory The SessionFactory
+ * @param options The CommonSharedSessionCreationOptions being wrapped.
+ */
+ private record CommonSharedSessionCreationOptionsWrapper(
+ SessionFactoryImplementor factory,
+ CommonSharedSessionCreationOptions options)
+ implements SessionCreationOptions {
+
+ private static SessionCreationOptions wrapOptions(SessionFactoryImpl factory, CommonSharedSessionCreationOptions options) {
+ return new CommonSharedSessionCreationOptionsWrapper( factory, options );
+ }
+
+ @Override
+ public Interceptor getInterceptor() {
+ return options.getInterceptor();
+ }
+
+ @Override
+ public StatementInspector getStatementInspector() {
+ return options.getStatementInspector();
+ }
+
+ @Override
+ public Object getTenantIdentifierValue() {
+ return options.getTenantIdentifierValue();
+ }
+
+ @Override
+ public boolean isReadOnly() {
+ return options.isReadOnly();
+ }
+
+ @Override
+ public CacheMode getInitialCacheMode() {
+ return options.getInitialCacheMode();
+ }
+
+ @Override
+ public boolean shouldAutoJoinTransactions() {
+ return true;
+ }
+
+ @Override
+ public FlushMode getInitialSessionFlushMode() {
+ return FlushMode.ALWAYS;
+ }
+
+ @Override
+ public boolean isSubselectFetchEnabled() {
+ return false;
+ }
+
+ @Override
+ public int getDefaultBatchFetchSize() {
+ return -1;
+ }
+
+ @Override
+ public boolean shouldAutoClose() {
+ return false;
+ }
+
+ @Override
+ public boolean shouldAutoClear() {
+ return false;
+ }
+
+ @Override
+ public Connection getConnection() {
+ return null;
+ }
+
+ @Override
+ public boolean isIdentifierRollbackEnabled() {
+ // identifier rollback not yet implemented for StatelessSessions
+ return false;
+ }
+
+ @Override
+ public PhysicalConnectionHandlingMode getPhysicalConnectionHandlingMode() {
+ return factory.getSessionFactoryOptions().getPhysicalConnectionHandlingMode();
+ }
+
+ @Override
+ public String getTenantIdentifier() {
+ final Object tenantIdentifier = getTenantIdentifierValue();
+ return tenantIdentifier == null
+ ? null
+ : factory.getTenantIdentifierJavaType().toString( tenantIdentifier );
+ }
+
+ @Override
+ public TimeZone getJdbcTimeZone() {
+ return factory.getSessionFactoryOptions().getJdbcTimeZone();
+ }
+
+ @Override
+ public List getCustomSessionEventListener() {
+ return null;
+ }
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/resource/jdbc/spi/StatementInspector.java b/hibernate-core/src/main/java/org/hibernate/resource/jdbc/spi/StatementInspector.java
index 5e5a6c303861..d833e00d176a 100644
--- a/hibernate-core/src/main/java/org/hibernate/resource/jdbc/spi/StatementInspector.java
+++ b/hibernate-core/src/main/java/org/hibernate/resource/jdbc/spi/StatementInspector.java
@@ -4,6 +4,7 @@
*/
package org.hibernate.resource.jdbc.spi;
+
import java.io.Serializable;
/**
@@ -30,6 +31,8 @@
* @author Steve Ebersole
*/
public interface StatementInspector extends Serializable {
+ StatementInspector NONE = sql -> sql;
+
/**
* Inspect the given SQL command, possibly returning a different
* SQL command to be used instead. A {@code null} return value is
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/actionqueue/CustomAfterCompletionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/actionqueue/CustomAfterCompletionTest.java
index a84ef9158785..2fd6cb703dd0 100644
--- a/hibernate-core/src/test/java/org/hibernate/orm/test/actionqueue/CustomAfterCompletionTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/actionqueue/CustomAfterCompletionTest.java
@@ -30,7 +30,7 @@ public class CustomAfterCompletionTest extends BaseCoreFunctionalTestCase {
public void success() {
inSession( session -> {
AtomicBoolean called = new AtomicBoolean( false );
- session.getActionQueue().registerProcess( new AfterTransactionCompletionProcess() {
+ session.getActionQueue().registerCallback( new AfterTransactionCompletionProcess() {
@Override
public void doAfterTransactionCompletion(boolean success, SharedSessionContractImplementor session) {
called.set( true );
@@ -56,7 +56,7 @@ public void doAfterTransactionCompletion(boolean success, SharedSessionContractI
public void failure() {
try {
inSession( session -> {
- session.getActionQueue().registerProcess( new AfterTransactionCompletionProcess() {
+ session.getActionQueue().registerCallback( new AfterTransactionCompletionProcess() {
@Override
public void doAfterTransactionCompletion(boolean success, SharedSessionContractImplementor session) {
throw new RuntimeException( "My exception" );
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/actionqueue/CustomBeforeCompletionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/actionqueue/CustomBeforeCompletionTest.java
index cd1e2187dc13..4aa869f83806 100644
--- a/hibernate-core/src/test/java/org/hibernate/orm/test/actionqueue/CustomBeforeCompletionTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/actionqueue/CustomBeforeCompletionTest.java
@@ -11,8 +11,8 @@
import org.hibernate.HibernateException;
import org.hibernate.action.spi.BeforeTransactionCompletionProcess;
-import org.hibernate.engine.spi.SessionImplementor;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Assert;
@@ -30,7 +30,7 @@ public class CustomBeforeCompletionTest extends BaseCoreFunctionalTestCase {
public void success() {
inSession( session -> {
AtomicBoolean called = new AtomicBoolean( false );
- session.getActionQueue().registerProcess( s -> called.set( true ) );
+ session.getActionQueue().registerCallback( s -> called.set( true ) );
Assert.assertFalse( called.get() );
inTransaction( session, theSession -> {
theSession.persist( new SimpleEntity( "jack" ) );
@@ -51,9 +51,9 @@ public void success() {
public void failure() {
try {
inSession( session -> {
- session.getActionQueue().registerProcess( new BeforeTransactionCompletionProcess() {
+ session.getActionQueue().registerCallback( new BeforeTransactionCompletionProcess() {
@Override
- public void doBeforeTransactionCompletion(SessionImplementor session) {
+ public void doBeforeTransactionCompletion(SharedSessionContractImplementor session) {
throw new RuntimeException( "My exception" );
}
} );
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/delegation/TestDelegatingSessionBuilderImplementor.java b/hibernate-core/src/test/java/org/hibernate/orm/test/delegation/TestDelegatingSessionBuilderImplementor.java
index d29e51fc6ab5..9a0473b91236 100644
--- a/hibernate-core/src/test/java/org/hibernate/orm/test/delegation/TestDelegatingSessionBuilderImplementor.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/delegation/TestDelegatingSessionBuilderImplementor.java
@@ -5,7 +5,7 @@
package org.hibernate.orm.test.delegation;
import org.hibernate.engine.spi.AbstractDelegatingSessionBuilderImplementor;
-import org.hibernate.engine.spi.SessionBuilderImplementor;
+import org.hibernate.engine.creation.spi.SessionBuilderImplementor;
/**
* If this class does not compile anymore due to unimplemented methods, you should probably add the corresponding
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/StatelessCallbacksTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/StatelessCallbacksTest.java
index c49feda578dc..2cb02b653181 100644
--- a/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/StatelessCallbacksTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/StatelessCallbacksTest.java
@@ -18,7 +18,6 @@
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
-import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
@SessionFactory
@@ -29,17 +28,13 @@ public class StatelessCallbacksTest {
WithCallbacks instance = new WithCallbacks();
instance.name = "gavin";
s.insert(instance);
- // because the semantics of @PrePersist and @PreRemove
- // are inappropriate for a StatelessSession, the @Pre
- // don't get called. However, the @Post events do make
- // sense, since they correspond to database operations
- assertFalse(instance.prePersist);
+ assertTrue(instance.prePersist);
assertTrue(instance.postPersist);
s.update(instance);
- assertFalse(instance.preUpdate);
+ assertTrue(instance.preUpdate);
assertTrue(instance.postUpdate);
s.delete(instance);
- assertFalse(instance.preRemove);
+ assertTrue(instance.preRemove);
assertTrue(instance.postRemove);
});
}
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/events/StatelessSessionCallbacksTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/events/StatelessSessionCallbacksTests.java
new file mode 100644
index 000000000000..cd3a6f416af2
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/events/StatelessSessionCallbacksTests.java
@@ -0,0 +1,169 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.orm.test.stateless.events;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.PostPersist;
+import jakarta.persistence.PostRemove;
+import jakarta.persistence.PostUpdate;
+import jakarta.persistence.PrePersist;
+import jakarta.persistence.PreRemove;
+import jakarta.persistence.PreUpdate;
+import jakarta.persistence.Table;
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author Steve Ebersole
+ */
+@SuppressWarnings("JUnitMalformedDeclaration")
+@DomainModel(annotatedClasses = StatelessSessionCallbacksTests.Person.class)
+@SessionFactory
+public class StatelessSessionCallbacksTests {
+
+ @Test
+ void simpleSession(SessionFactoryScope factoryScope) {
+ factoryScope.inTransaction( (session) -> {
+ final Person john = new Person( 1, "John" );
+ session.persist( john );
+ } );
+
+ checkCallbackCounts( 1, 0, 0 );
+
+ factoryScope.inTransaction( (session) -> {
+ final Person john = session.find( Person.class, 1 );
+ john.name = "Jonathan";
+ } );
+
+ checkCallbackCounts( 1, 1, 0 );
+
+ factoryScope.inTransaction( (session) -> {
+ final Person john = session.find( Person.class, 1 );
+ session.remove( john );
+ } );
+
+ checkCallbackCounts( 1, 1, 1 );
+ }
+
+ @Test
+ void simpleStatelessSession(SessionFactoryScope factoryScope) {
+ factoryScope.inStatelessTransaction( (session) -> {
+ final Person john = new Person( 1, "John" );
+ session.insert( john );
+ } );
+
+ checkCallbackCounts( 1, 0, 0 );
+
+ factoryScope.inStatelessTransaction( (session) -> {
+ final Person john = session.get( Person.class, 1 );
+ john.name = "Jonathan";
+ session.update( john );
+ } );
+
+ checkCallbackCounts( 1, 1, 0 );
+
+ factoryScope.inStatelessTransaction( (session) -> {
+ final Person john = session.get( Person.class, 1 );
+ session.delete( john );
+ } );
+
+ checkCallbackCounts( 1, 1, 1 );
+ }
+
+ private void checkCallbackCounts(int insert, int update, int delete) {
+ assertThat( Person.beforeInsertCalls ).isEqualTo( insert );
+ assertThat( Person.afterInsertCalls ).isEqualTo( insert );
+
+ assertThat( Person.beforeUpdateCalls ).isEqualTo( update );
+ assertThat( Person.afterUpdateCalls ).isEqualTo( update );
+
+ assertThat( Person.beforeDeleteCalls ).isEqualTo( delete );
+ assertThat( Person.afterDeleteCalls ).isEqualTo( delete );
+
+ }
+
+ @BeforeEach
+ void setUp() {
+ Person.resetCallbackState();
+ }
+
+ @AfterEach
+ void dropTestData(SessionFactoryScope factoryScope) {
+ factoryScope.dropData();
+ }
+
+ @Entity(name="Person")
+ @Table(name="persons")
+ public static class Person {
+ public static int beforeInsertCalls;
+ public static int afterInsertCalls;
+
+ public static int beforeUpdateCalls;
+ public static int afterUpdateCalls;
+
+ public static int beforeDeleteCalls;
+ public static int afterDeleteCalls;
+
+ @Id
+ private Integer id;
+ private String name;
+
+ public Person() {
+ }
+
+ public Person(Integer id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+
+ @PrePersist
+ public void beforeInsert() {
+ beforeInsertCalls++;
+ }
+
+ @PostPersist
+ public void afterInsert() {
+ afterInsertCalls++;
+ }
+
+ @PreUpdate
+ public void beforeUpdate() {
+ beforeUpdateCalls++;
+ }
+
+ @PostUpdate
+ public void afterUpdate() {
+ afterUpdateCalls++;
+ }
+
+ @PreRemove
+ public void beforeDelete() {
+ beforeDeleteCalls++;
+ }
+
+ @PostRemove
+ public void afterDelete() {
+ afterDeleteCalls++;
+ }
+
+ public static void resetCallbackState() {
+ beforeInsertCalls = 0;
+ afterInsertCalls = 0;
+
+ beforeUpdateCalls = 0;
+ afterUpdateCalls = 0;
+
+ beforeDeleteCalls = 0;
+ afterDeleteCalls = 0;
+ }
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/shared/SimpleSharedStatelessSessionBuildingTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/shared/SimpleSharedStatelessSessionBuildingTests.java
new file mode 100644
index 000000000000..5e7cc35b8939
--- /dev/null
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/stateless/shared/SimpleSharedStatelessSessionBuildingTests.java
@@ -0,0 +1,168 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.orm.test.stateless.shared;
+
+import jakarta.persistence.Entity;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+import org.hibernate.Interceptor;
+import org.hibernate.Session;
+import org.hibernate.StatelessSession;
+import org.hibernate.engine.spi.StatelessSessionImplementor;
+import org.hibernate.orm.test.interceptor.StatefulInterceptor;
+import org.hibernate.resource.jdbc.spi.StatementInspector;
+import org.hibernate.testing.jdbc.SQLStatementInspector;
+import org.hibernate.testing.orm.junit.DomainModel;
+import org.hibernate.testing.orm.junit.SessionFactory;
+import org.hibernate.testing.orm.junit.SessionFactoryScope;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author Steve Ebersole
+ */
+@SuppressWarnings("JUnitMalformedDeclaration")
+@DomainModel(annotatedClasses = SimpleSharedStatelessSessionBuildingTests.Something.class)
+@SessionFactory(useCollectingStatementInspector = true, interceptorClass = StatefulInterceptor.class)
+public class SimpleSharedStatelessSessionBuildingTests {
+
+ @Test
+ void testStatementInspector(SessionFactoryScope factoryScope) {
+ final SQLStatementInspector sqlCollector = factoryScope.getCollectingStatementInspector();
+
+ // apply a special StatementInspector to the base and check the behavior of the various options
+ final StatementInspectorImpl appliedToBase = new StatementInspectorImpl( "Applied to base" );
+
+ try (Session base = factoryScope.getSessionFactory()
+ .withOptions()
+ .statementInspector( appliedToBase )
+ .openSession()) {
+
+ // baseline:
+ try (StatelessSessionImplementor nested = (StatelessSessionImplementor) base.
+ statelessWithOptions()
+ .open()) {
+ assertThat( nested.getJdbcSessionContext().getStatementInspector() ).isSameAs( sqlCollector );
+ }
+
+ // 1. noStatementInspector
+ try (StatelessSessionImplementor nested = (StatelessSessionImplementor) base
+ .statelessWithOptions()
+ .noStatementInspector()
+ .open()) {
+ assertThat( nested.getJdbcSessionContext().getStatementInspector() ).isNotSameAs( sqlCollector );
+ assertThat( nested.getJdbcSessionContext().getStatementInspector() ).isNotSameAs( appliedToBase );
+ }
+
+ // 2. statementInspector()
+ try (StatelessSessionImplementor nested = (StatelessSessionImplementor) base
+ .statelessWithOptions()
+ .statementInspector()
+ .open()) {
+ assertThat( nested.getJdbcSessionContext().getStatementInspector() ).isSameAs( appliedToBase );
+ }
+ }
+ }
+
+ @Test
+ void testInterceptor(SessionFactoryScope factoryScope) {
+ final Interceptor sfInterceptor = factoryScope.getSessionFactory().getSessionFactoryOptions().getInterceptor();
+
+ // apply a special StatementInspector to the base and check the behavior of the various options
+ final InterceptorImpl appliedToBase = new InterceptorImpl( "Applied to base" );
+
+ try (Session base = factoryScope.getSessionFactory()
+ .withOptions()
+ .interceptor( appliedToBase )
+ .openSession()) {
+
+ // baseline - should use the Interceptor from SF
+ try (StatelessSessionImplementor nested = (StatelessSessionImplementor) base.
+ statelessWithOptions()
+ .open()) {
+ assertThat( nested.getInterceptor() ).isSameAs( sfInterceptor );
+ }
+
+ // 1. noInterceptor() - should use no (Empty)Interceptor
+ try (StatelessSessionImplementor nested = (StatelessSessionImplementor) base
+ .statelessWithOptions()
+ .noInterceptor()
+ .open()) {
+ assertThat( nested.getInterceptor() ).isNotSameAs( sfInterceptor );
+ assertThat( nested.getInterceptor() ).isNotSameAs( appliedToBase );
+ }
+
+ // 2. interceptor() - should share the interceptor from the base session
+ try (StatelessSessionImplementor nested = (StatelessSessionImplementor) base
+ .statelessWithOptions()
+ .interceptor()
+ .open()) {
+ assertThat( nested.getInterceptor() ).isSameAs( appliedToBase );
+ }
+ }
+ }
+
+ @Test
+ void testUsage(SessionFactoryScope factoryScope) {
+ final SQLStatementInspector sqlCollector = factoryScope.getCollectingStatementInspector();
+
+ // try from Session
+ sqlCollector.clear();
+ factoryScope.inTransaction( (statefulSession) -> {
+ try (StatelessSession statelessSession = statefulSession
+ .statelessWithOptions()
+ .connection()
+ .open()) {
+ statelessSession.insert( new Something( 1, "first" ) );
+ }
+ } );
+
+ // try from StatelessSession
+ sqlCollector.clear();
+ factoryScope.inStatelessTransaction( (statelessSession) -> {
+ try (StatelessSession ss2 = statelessSession
+ .statelessWithOptions()
+ .connection()
+ .open()) {
+ ss2.insert( new Something( 2, "first" ) );
+ }
+ } );
+
+ assertThat( sqlCollector.getSqlQueries() ).hasSize( 1 );
+ }
+
+ @AfterEach
+ void dropTestData(SessionFactoryScope factoryScope) {
+ factoryScope.dropData();
+ }
+
+ @Entity(name="Something")
+ @Table(name="somethings")
+ public static class Something {
+ @Id
+ private Integer id;
+ private String name;
+
+ public Something() {
+ }
+
+ public Something(Integer id, String name) {
+ this.id = id;
+ this.name = name;
+ }
+ }
+
+ public record StatementInspectorImpl(String name) implements StatementInspector {
+ @Override
+ public String inspect(String sql) {
+ return sql;
+ }
+ }
+
+ public record InterceptorImpl(String name) implements Interceptor {
+ }
+}
diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/tm/JtaAfterCompletionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/tm/JtaAfterCompletionTest.java
index b89dabe50869..3a748e4999c7 100644
--- a/hibernate-core/src/test/java/org/hibernate/orm/test/tm/JtaAfterCompletionTest.java
+++ b/hibernate-core/src/test/java/org/hibernate/orm/test/tm/JtaAfterCompletionTest.java
@@ -77,8 +77,8 @@ public void testAfterCompletionCallbackExecutedAfterTransactionTimeout() throws
// The after tracks whether it is invoked since this test is to guarantee it is called
final SessionImplementor sessionImplementor = (SessionImplementor) session;
final ActionQueue actionQueue = sessionImplementor.getActionQueue();
- actionQueue.registerProcess( new AfterCallbackCompletionHandler() );
- actionQueue.registerProcess( new BeforeCallbackCompletionHandler() );
+ actionQueue.registerCallback( new AfterCallbackCompletionHandler() );
+ actionQueue.registerCallback( new BeforeCallbackCompletionHandler() );
TestingJtaPlatformImpl.transactionManager().commit();
}
@@ -104,7 +104,7 @@ public void testAfterCompletionCallbackExecutedAfterTransactionTimeout() throws
public static class BeforeCallbackCompletionHandler implements BeforeTransactionCompletionProcess {
@Override
- public void doBeforeTransactionCompletion(SessionImplementor session) {
+ public void doBeforeTransactionCompletion(SharedSessionContractImplementor session) {
try {
// Wait for the transaction to be rolled back by the Reaper thread.
final Transaction transaction = TestingJtaPlatformImpl.transactionManager().getTransaction();
diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/RevisionInfoConfiguration.java b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/RevisionInfoConfiguration.java
index 9ad4bc106cad..3da2a85fff57 100644
--- a/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/RevisionInfoConfiguration.java
+++ b/hibernate-envers/src/main/java/org/hibernate/envers/configuration/internal/RevisionInfoConfiguration.java
@@ -41,6 +41,7 @@
import org.hibernate.envers.internal.revisioninfo.RevisionInfoNumberReader;
import org.hibernate.envers.internal.revisioninfo.RevisionInfoQueryCreator;
import org.hibernate.envers.internal.revisioninfo.RevisionTimestampValueResolver;
+import org.hibernate.internal.util.StringHelper;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.models.spi.ClassDetails;
@@ -72,6 +73,7 @@ public class RevisionInfoConfiguration {
private final RevisionInfoQueryCreator revisionInfoQueryCreator;
private final ModifiedEntityNamesReader modifiedEntityNamesReader;
private final String revisionInfoEntityName;
+ private final String revisionInfoQueryName;
private final PropertyData revisionInfoTimestampData;
private final String revisionInfoTimestampTypeName;
private final String revisionPropType;
@@ -89,6 +91,7 @@ public RevisionInfoConfiguration(Configuration config, InFlightMetadataCollector
// initialize attributes from resolver
this.revisionInfoClass = resolver.revisionInfoClass;
this.revisionInfoEntityName = resolver.revisionInfoEntityName;
+ this.revisionInfoQueryName = resolver.revisionInfoQueryName;
this.revisionPropType = resolver.revisionPropType;
this.revisionPropSqlType = resolver.revisionPropSqlType;
this.revisionInfoTimestampData = resolver.revisionInfoTimestampData;
@@ -106,7 +109,7 @@ public RevisionInfoConfiguration(Configuration config, InFlightMetadataCollector
);
revisionInfoQueryCreator = new RevisionInfoQueryCreator(
- resolver.revisionInfoEntityName,
+ resolver.revisionInfoQueryName,
resolver.revisionInfoIdData.getName(),
resolver.timestampValueResolver
);
@@ -123,10 +126,20 @@ public RevisionInfoConfiguration(Configuration config, InFlightMetadataCollector
}
}
+ /**
+ * The full entity name for the revision entity.
+ */
public String getRevisionInfoEntityName() {
return revisionInfoEntityName;
}
+ /**
+ * The query name for the revision entity.
+ */
+ public String getRevisionInfoQueryName() {
+ return revisionInfoQueryName;
+ }
+
public String getRevisionInfoPropertyType() {
return revisionPropType;
}
@@ -269,6 +282,7 @@ private class RevisionEntityResolver {
private boolean revisionTimestampFound;
private boolean modifiedEntityNamesFound;
private String revisionInfoEntityName;
+ private String revisionInfoQueryName;
private Class> revisionInfoClass;
private Class extends RevisionListener> revisionListenerClass;
private RevisionInfoGenerator revisionInfoGenerator;
@@ -335,6 +349,7 @@ private void locateRevisionEntityMapping() {
}
revisionInfoEntityName = persistentClass.getEntityName();
+ revisionInfoQueryName = determineQueryName( persistentClass );
revisionInfoClass = persistentClass.getMappedClass();
revisionListenerClass = getRevisionListenerClass( revisionEntity.value() );
@@ -387,8 +402,8 @@ private void locateRevisionEntityMapping() {
: SequenceIdRevisionEntity.class;
}
- // Use the simple name of default revision entities as entity name
- revisionInfoEntityName = revisionInfoClass.getSimpleName();
+ revisionInfoQueryName = revisionInfoClass.getSimpleName();
+ revisionInfoEntityName = revisionInfoClass.getName();
timestampValueResolver = createRevisionTimestampResolver(
revisionInfoClass,
@@ -421,6 +436,13 @@ private void locateRevisionEntityMapping() {
}
}
+ private String determineQueryName(PersistentClass persistentClass) {
+ if ( StringHelper.isNotEmpty( persistentClass.getJpaEntityName() ) ) {
+ return persistentClass.getJpaEntityName();
+ }
+ return persistentClass.getEntityName();
+ }
+
private boolean useEntityTrackingRevisionEntity(Class> clazz) {
return configuration.isTrackEntitiesChanged()
|| ( configuration.isNativeIdEnabled() && DefaultTrackingModifiedEntitiesRevisionEntity.class.isAssignableFrom( clazz ) )
diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/event/spi/BaseEnversEventListener.java b/hibernate-envers/src/main/java/org/hibernate/envers/event/spi/BaseEnversEventListener.java
index 3b014881a028..20111b395576 100644
--- a/hibernate-envers/src/main/java/org/hibernate/envers/event/spi/BaseEnversEventListener.java
+++ b/hibernate-envers/src/main/java/org/hibernate/envers/event/spi/BaseEnversEventListener.java
@@ -6,7 +6,7 @@
import java.util.Set;
-import org.hibernate.engine.spi.SessionImplementor;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.envers.boot.internal.EnversService;
import org.hibernate.envers.exception.AuditException;
import org.hibernate.envers.internal.entities.RelationDescription;
@@ -45,7 +45,7 @@ protected final void generateBidirectionalCollectionChangeWorkUnits(
String entityName,
Object[] newState,
Object[] oldState,
- SessionImplementor session) {
+ SharedSessionContractImplementor session) {
// Checking if this is enabled in configuration ...
if ( !enversService.getConfig().isGenerateRevisionsForCollections() ) {
return;
@@ -84,8 +84,11 @@ protected final void generateBidirectionalCollectionChangeWorkUnits(
}
private void addCollectionChangeWorkUnit(
- AuditProcess auditProcess, SessionImplementor session,
- String fromEntityName, RelationDescription relDesc, Object value) {
+ AuditProcess auditProcess,
+ SharedSessionContractImplementor session,
+ String fromEntityName,
+ RelationDescription relDesc,
+ Object value) {
// relDesc.getToEntityName() doesn't always return the entity name of the value - in case
// of subclasses, this will be root class, no the actual class. So it can't be used here.
String toEntityName;
@@ -128,9 +131,9 @@ private void addCollectionChangeWorkUnit(
);
}
- protected void checkIfTransactionInProgress(SessionImplementor session) {
+ protected void checkIfTransactionInProgress(SharedSessionContractImplementor session) {
if ( !session.isTransactionInProgress() ) {
- // Historical data would not be flushed to audit tables if outside of active transaction
+ // Historical data would not be flushed to audit tables if we are outside an active transaction
// (AuditProcess#doBeforeTransactionCompletion(SessionImplementor) not executed).
throw new AuditException( "Unable to create revision because of non-active transaction" );
}
diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/ComponentPropertyMapper.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/ComponentPropertyMapper.java
index a2e9cf09f820..05a641bc834c 100644
--- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/ComponentPropertyMapper.java
+++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/ComponentPropertyMapper.java
@@ -4,13 +4,8 @@
*/
package org.hibernate.envers.internal.entities.mapper;
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
import org.hibernate.collection.spi.PersistentCollection;
-import org.hibernate.engine.spi.SessionImplementor;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.envers.boot.internal.EnversService;
import org.hibernate.envers.exception.AuditException;
import org.hibernate.envers.internal.entities.PropertyData;
@@ -20,6 +15,11 @@
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
import org.hibernate.property.access.spi.Setter;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
@@ -69,7 +69,7 @@ public void addComposite(PropertyData propertyData, PropertyMapper propertyMappe
@Override
public boolean mapToMapFromEntity(
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Map data,
Object newObj,
Object oldObj) {
@@ -78,7 +78,7 @@ public boolean mapToMapFromEntity(
@Override
public void mapModifiedFlagsToMapFromEntity(
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Map data,
Object newObj,
Object oldObj) {
@@ -251,9 +251,11 @@ private boolean isAllPropertiesNull(Map data) {
@Override
public List mapCollectionChanges(
- SessionImplementor session, String referencingPropertyName,
+ SharedSessionContractImplementor session,
+ String referencingPropertyName,
PersistentCollection newColl,
- Serializable oldColl, Object id) {
+ Serializable oldColl,
+ Object id) {
return delegate.mapCollectionChanges( session, referencingPropertyName, newColl, oldColl, id );
}
diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/ExtendedPropertyMapper.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/ExtendedPropertyMapper.java
index ccd932008488..066fe0dbff4d 100644
--- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/ExtendedPropertyMapper.java
+++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/ExtendedPropertyMapper.java
@@ -6,14 +6,14 @@
import java.util.Map;
-import org.hibernate.engine.spi.SessionImplementor;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
/**
* @author Adam Warski (adam at warski dot org)
*/
public interface ExtendedPropertyMapper extends PropertyMapper, CompositeMapperBuilder {
boolean map(
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Map data,
String[] propertyNames,
Object[] newState,
diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/MultiDynamicComponentMapper.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/MultiDynamicComponentMapper.java
index fdd08ed30160..ea359a257bdd 100644
--- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/MultiDynamicComponentMapper.java
+++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/MultiDynamicComponentMapper.java
@@ -4,13 +4,13 @@
*/
package org.hibernate.envers.internal.entities.mapper;
-import java.util.Map;
-
-import org.hibernate.engine.spi.SessionImplementor;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.envers.boot.internal.EnversService;
import org.hibernate.envers.internal.entities.PropertyData;
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
+import java.util.Map;
+
/**
* Multi mapper for dynamic components (it knows that component is a map, not a class)
*
@@ -43,7 +43,7 @@ public void add(PropertyData propertyData) {
@Override
public boolean mapToMapFromEntity(
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Map data,
Object newObj,
Object oldObj) {
@@ -69,7 +69,7 @@ private Object getValue(Object newObj, PropertyData propertyData) {
@Override
public boolean map(
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Map data,
String[] propertyNames,
Object[] newState,
@@ -92,7 +92,7 @@ public boolean map(
@Override
public void mapModifiedFlagsToMapFromEntity(
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Map data,
Object newObj,
Object oldObj) {
diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/MultiPropertyMapper.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/MultiPropertyMapper.java
index 2764175f7d01..f4a4b5000360 100644
--- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/MultiPropertyMapper.java
+++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/MultiPropertyMapper.java
@@ -4,12 +4,8 @@
*/
package org.hibernate.envers.internal.entities.mapper;
-import java.io.Serializable;
-import java.util.List;
-import java.util.Map;
-
import org.hibernate.collection.spi.PersistentCollection;
-import org.hibernate.engine.spi.SessionImplementor;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.envers.boot.internal.EnversService;
import org.hibernate.envers.internal.entities.PropertyData;
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
@@ -20,6 +16,10 @@
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
import org.hibernate.property.access.spi.Getter;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
@@ -74,7 +74,7 @@ protected Object getAtIndexOrNull(Object[] array, int index) {
@Override
public boolean map(
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Map data,
String[] propertyNames,
Object[] newState,
@@ -97,7 +97,7 @@ public boolean map(
@Override
public boolean mapToMapFromEntity(
- final SessionImplementor session,
+ final SharedSessionContractImplementor session,
final Map data,
final Object newObj,
final Object oldObj) {
@@ -141,7 +141,7 @@ else if ( oldObj != null ) {
@Override
public void mapModifiedFlagsToMapFromEntity(
- final SessionImplementor session,
+ final SharedSessionContractImplementor session,
final Map data,
final Object newObj,
final Object oldObj) {
@@ -240,7 +240,7 @@ public void mapModifiedFlagsToMapForCollectionChange(String collectionPropertyNa
@Override
public List mapCollectionChanges(
- SessionImplementor session,
+ SharedSessionContractImplementor session,
String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl, Object id) {
diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/PropertyMapper.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/PropertyMapper.java
index 75d52b05016f..348a4be2bc8d 100644
--- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/PropertyMapper.java
+++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/PropertyMapper.java
@@ -4,15 +4,15 @@
*/
package org.hibernate.envers.internal.entities.mapper;
-import java.io.Serializable;
-import java.util.List;
-import java.util.Map;
-
import org.hibernate.collection.spi.PersistentCollection;
-import org.hibernate.engine.spi.SessionImplementor;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.envers.boot.internal.EnversService;
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
/**
* @author Adam Warski (adam at warski dot org)
* @author Michal Skowronek (mskowr at o2 dot pl)
@@ -29,7 +29,7 @@ public interface PropertyMapper extends ModifiedFlagMapperSupport, DynamicCompon
*
* @return True if there are any differences between the states represented by newObj and oldObj.
*/
- boolean mapToMapFromEntity(SessionImplementor session, Map data, Object newObj, Object oldObj);
+ boolean mapToMapFromEntity(SharedSessionContractImplementor session, Map data, Object newObj, Object oldObj);
/**
* Maps properties from the given map to the given object.
@@ -68,12 +68,13 @@ Object mapToEntityFromMap(
* @return List of changes that need to be performed on the persistent store.
*/
List mapCollectionChanges(
- SessionImplementor session, String referencingPropertyName,
+ SharedSessionContractImplementor session,
+ String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl, Object id);
void mapModifiedFlagsToMapFromEntity(
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Map data,
Object newObj,
Object oldObj);
diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/SinglePropertyMapper.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/SinglePropertyMapper.java
index 33c33804edea..14c7c51d50a6 100644
--- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/SinglePropertyMapper.java
+++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/SinglePropertyMapper.java
@@ -4,16 +4,11 @@
*/
package org.hibernate.envers.internal.entities.mapper;
-import java.io.Serializable;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
import org.hibernate.HibernateException;
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.OracleDialect;
-import org.hibernate.engine.spi.SessionImplementor;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.envers.boot.internal.EnversService;
import org.hibernate.envers.exception.AuditException;
import org.hibernate.envers.internal.entities.PropertyData;
@@ -23,6 +18,11 @@
import org.hibernate.property.access.spi.Setter;
import org.hibernate.property.access.spi.SetterFieldImpl;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
/**
* TODO: diff
*
@@ -51,7 +51,7 @@ public void add(PropertyData propertyData) {
@Override
public boolean mapToMapFromEntity(
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Map data,
Object newObj,
Object oldObj) {
@@ -67,7 +67,7 @@ public boolean mapToMapFromEntity(
@Override
public void mapModifiedFlagsToMapFromEntity(
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Map data,
Object newObj,
Object oldObj) {
@@ -152,7 +152,7 @@ private boolean isPrimitive(Setter setter, PropertyData propertyData, Class> c
@Override
public List mapCollectionChanges(
- SessionImplementor sessionImplementor,
+ SharedSessionContractImplementor sessionImplementor,
String referencingPropertyName,
PersistentCollection newColl,
Serializable oldColl,
diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/SubclassPropertyMapper.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/SubclassPropertyMapper.java
index cd3da5238504..f7a1302d4e5f 100644
--- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/SubclassPropertyMapper.java
+++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/SubclassPropertyMapper.java
@@ -4,18 +4,18 @@
*/
package org.hibernate.envers.internal.entities.mapper;
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
import org.hibernate.collection.spi.PersistentCollection;
-import org.hibernate.engine.spi.SessionImplementor;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.envers.boot.internal.EnversService;
import org.hibernate.envers.internal.entities.PropertyData;
import org.hibernate.envers.internal.reader.AuditReaderImplementor;
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
/**
* A mapper which maps from a parent mapper and a "main" one, but adds only to the "main". The "main" mapper
* should be the mapper of the subclass.
@@ -35,7 +35,7 @@ public SubclassPropertyMapper(ExtendedPropertyMapper main, ExtendedPropertyMappe
@Override
public boolean map(
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Map data,
String[] propertyNames,
Object[] newState,
@@ -48,7 +48,7 @@ public boolean map(
@Override
public boolean mapToMapFromEntity(
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Map data,
Object newObj,
Object oldObj) {
@@ -60,7 +60,7 @@ public boolean mapToMapFromEntity(
@Override
public void mapModifiedFlagsToMapFromEntity(
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Map data,
Object newObj,
Object oldObj) {
@@ -98,9 +98,11 @@ public Object mapToEntityFromMap(
@Override
public List mapCollectionChanges(
- SessionImplementor session, String referencingPropertyName,
+ SharedSessionContractImplementor session,
+ String referencingPropertyName,
PersistentCollection newColl,
- Serializable oldColl, Object id) {
+ Serializable oldColl,
+ Object id) {
final List parentCollectionChanges = parentMapper.mapCollectionChanges(
session,
referencingPropertyName,
diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/IdMapper.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/IdMapper.java
index 28a14ce3ba70..6e5ce9be44cf 100644
--- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/IdMapper.java
+++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/IdMapper.java
@@ -4,13 +4,13 @@
*/
package org.hibernate.envers.internal.entities.mapper.id;
-import java.util.List;
-import java.util.Map;
-
-import org.hibernate.Session;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.envers.internal.tools.query.Parameters;
import org.hibernate.service.ServiceRegistry;
+import java.util.List;
+import java.util.Map;
+
/**
* Base contract for all identifier mappers.
*
@@ -22,7 +22,7 @@ public interface IdMapper {
void mapToMapFromId(Map data, Object obj);
- default void mapToMapFromId(Session session, Map data, Object obj) {
+ default void mapToMapFromId(SharedSessionContractImplementor session, Map data, Object obj) {
// Delegate to the old behavior, allowing implementations to override.
mapToMapFromId( data, obj );
}
diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/MultipleIdMapper.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/MultipleIdMapper.java
index 5cdc253414a4..93174d888753 100644
--- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/MultipleIdMapper.java
+++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/MultipleIdMapper.java
@@ -4,18 +4,18 @@
*/
package org.hibernate.envers.internal.entities.mapper.id;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.hibernate.Session;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.envers.internal.entities.PropertyData;
import org.hibernate.mapping.Component;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.service.ServiceRegistry;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
/**
* An implementation of an identifier mapper for {@link jakarta.persistence.IdClass} or multiple
* {@link jakarta.persistence.Id} identifier mappings.
@@ -43,7 +43,7 @@ public void add(PropertyData propertyData) {
}
@Override
- public void mapToMapFromId(Session session, Map data, Object obj) {
+ public void mapToMapFromId(SharedSessionContractImplementor session, Map data, Object obj) {
if ( compositeIdClass.isInstance( obj ) ) {
if ( embedded ) {
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( obj );
diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/VirtualEntitySingleIdMapper.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/VirtualEntitySingleIdMapper.java
index ce25129b5b3b..74254d92f5d2 100644
--- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/VirtualEntitySingleIdMapper.java
+++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/VirtualEntitySingleIdMapper.java
@@ -6,11 +6,12 @@
import java.util.Map;
-import org.hibernate.Session;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.envers.boot.internal.EnversService;
import org.hibernate.envers.internal.entities.EntitiesConfigurations;
import org.hibernate.envers.internal.entities.EntityConfiguration;
import org.hibernate.envers.internal.entities.PropertyData;
+import org.hibernate.envers.internal.tools.OrmTools;
import org.hibernate.envers.internal.tools.ReflectionTools;
import org.hibernate.property.access.spi.Getter;
import org.hibernate.property.access.spi.Setter;
@@ -44,12 +45,12 @@ public VirtualEntitySingleIdMapper(ServiceRegistry serviceRegistry, PropertyData
}
@Override
- public void mapToMapFromId(Session session, Map data, Object obj) {
+ public void mapToMapFromId(SharedSessionContractImplementor session, Map data, Object obj) {
final Object value = getValueFromObject( propertyData, obj );
// Either loads the entity from the session's 1LC if it already exists or potentially creates a
// proxy object to represent the entity by identifier so that we can reference it in the map.
- final Object entity = session.getReference( this.entityName, value );
+ final Object entity = OrmTools.loadAuditEntity( this.entityName, value, session );
data.put( propertyData.getName(), entity );
}
diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/relation/AbstractCollectionMapper.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/relation/AbstractCollectionMapper.java
index 82da4496cf45..5511647ac50b 100644
--- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/relation/AbstractCollectionMapper.java
+++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/relation/AbstractCollectionMapper.java
@@ -16,7 +16,7 @@
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.CollectionEntry;
-import org.hibernate.engine.spi.SessionImplementor;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.envers.RevisionType;
import org.hibernate.envers.boot.internal.EnversService;
import org.hibernate.envers.configuration.Configuration;
@@ -77,7 +77,7 @@ protected AbstractCollectionMapper(
* @param changed The changed collection element to map.
*/
protected abstract void mapToMapFromObject(
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Map idData,
Map data,
Object changed);
@@ -99,7 +99,7 @@ protected Map createIdMap(int ordinal) {
}
protected void addCollectionChanges(
- SessionImplementor session,
+ SharedSessionContractImplementor session,
List collectionChanges,
Set