You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@causeway.apache.org by da...@apache.org on 2023/12/11 10:37:38 UTC

(causeway) 20/25: CAUSEWAY-3654: moves calls to transactionBoundaryAwareBeans within the iteration of

This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch CAUSEWAY-3654-isis
in repository https://gitbox.apache.org/repos/asf/causeway.git

commit cf7602952b9695a4b9f65cabda97cd9a937e49a6
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Sun Dec 10 11:13:20 2023 +0000

    CAUSEWAY-3654: moves calls to transactionBoundaryAwareBeans within the iteration of
    
    PlatformTransactionManagers of onOpen, and the onCloseTasks similarly.
    
    Note that if there is more than one PlatformTransactionManager, then currently these TBAB's will be called multiple times and not know why
---
 .../services/xactn/TransactionalProcessor.java     | 17 ++++++++--
 .../session/InteractionServiceDefault.java         | 13 ++------
 .../transaction/TransactionServiceSpring.java      | 39 +++++++++++-----------
 3 files changed, 36 insertions(+), 33 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionalProcessor.java b/api/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionalProcessor.java
index e3275bcfce..51cf67e75e 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionalProcessor.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionalProcessor.java
@@ -44,6 +44,10 @@ public interface TransactionalProcessor {
     /**
      * Runs given {@code callable} with a transactional boundary, where the detailed transactional behavior
      * is governed by given {@link TransactionDefinition} {@code def}.
+     *
+     * @param def - transaction definition, in particular whether to use existing or start new transaction.  Requires only a single {@link org.springframework.transaction.PlatformTransactionManager} to be configured (unless a {@link org.springframework.transaction.support.TransactionTemplate} is provided which wraps a specific {@link org.springframework.transaction.PlatformTransactionManager}.
+     * @param callable - the work to be performed within the transaction.
+     * @return {@link Try} of calling given {@code callable}
      * @return {@link Try} of calling given {@code callable}
      */
     <T> Try<T> callTransactional(TransactionDefinition def, Callable<T> callable);
@@ -51,6 +55,10 @@ public interface TransactionalProcessor {
     /**
      * Runs given {@code runnable} with a transactional boundary, where the detailed transactional behavior
      * is governed by given {@link TransactionDefinition} {@code def}.
+     *
+     * @param def - transaction definition, in particular whether to use existing or start new transaction.  Requires only a single {@link org.springframework.transaction.PlatformTransactionManager} to be configured (unless a {@link org.springframework.transaction.support.TransactionTemplate} is provided which wraps a specific {@link org.springframework.transaction.PlatformTransactionManager}.
+     * @param runnable - the work to be performed within the transaction.
+     * @return {@link Try} of calling given {@code callable}
      */
     default Try<Void> runTransactional(final TransactionDefinition def, final ThrowingRunnable runnable) {
         return callTransactional(def, ThrowingRunnable.toCallable(runnable));
@@ -61,8 +69,9 @@ public interface TransactionalProcessor {
     /**
      * Runs given {@code callable} with a transactional boundary, where the detailed transactional behavior
      * is governed by given {@link Propagation} {@code propagation}.
-     * <p>
-     * More fine grained control is given via {@link #callTransactional(TransactionDefinition, Callable)}
+     *
+     * @param propagation - transaction propagation, ie whether to use existing or start new transaction.  Requires only a single {@link org.springframework.transaction.PlatformTransactionManager} to be configured.  For more control, use {@link #callTransactional(TransactionDefinition, Callable)} and pass in a {@link org.springframework.transaction.support.TransactionTemplate} is provided which wraps a specific {@link org.springframework.transaction.PlatformTransactionManager}.
+     * @param callable - the work to be performed within the transaction.
      * @return {@link Try} of calling given {@code callable}
      */
     default <T> Try<T> callTransactional(final Propagation propagation, final Callable<T> callable) {
@@ -77,6 +86,10 @@ public interface TransactionalProcessor {
      * <p>
      * More fine grained control is given via
      * {@link #runTransactional(TransactionDefinition, ThrowingRunnable)}
+     *
+     * @param propagation - transaction propagation, ie whether to use existing or start new transaction.  Requires only a single {@link org.springframework.transaction.PlatformTransactionManager} to be configured.  For more control, use {@link #callTransactional(TransactionDefinition, Callable)} and pass in a {@link org.springframework.transaction.support.TransactionTemplate} is provided which wraps a specific {@link org.springframework.transaction.PlatformTransactionManager}.
+     * @param runnable - the work to be performed within the transaction.
+     * @return {@link Try} of calling given {@code callable}
      */
     default Try<Void> runTransactional(final Propagation propagation, final ThrowingRunnable runnable) {
         return callTransactional(propagation, ThrowingRunnable.toCallable(runnable));
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/InteractionServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/InteractionServiceDefault.java
index 2a6cb150a2..91fc2a5167 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/InteractionServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/InteractionServiceDefault.java
@@ -19,7 +19,6 @@
 package org.apache.isis.core.runtimeservices.session;
 
 import java.io.File;
-import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Stack;
@@ -35,7 +34,6 @@ import org.apache.isis.core.runtimeservices.transaction.TransactionServiceSpring
 
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.beans.factory.config.ConfigurableBeanFactory;
-import org.springframework.context.annotation.Lazy;
 import org.springframework.context.event.ContextRefreshedEvent;
 import org.springframework.context.event.EventListener;
 import org.springframework.stereotype.Service;
@@ -63,7 +61,6 @@ import org.apache.isis.commons.internal.debug.xray.XrayUi;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.interaction.scope.InteractionScopeBeanFactoryPostProcessor;
 import org.apache.isis.core.interaction.scope.InteractionScopeLifecycleHandler;
-import org.apache.isis.core.interaction.scope.TransactionBoundaryAware;
 import org.apache.isis.core.interaction.session.IsisInteraction;
 import org.apache.isis.core.metamodel.services.publishing.CommandPublisher;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
@@ -204,7 +201,8 @@ implements
         interactionLayerStack.get().push(interactionLayer);
 
         if(isAtTopLevel()) {
-        	postInteractionOpened(isisInteraction);
+            transactionServiceSpring.onOpen(isisInteraction);
+            interactionScopeLifecycleHandler.onTopLevelInteractionOpened();
         }
 
         if(log.isDebugEnabled()) {
@@ -361,13 +359,6 @@ implements
     	return interactionLayerStack.get().size()==1;
     }
 
-    private void postInteractionOpened(final IsisInteraction interaction) {
-
-        transactionServiceSpring.onOpen(interaction);
-
-        interactionScopeLifecycleHandler.onTopLevelInteractionOpened();
-    }
-
     @SneakyThrows
     private void preInteractionClosed(final IsisInteraction interaction) {
 
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/transaction/TransactionServiceSpring.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/transaction/TransactionServiceSpring.java
index 481b950242..7cb60ce0c3 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/transaction/TransactionServiceSpring.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/transaction/TransactionServiceSpring.java
@@ -337,14 +337,15 @@ implements
             log.debug("opening on {}", _Probe.currentThreadId());
         }
 
-        transactionBoundaryAwareBeans.forEach(TransactionBoundaryAware::beforeEnteringTransactionalBoundary);
-
         if (!platformTransactionManagers.isEmpty()) {
             val onCloseTasks = _Lists.<CloseTask>newArrayList(platformTransactionManagers.size());
+
             interaction.putAttribute(OnCloseHandle.class, new OnCloseHandle(onCloseTasks));
 
             platformTransactionManagers.forEach(txManager -> {
 
+                transactionBoundaryAwareBeans.forEach(TransactionBoundaryAware::beforeEnteringTransactionalBoundary);
+
                 val def = new TransactionTemplate(txManager);
                 def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
 
@@ -357,24 +358,26 @@ implements
                 }
 
                 // we have created a new transaction, so need to provide a CloseTask
-
-                ((Consumer<CloseTask>) onCloseTasks::add).accept(
+                onCloseTasks.add(
                         new CloseTask(
-                                txStatus,
-                                txManager.getClass().getName(), // info to be used for display in case of errors
-                                ()->{
-
-                                    if(txStatus.isRollbackOnly()) {
-                                        txManager.rollback(txStatus);
-                                    } else {
-                                        txManager.commit(txStatus);
-                                    }
-
-                                }));
+                            txStatus,
+                            txManager.getClass().getName(), // info to be used for display in case of errors
+                            () -> {
+                                transactionBoundaryAwareBeans.forEach(TransactionBoundaryAware::beforeLeavingTransactionalBoundary);
+                                if (txStatus.isRollbackOnly()) {
+                                    txManager.rollback(txStatus);
+                                } else {
+                                    txManager.commit(txStatus);
+                                }
+                                transactionBoundaryAwareBeans.forEach(TransactionBoundaryAware::afterLeavingTransactionalBoundary);
+                            }
+                        )
+                );
+
+                transactionBoundaryAwareBeans.forEach(TransactionBoundaryAware::afterEnteringTransactionalBoundary);
             });
         }
 
-        transactionBoundaryAwareBeans.forEach(TransactionBoundaryAware::afterEnteringTransactionalBoundary);
     }
 
 
@@ -389,15 +392,11 @@ implements
             log.debug("closing on {}", _Probe.currentThreadId());
         }
 
-        transactionBoundaryAwareBeans.forEach(TransactionBoundaryAware::beforeLeavingTransactionalBoundary);
-
         if (!platformTransactionManagers.isEmpty()) {
             Optional.ofNullable(interaction.getAttribute(OnCloseHandle.class))
                     .ifPresent(OnCloseHandle::runOnCloseTasks);
         }
 
-        transactionBoundaryAwareBeans.forEach(TransactionBoundaryAware::afterLeavingTransactionalBoundary);
-
         txCounter.remove(); //XXX not tested yet: can we be certain that no txCounter.get() is called afterwards?
     }