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

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


The following commit(s) were added to refs/heads/CAUSEWAY-3654 by this push:
     new 15902ba61b CAUSEWAY-3654: adds guards to handle afterCompletion call
15902ba61b is described below

commit 15902ba61b5de6d7a82c63354c68c80665fbba94
Author: danhaywood <d...@haywood-associates.co.uk>
AuthorDate: Tue Dec 12 17:58:00 2023 +0000

    CAUSEWAY-3654: adds guards to handle afterCompletion call
---
 .../transaction/scope/StackedTransactionScope.java | 29 ++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)

diff --git 
a/core/transaction/src/main/java/org/apache/causeway/core/transaction/scope/StackedTransactionScope.java
 
b/core/transaction/src/main/java/org/apache/causeway/core/transaction/scope/StackedTransactionScope.java
index d1a431fb9e..4bdbb94ccd 100644
--- 
a/core/transaction/src/main/java/org/apache/causeway/core/transaction/scope/StackedTransactionScope.java
+++ 
b/core/transaction/src/main/java/org/apache/causeway/core/transaction/scope/StackedTransactionScope.java
@@ -15,10 +15,14 @@
  */
 package org.apache.causeway.core.transaction.scope;
 
+import lombok.val;
+
 import java.util.HashMap;
 import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Stack;
+import java.util.stream.Collectors;
 
 import org.springframework.beans.factory.ObjectFactory;
 import org.springframework.beans.factory.config.Scope;
@@ -37,9 +41,30 @@ public class StackedTransactionScope implements Scope {
         ScopedObjectsHolder scopedObjects = (ScopedObjectsHolder) 
TransactionSynchronizationManager.getResource(key);
                if (scopedObjects == null) {
                        scopedObjects = new ScopedObjectsHolder();
-                       
TransactionSynchronizationManager.registerSynchronization(new 
CleanupSynchronization(scopedObjects));
+            if (TransactionSynchronizationManager.isSynchronizationActive()) {
+                // this happen when TransactionSynchronization#afterCompletion 
is called.
+                // it's a catch-22 : we use TransactionSynchronization as a 
resource to hold the scoped objects,
+                // but those scoped objects shouldn't only be interacted with 
during the transaction, not after it.
+                //
+                // see the 'else' clause for the handling if we encounter the 
ScopedObjectsHolder later.
+                           
TransactionSynchronizationManager.registerSynchronization(new 
CleanupSynchronization(scopedObjects));
+            }
                        TransactionSynchronizationManager.bindResource(key, 
scopedObjects);
-               }
+               } else {
+            if (TransactionSynchronizationManager.isSynchronizationActive()) {
+                // it's possible that this already-existing scopedObject was 
added when a synchronization wasn't active
+                // and so wouldn't be known to TSM.  if that's the case, we 
register it now.
+                val synchronizations = 
TransactionSynchronizationManager.getSynchronizations();
+                val synchronizedHolders = synchronizations.stream()
+                                                
.filter(CleanupSynchronization.class::isInstance)
+                                                
.map(CleanupSynchronization.class::cast)
+                                                .map(x -> x.scopedObjects)
+                                                .collect(Collectors.toList());
+                if (! synchronizedHolders.contains(scopedObjects)) {
+                    
TransactionSynchronizationManager.registerSynchronization(new 
CleanupSynchronization(scopedObjects));
+                }
+            }
+        }
                // NOTE: Do NOT modify the following to use 
Map::computeIfAbsent. For details,
                // see 
https://github.com/spring-projects/spring-framework/issues/25801.
                Object scopedObject = scopedObjects.scopedInstances.get(name);

Reply via email to