You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2020/12/30 18:51:44 UTC

[isis] 01/01: ISIS-2033: Let Spring take over Transaction Management

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

ahuber pushed a commit to branch 2033-Spring_Data_Integration
in repository https://gitbox.apache.org/repos/asf/isis.git

commit e7f6276e5343e3c2117b8b9b25aad1a766dab3e3
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed Dec 30 19:51:21 2020 +0100

    ISIS-2033: Let Spring take over Transaction Management
---
 .../applib/services/xactn/TransactionService.java  |   1 -
 .../services/xactn/TransactionalProcessor.java     |  42 ++++-
 .../metamodel/context/HasMetaModelContext.java     |   5 -
 .../core/metamodel/context/MetaModelContext.java   |   3 -
 .../context/MetaModelContext_usingIoc.java         |   9 +-
 ...ctionInvocationFacetForDomainEventAbstract.java |  52 +++---
 ...tySetterOrClearFacetForDomainEventAbstract.java |   2 +-
 .../query/ObjectBulkLoader_builtinHandlers.java    |   2 +-
 .../command/CommandExecutorServiceDefault.java     |   2 +-
 .../wrapper/WrapperFactoryDefault.java             |   2 +-
 .../xactn/TransactionServiceSpring.java            | 197 +++++++++++----------
 .../xactn/_GlobalPlatformTransactionManager.java   |  62 -------
 .../jobcallables/IsTickingClockInitialized.java    |   2 +-
 .../jobcallables/ReplicateAndRunCommands.java      |  12 +-
 .../jdo/datanucleus/config/DnSettings.java         |  74 ++++++++
 persistence/jdo/integration/pom.xml                |   4 +
 .../jdo/integration/IsisModuleJdoIntegration.java  |  26 ++-
 .../lifecycles/JdoPersistenceLifecycleService.java |  14 +-
 .../metamodel/facets/entity/JdoEntityFacet.java    |  10 +-
 .../jdo/integration/persistence/DnApplication.java |  77 ++++++++
 .../persistence/JdoPersistenceSession5.java        |  32 ++--
 .../persistence/JdoPersistenceSessionFactory.java  |   8 -
 .../persistence/JdoPersistenceSessionFactory5.java | 148 +---------------
 .../jdo/integration/persistence/_ContextUtil.java  |  57 ------
 ...ponents5.java => _DnApplicationComponents.java} |  19 +-
 ...reManagerType.java => _DnStoreManagerType.java} |  10 +-
 ...sisPlatformTransactionManagerForJdoNoMore.java} |  29 ++-
 .../transaction/TxManagerInternalFactory.java      |   2 +-
 .../jdo/integration/transaction/_TxProcessor.java  |  13 +-
 .../jdo/lightweight/IsisModuleJdoLightweight.java  |  12 +-
 .../metamodel/facets/entity/JdoEntityFacet.java    |  25 +--
 .../facets/entity/JdoEntityFacetFactory.java       | 110 ------------
 .../applayer/ApplicationLayerTestFactory.java      |   2 +-
 .../persistence/jpa/JpaBootstrappingTest.java      |  20 ++-
 ...actionRollbackTest_usingTransactionService.java |   4 +-
 ...TransactionRollbackTest_usingTransactional.java |  56 ++++--
 .../isis/JdoIsisTransactionScopeListenerTest.java  |   2 +-
 ...actionRollbackTest_usingTransactionService.java |  55 +++---
 ...TransactionRollbackTest_usingTransactional.java |  64 ++++---
 .../JdoSpringTransactionScopeListenerTest.java     |   2 +-
 ...actionRollbackTest_usingTransactionService.java |  78 ++++----
 ...TransactionRollbackTest_usingTransactional.java |  23 ++-
 .../jpa/JpaTransactionScopeListenerTest.java       |   2 +-
 .../applib/fixturescripts/FixtureScripts.java      |   4 +-
 .../applib/IsisInteractionHandler.java             |  11 ++
 .../IsisRestfulObjectsInteractionFilter.java       |  15 +-
 .../ui/pages/accmngt/register/RegisterPanel.java   |   2 +-
 47 files changed, 650 insertions(+), 753 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java b/api/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java
index 736d145..d95bc42 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java
@@ -56,5 +56,4 @@ public interface TransactionService extends TransactionalProcessor {
      */
     void nextTransaction();
 
-
 }
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 64b4ebb..aab6bcf 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
@@ -20,20 +20,49 @@ package org.apache.isis.applib.services.xactn;
 
 import java.util.concurrent.Callable;
 
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.support.DefaultTransactionDefinition;
+
 import org.apache.isis.commons.functional.Result;
 import org.apache.isis.commons.functional.ThrowingRunnable;
 
 import lombok.val;
 
 public interface TransactionalProcessor {
+
+    // -- INTERFACE
+    
+    /**
+     * Runs given {@code callable} with a transactional boundary, where the detailed transactional behavior 
+     * is governed by given {@link TransactionDefinition} {@code def}.
+     * @return {@link Result} of calling given {@code callable} 
+     */
+    <T> Result<T> callTransactional(TransactionDefinition def, Callable<T> callable);
+    
+    // -- SHORTCUTS
+    
+    /**
+     * Runs given {@code runnable} with a transactional boundary, where the detailed transactional behavior 
+     * is governed by given {@link TransactionDefinition} {@code def}.
+     */
+    default Result<Void> runTransactional(TransactionDefinition def, ThrowingRunnable runnable) {
+        return callTransactional(def, ThrowingRunnable.toCallable(runnable));
+    }
     
     /**
      * Runs given {@code callable} within an existing transactional boundary, or in the absence of such a
-     * boundary creates a new one.
-     *
+     * boundary, creates a new one.
+     * <p>
+     * In other words, support a current transaction, create a new one if none exists. 
+     * @param <T>
      * @param callable
+     * @return {@link Result} of calling given {@code callable} 
      */
-    <T> Result<T> executeWithinTransaction(Callable<T> callable);
+    default <T> Result<T> callWithinCurrentTransactionElseCreateNew(Callable<T> callable) {
+        val def = new DefaultTransactionDefinition();
+        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
+        return callTransactional(def, callable);
+    }
     
     /**
      * Runs given {@code runnable} within an existing transactional boundary, or in the absence of such a
@@ -41,9 +70,10 @@ public interface TransactionalProcessor {
      *
      * @param runnable
      */
-    default Result<Void> executeWithinTransaction(ThrowingRunnable runnable) {
-        val callable = ThrowingRunnable.toCallable(runnable);
-        return executeWithinTransaction(callable);
+    default Result<Void> runWithinCurrentTransactionElseCreateNew(ThrowingRunnable runnable) {
+        return callWithinCurrentTransactionElseCreateNew(ThrowingRunnable.toCallable(runnable));
     }
+    
+    
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/context/HasMetaModelContext.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/context/HasMetaModelContext.java
index dfd56bf..f715482 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/context/HasMetaModelContext.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/context/HasMetaModelContext.java
@@ -28,7 +28,6 @@ import org.apache.isis.applib.services.repository.RepositoryService;
 import org.apache.isis.applib.services.title.TitleService;
 import org.apache.isis.applib.services.wrapper.WrapperFactory;
 import org.apache.isis.applib.services.xactn.TransactionService;
-import org.apache.isis.applib.services.xactn.TransactionState;
 import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.core.config.environment.IsisSystemEnvironment;
 import org.apache.isis.core.metamodel.execution.MemberExecutorService;
@@ -105,10 +104,6 @@ public interface HasMetaModelContext {
         return getMetaModelContext().getRepositoryService();
     }
 
-    default TransactionState getTransactionState() {
-        return getMetaModelContext().getTransactionState();
-    }
-
     default ManagedObject getHomePageAdapter() {
         return getMetaModelContext().getHomePageAdapter();
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/context/MetaModelContext.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/context/MetaModelContext.java
index e9b36b3..caf3582 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/context/MetaModelContext.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/context/MetaModelContext.java
@@ -28,7 +28,6 @@ import org.apache.isis.applib.services.repository.RepositoryService;
 import org.apache.isis.applib.services.title.TitleService;
 import org.apache.isis.applib.services.wrapper.WrapperFactory;
 import org.apache.isis.applib.services.xactn.TransactionService;
-import org.apache.isis.applib.services.xactn.TransactionState;
 import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.core.config.environment.IsisSystemEnvironment;
 import org.apache.isis.core.metamodel.execution.MemberExecutorService;
@@ -90,8 +89,6 @@ public interface MetaModelContext {
 
     TransactionService getTransactionService();
 
-    TransactionState getTransactionState();
-
     ManagedObject getHomePageAdapter();
 
     Stream<ManagedObject> streamServiceAdapters();
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/context/MetaModelContext_usingIoc.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/context/MetaModelContext_usingIoc.java
index bf7ed11..cdae61e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/context/MetaModelContext_usingIoc.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/context/MetaModelContext_usingIoc.java
@@ -32,7 +32,6 @@ import org.apache.isis.applib.services.repository.RepositoryService;
 import org.apache.isis.applib.services.title.TitleService;
 import org.apache.isis.applib.services.wrapper.WrapperFactory;
 import org.apache.isis.applib.services.xactn.TransactionService;
-import org.apache.isis.applib.services.xactn.TransactionState;
 import org.apache.isis.commons.internal.base._Lazy;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.commons.internal.ioc._IocContainer;
@@ -128,10 +127,10 @@ class MetaModelContext_usingIoc implements MetaModelContext {
     getSingletonElseFail(MemberExecutorService.class);
     
     
-    @Override
-    public final TransactionState getTransactionState() {
-        return getTransactionService().currentTransactionState();
-    }
+//    @Override
+//    public final TransactionState getTransactionState() {
+//        return getTransactionService().currentTransactionState();
+//    }
 
     @Override
     public final ManagedObject getHomePageAdapter() {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java
index aa9c4c7..632a5e5 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java
@@ -25,10 +25,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.function.Consumer;
 
-import org.apache.isis.applib.NonRecoverableException;
-import org.apache.isis.applib.RecoverableException;
 import org.apache.isis.applib.events.domain.AbstractDomainEvent;
 import org.apache.isis.applib.events.domain.ActionDomainEvent;
 import org.apache.isis.applib.services.iactn.Interaction.ActionInvocation;
@@ -39,7 +36,6 @@ import org.apache.isis.commons.internal.assertions._Assert;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.collections._Arrays;
 import org.apache.isis.core.metamodel.commons.CanonicalParameterUtil;
-import org.apache.isis.core.metamodel.commons.ThrowableExtensions;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.execution.InternalInteraction;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
@@ -57,6 +53,7 @@ import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import lombok.Getter;
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
 import lombok.val;
 
 public abstract class ActionInvocationFacetForDomainEventAbstract
@@ -108,7 +105,7 @@ implements ImperativeFacet {
             final InteractionInitiatedBy interactionInitiatedBy) {
 
         val executionResult = 
-                getTransactionService().executeWithinTransaction(()->
+                getTransactionService().callWithinCurrentTransactionElseCreateNew(()->
                     doInvoke(owningAction, head, argumentAdapters, interactionInitiatedBy));
 
         //PersistableTypeGuard.instate(executionResult);
@@ -231,10 +228,11 @@ implements ImperativeFacet {
         private final ManagedObject mixinElseRegularAdapter;
         private final ManagedObject mixedInAdapter;
 
+        @SneakyThrows
         @Override
         public Object execute(final ActionInvocation currentExecution) {
 
-            try {
+//            try {
                 // it's possible that an event handler changes these en-route
                 // so we take a non-final copy
                 Can<ManagedObject> argumentAdapters = this.argumentAdapters;
@@ -283,27 +281,27 @@ implements ImperativeFacet {
                 }
                 return UnwrapUtil.single(resultAdapterPossiblyCloned);
 
-            } catch (Exception e) {
-
-                final Consumer<RecoverableException> recovery = recoverableException->{
-
-                    if (!getTransactionState().canCommit()) {
-                        // something severe has happened to the underlying transaction;
-                        // so escalate this exception to be non-recoverable
-                        final Throwable recoverableExceptionCause = recoverableException.getCause();
-                        Throwable nonRecoverableCause = recoverableExceptionCause != null
-                                ? recoverableExceptionCause
-                                        : recoverableException;
-
-                        // trim to first 300 chars
-                        final String message = trim(nonRecoverableCause.getMessage(), 300);
-
-                        throw new NonRecoverableException(message, nonRecoverableCause);
-                    }
-                };
-
-                return ThrowableExtensions.handleInvocationException(e, method.toString(), recovery);
-            }
+//            } catch (Exception e) {
+//
+//                final Consumer<RecoverableException> recovery = recoverableException->{
+//
+//                    if (!getTransactionState().canCommit()) {
+//                        // something severe has happened to the underlying transaction;
+//                        // so escalate this exception to be non-recoverable
+//                        final Throwable recoverableExceptionCause = recoverableException.getCause();
+//                        Throwable nonRecoverableCause = recoverableExceptionCause != null
+//                                ? recoverableExceptionCause
+//                                        : recoverableException;
+//
+//                        // trim to first 300 chars
+//                        final String message = trim(nonRecoverableCause.getMessage(), 300);
+//
+//                        throw new NonRecoverableException(message, nonRecoverableCause);
+//                    }
+//                };
+//
+//                return ThrowableExtensions.handleInvocationException(e, method.toString(), recovery);
+//            }
         }
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterOrClearFacetForDomainEventAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterOrClearFacetForDomainEventAbstract.java
index 5df5f23..e0a4f73 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterOrClearFacetForDomainEventAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterOrClearFacetForDomainEventAbstract.java
@@ -149,7 +149,7 @@ extends SingleValueFacetAbstract<Class<? extends PropertyDomainEvent<?,?>>> {
             final InteractionInitiatedBy interactionInitiatedBy) {
 
         return getTransactionService()
-                .executeWithinTransaction(() ->
+                .callWithinCurrentTransactionElseCreateNew(() ->
                     doSetOrClearProperty(
                             style, 
                             owningProperty, 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/query/ObjectBulkLoader_builtinHandlers.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/query/ObjectBulkLoader_builtinHandlers.java
index 9b73281..bb14a64 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/query/ObjectBulkLoader_builtinHandlers.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/query/ObjectBulkLoader_builtinHandlers.java
@@ -87,7 +87,7 @@ final class ObjectBulkLoader_builtinHandlers {
             val entityFacet = spec.getFacet(EntityFacet.class);
             if(entityFacet==null) {
                 throw _Exceptions.illegalArgument(
-                        "ObjectSpecification is missing an EntityFacet: %s", spec);
+                        "ObjectSpecification is missing an EntityFacet: %s", spec.getCorrespondingClass());
             }
             
             val entities = entityFacet.fetchByQuery(spec, objectQuery.getQuery());
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java
index c6db66f..04a97b1 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java
@@ -150,7 +150,7 @@ public class CommandExecutorServiceDefault implements CommandExecutorService {
 
         copyStartedAtFromInteractionExecution(commandUpdater);
 
-        val result = transactionService.executeWithinTransaction(
+        val result = transactionService.callWithinCurrentTransactionElseCreateNew(
             () -> sudoPolicy == SudoPolicy.SWITCH
                 ? sudoService.call(
                         context->context.withUser(UserMemento.ofName(dto.getUser())),
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefault.java
index 0cc83ac..cabec81 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefault.java
@@ -578,7 +578,7 @@ public class WrapperFactoryDefault implements WrapperFactory {
                 val childCommand = interactionContextProvider.get().currentInteractionElseFail().getCommand();
                 childCommand.updater().setParent(parentCommand);
                 return transactionService
-                        .executeWithinTransaction(() -> {
+                        .callWithinCurrentTransactionElseCreateNew(() -> {
                         val bookmark = commandExecutorService.executeCommand(commandDto, CommandOutcomeHandler.NULL);
                         if (bookmark == null) {
                             return null;
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/xactn/TransactionServiceSpring.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/xactn/TransactionServiceSpring.java
index 7edef00..30ef4a4 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/xactn/TransactionServiceSpring.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/xactn/TransactionServiceSpring.java
@@ -16,13 +16,12 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package org.apache.isis.core.runtimeservices.xactn;
 
 import java.util.List;
+import java.util.Optional;
 import java.util.concurrent.Callable;
 
-import javax.annotation.Nonnull;
 import javax.inject.Inject;
 import javax.inject.Named;
 
@@ -31,8 +30,9 @@ import org.springframework.context.annotation.Primary;
 import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.TransactionDefinition;
 import org.springframework.transaction.TransactionStatus;
-import org.springframework.transaction.support.TransactionCallback;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
 import org.springframework.transaction.support.TransactionTemplate;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
@@ -41,12 +41,9 @@ import org.apache.isis.applib.services.xactn.TransactionService;
 import org.apache.isis.applib.services.xactn.TransactionState;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.functional.Result;
+import org.apache.isis.commons.internal.assertions._Assert;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
-import org.apache.isis.core.transaction.integration.IsisTransactionAspectSupport;
-import org.apache.isis.core.transaction.integration.IsisTransactionObject;
 
-import lombok.NonNull;
-import lombok.SneakyThrows;
 import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
@@ -58,129 +55,139 @@ import lombok.extern.log4j.Log4j2;
 @Log4j2
 public class TransactionServiceSpring implements TransactionService {
 
-    private final PlatformTransactionManager platformTransactionManager;
-
-    // single TransactionTemplate shared amongst all methods in this instance
-    private final TransactionTemplate transactionTemplate;
+    private final Can<PlatformTransactionManager> platformTransactionManagers;
 
     @Inject
     public TransactionServiceSpring(List<PlatformTransactionManager> platformTransactionManagers) {
-        this.platformTransactionManager = 
-                _GlobalPlatformTransactionManager.of(Can.ofCollection(platformTransactionManagers));
-        
-        log.info("platformTransactionManagers: {}", platformTransactionManager);
-        
-        this.transactionTemplate = new TransactionTemplate(platformTransactionManager);
+        this.platformTransactionManagers = Can.ofCollection(platformTransactionManagers);
+        log.info("PlatformTransactionManagers: {}", platformTransactionManagers);
     }
 
+    // -- SPRING INTEGRATION
+    
     @Override
-    public void flushTransaction() {
+    public <T> Result<T> callTransactional(TransactionDefinition def, Callable<T> callable) {
 
-        val txObject = currentTransactionObject(WarnIfNonePolicy.IGNORE);
-
-        if(txObject==null) {
-            return;
-        }
-
-        log.debug("about to flush tx");
-        txObject.flush();
-    }
-
-    @Override
-    public TransactionId currentTransactionId() {
-
-        val txObject = currentTransactionObject(WarnIfNonePolicy.IGNORE);
-
-        if(txObject==null) {
-            return null;
-        }
-
-        log.debug("about to get current tx-id");
-        return txObject.getTransactionId();
-    }
-
-    @Override @Nonnull
-    public TransactionState currentTransactionState() {
-
-        val txObject = currentTransactionObject(WarnIfNonePolicy.IGNORE);
+        val txManager = transactionManagerForElseFail(def);
+        
+        val tx = txManager.getTransaction(def);
 
-        if(txObject==null || txObject.getCurrentTransaction()==null) {
-            return TransactionState.NONE;
+        val result = Result.ofNullable(callable);
+        
+        if(result.isFailure()) {
+            txManager.rollback(tx);
+        } else {
+            txManager.commit(tx);
         }
 
-        val state = txObject.getCurrentTransaction().getTransactionState();
-        return state != null
-                ? state
-                        : TransactionState.NONE;
+        return result;
     }
-
+    
     @Override
     public void nextTransaction() {
-        val status = platformTransactionManager.getTransaction(transactionTemplate);
-        if(status.isCompleted()) {
+        
+        val txManager = singletonTransactionManagerElseFail(); 
+        val txTemplate = new TransactionTemplate(txManager);
+        txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
+
+        // either reuse existing or create new
+        val txStatus = txManager.getTransaction(txTemplate);
+        if(txStatus.isNewTransaction()) {
+            // we have created a new transaction, so we are done
             return;
         }
-        if(status.isRollbackOnly()) {
-            platformTransactionManager.rollback(status);
+        // we are reusing an exiting transaction, so end it and create a new one afterwards
+        if(txStatus.isRollbackOnly()) {
+            txManager.rollback(txStatus);
         } else {
-            platformTransactionManager.commit(status);
+            txManager.commit(txStatus);
         }
         // begins a new transaction
-        platformTransactionManager.getTransaction(transactionTemplate);
+        val txStatus2 = txManager.getTransaction(txTemplate);
+        _Assert.assertTrue(txStatus2.isNewTransaction()); //XXX remove once known to be always correct
+    }
+    
+    @Override
+    public void flushTransaction() {
+        log.debug("about to flush tx");
+        currentTransactionStatus()
+            .ifPresent(TransactionStatus::flush);
     }
 
     @Override
-    public <T> Result<T> executeWithinTransaction(final @NonNull Callable<T> callable) {
+    public TransactionId currentTransactionId() {
+        System.err.println("currentTransactionId:" + currentTransactionStatus().getClass().getName());
+        return TransactionId.empty();
+    }
 
-        return Result.ofNullable(()->{
+    @Override
+    public TransactionState currentTransactionState() {
+
+        return currentTransactionStatus()
+        .map(txStatus->{
+        
+            if(txStatus.isNewTransaction()) {
+                return txStatus.isRollbackOnly()
+                        ? TransactionState.MUST_ABORT
+                        : TransactionState.IN_PROGRESS;
+            }
 
-            if(currentTransactionState() != TransactionState.NONE) {
-                val t = callable.call();
-                flushTransaction();
-                return t;
+            if(txStatus.isCompleted()) {
+                return txStatus.isRollbackOnly()
+                        ? TransactionState.ABORTED
+                        : TransactionState.COMMITTED;
             }
             
-            return executeWithinNewTransaction(callable);
+            throw _Exceptions.unexpectedCodeReach();
             
-        });
+        })
+        .orElse(TransactionState.NONE);
     }
-
+    
     // -- HELPER
-
-    enum WarnIfNonePolicy {
-        IGNORE,
-        LOG
-    }
-
-    private <T> T executeWithinNewTransaction(Callable<T> callable) {
-
-        return transactionTemplate.execute(new TransactionCallback<T>() {
-            // the code in this method executes in a transactional context
-            @SneakyThrows
-            @Override
-            public T doInTransaction(TransactionStatus status) {
-                return callable.call();
+    
+    private PlatformTransactionManager transactionManagerForElseFail(TransactionDefinition def) {
+        if(def instanceof TransactionTemplate) {
+            val txManager = ((TransactionTemplate)def).getTransactionManager();
+            if(txManager!=null) {
+                return txManager;
             }
-        });
+        }
+        return platformTransactionManagers.getSingleton()
+                .orElseThrow(()->
+                    platformTransactionManagers.getCardinality().isMultiple()
+                        ? _Exceptions.illegalState("Multiple PlatformTransactionManagers are configured, "
+                                + "make sure a PlatformTransactionManager is provided via the TransactionTemplate argument.")
+                        : _Exceptions.illegalState("Needs a PlatformTransactionManager."));
     }
     
-    private IsisTransactionObject currentTransactionObject(WarnIfNonePolicy warnIfNonePolicy) {
+    private PlatformTransactionManager singletonTransactionManagerElseFail() {
+        return platformTransactionManagers.getSingleton()
+                .orElseThrow(()->
+                    platformTransactionManagers.getCardinality().isMultiple()
+                        ? _Exceptions.illegalState("Multiple PlatformTransactionManagers are configured, "
+                                + "cannot reason about which one to use.")
+                        : _Exceptions.illegalState("Needs a PlatformTransactionManager."));
+    }
 
-        val txObject = IsisTransactionAspectSupport.currentTransactionObject().orElse(null);
+    private Optional<TransactionStatus> currentTransactionStatus() {
+        
+        val txManager = singletonTransactionManagerElseFail();
+        val txTemplate = new TransactionTemplate(txManager);
+        txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_MANDATORY);
 
-        if(txObject==null) {
-            if(warnIfNonePolicy == WarnIfNonePolicy.LOG) {
-                log.warn("no current txStatus present");
-                _Exceptions.dumpStackTrace(System.out, 0, 1000);
-            }
-            return null;
+        // not strictly required, but to prevent stack-trace creation later on
+        if(!TransactionSynchronizationManager.isActualTransactionActive()) {
+            return Optional.empty();
         }
-
-        return txObject;
-
+        
+        // get current transaction else throw an exception
+        return Result.of(()->
+                //XXX creating stack-traces is expensive
+                txManager.getTransaction(txTemplate))
+                .value();
+        
     }
 
 
-
-
 }
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/xactn/_GlobalPlatformTransactionManager.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/xactn/_GlobalPlatformTransactionManager.java
deleted file mode 100644
index ca1714f..0000000
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/xactn/_GlobalPlatformTransactionManager.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.core.runtimeservices.xactn;
-
-import java.util.stream.Collectors;
-
-import org.springframework.transaction.PlatformTransactionManager;
-import org.springframework.transaction.TransactionDefinition;
-import org.springframework.transaction.TransactionException;
-import org.springframework.transaction.TransactionStatus;
-
-import org.apache.isis.commons.collections.Can;
-
-import lombok.RequiredArgsConstructor;
-
-@RequiredArgsConstructor(staticName = "of")
-final class _GlobalPlatformTransactionManager implements PlatformTransactionManager {
-
-    private final Can<PlatformTransactionManager> localPlatformTransactionManagers;
-    
-    @Override
-    public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
-        return localPlatformTransactionManagers.getFirstOrFail().getTransaction(definition);
-    }
-
-    @Override
-    public void commit(TransactionStatus status) throws TransactionException {
-        localPlatformTransactionManagers.getFirstOrFail().commit(status);
-    }
-
-    @Override
-    public void rollback(TransactionStatus status) throws TransactionException {
-        localPlatformTransactionManagers.getFirstOrFail().rollback(status);
-    }
-
-    @Override
-    public String toString() {
-        return String.format("local PlatformTransactionManagers [%s]", 
-                localPlatformTransactionManagers
-                .stream()
-                .map(PlatformTransactionManager::getClass)
-                .map(Class::getSimpleName)
-                .collect(Collectors.joining(", ")));
-    }
-    
-}
diff --git a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/jobcallables/IsTickingClockInitialized.java b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/jobcallables/IsTickingClockInitialized.java
index 2390c2a..f31972e 100644
--- a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/jobcallables/IsTickingClockInitialized.java
+++ b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/jobcallables/IsTickingClockInitialized.java
@@ -34,7 +34,7 @@ public class IsTickingClockInitialized implements Callable<Boolean> {
 
     @Override
     public Boolean call() {
-        return transactionService.executeWithinTransaction(
+        return transactionService.callWithinCurrentTransactionElseCreateNew(
                 () -> tickingClockService.isInitialized())
                 .nullableOrElseFail();
     }
diff --git a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/jobcallables/ReplicateAndRunCommands.java b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/jobcallables/ReplicateAndRunCommands.java
index cb44473..cc40bd6 100644
--- a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/jobcallables/ReplicateAndRunCommands.java
+++ b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/jobcallables/ReplicateAndRunCommands.java
@@ -107,7 +107,7 @@ public class ReplicateAndRunCommands implements Callable<SecondaryStatus> {
                 val commandDtos = commandFetcher.fetchCommand(hwm);
                 commandsToReplay = commandDtos.stream()
                         .map(dto ->
-                                transactionService.executeWithinTransaction(
+                                transactionService.callWithinCurrentTransactionElseCreateNew(
                                     () -> commandJdoRepository.saveForReplay(dto))
                                 .nullableOrElseFail()
                         ).collect(Collectors.toList());
@@ -147,7 +147,7 @@ public class ReplicateAndRunCommands implements Callable<SecondaryStatus> {
             //
             val parent = commandJdo;
             val childCommands =
-                    transactionService.executeWithinTransaction(
+                    transactionService.callWithinCurrentTransactionElseCreateNew(
                             () -> commandJdoRepository.findByParent(parent))
                     .nullableOrElseFail();
             for (val childCommand : childCommands) {
@@ -164,13 +164,13 @@ public class ReplicateAndRunCommands implements Callable<SecondaryStatus> {
     }
 
     private ReplayState executeCommandInTranAndAnalyse(final CommandJdo commandJdo) {
-        transactionService.executeWithinTransaction(
+        transactionService.runWithinCurrentTransactionElseCreateNew(
                 () -> {
                     commandExecutorService.executeCommand(
                         CommandExecutorService.SudoPolicy.SWITCH, commandJdo.getCommandDto(), commandJdo.outcomeHandler());
                 });
 
-        transactionService.executeWithinTransaction(() -> {
+        transactionService.runWithinCurrentTransactionElseCreateNew(() -> {
             analysisService.analyse(commandJdo);
         });
 
@@ -180,7 +180,9 @@ public class ReplicateAndRunCommands implements Callable<SecondaryStatus> {
 
     private boolean isRunning() {
         return controller
-                .map( control -> transactionService.executeWithinTransaction(control::getState).nullableOrElseFail())
+                .map( control -> transactionService
+                        .callWithinCurrentTransactionElseCreateNew(control::getState)
+                        .nullableOrElseFail())
                 .map(state -> state == ReplayCommandExecutionController.State.RUNNING)
             // if no controller implementation provided, then just continue
             .orElse(true);
diff --git a/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/config/DnSettings.java b/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/config/DnSettings.java
index 5b2a004..00a2b0f 100644
--- a/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/config/DnSettings.java
+++ b/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/config/DnSettings.java
@@ -18,17 +18,23 @@
  */
 package org.apache.isis.persistence.jdo.datanucleus.config;
 
+import java.util.HashMap;
 import java.util.Map;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 
+import org.datanucleus.PropertyNames;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.context.annotation.Primary;
 import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
+import org.apache.isis.commons.internal.collections._Maps;
+
+import lombok.val;
+import lombok.extern.log4j.Log4j2;
 
 /**
  * @since 2.0
@@ -38,13 +44,81 @@ import org.apache.isis.applib.annotation.OrderPrecedence;
 @Order(OrderPrecedence.EARLY)
 @Primary
 @Qualifier("Default")
+@Log4j2
 public class DnSettings {
 
     @Inject @Named("dn-settings") 
     private Map<String, String> dnSettings;
     
+    private final Object lock = new Object();
+    private boolean amended = false;
+    
     public Map<String, String> getAsMap() {
+        synchronized(lock) {
+            if(!amended) {
+                addDataNucleusPropertiesAsRequired();
+                amended = true;
+            }
+        }
         return dnSettings;
     }
     
+    public Map<String, Object> getAsProperties() {
+        return _Maps.mapValues(getAsMap(), HashMap::new, Object.class::cast);
+    }
+    
+    // -- HELPER
+    
+    private void addDataNucleusPropertiesAsRequired() {
+        
+        val props = dnSettings;
+
+        String connectionFactoryName = (String) props.get(PropertyNames.PROPERTY_CONNECTION_FACTORY_NAME);
+        if(connectionFactoryName != null) {
+            String connectionFactory2Name = (String) props.get(PropertyNames.PROPERTY_CONNECTION_FACTORY2_NAME);
+            String transactionType = (String) props.get("javax.jdo.option.TransactionType");
+            // extended logging
+            if(transactionType == null) {
+                log.info("found config properties to use non-JTA JNDI datasource ({})", connectionFactoryName);
+                if(connectionFactory2Name != null) {
+                    log.warn("found config properties to use non-JTA JNDI datasource ({}); second '-nontx' JNDI datasource also configured but will not be used ({})", connectionFactoryName, connectionFactory2Name);
+                }
+            } else {
+                log.info("found config properties to use JTA JNDI datasource ({})", connectionFactoryName);
+            }
+            if(connectionFactory2Name == null) {
+                // JDO/DN itself will (probably) throw an exception
+                log.error("found config properties to use JTA JNDI datasource ({}) but config properties for second '-nontx' JNDI datasource were *not* found", connectionFactoryName);
+            } else {
+                log.info("... and config properties for second '-nontx' JNDI datasource also found; {}", connectionFactory2Name);
+            }
+            // nothing further to do
+        } else {
+            // use JDBC connection properties; put if not present
+
+            putIfNotPresent(props, "javax.jdo.option.ConnectionDriverName", "org.hsqldb.jdbcDriver");
+            putIfNotPresent(props, "javax.jdo.option.ConnectionURL", "jdbc:hsqldb:mem:test");
+            putIfNotPresent(props, "javax.jdo.option.ConnectionUserName", "sa");
+            putIfNotPresent(props, "javax.jdo.option.ConnectionPassword", "");
+
+            if(log.isInfoEnabled()) {
+                log.info("using JDBC connection '{}'", 
+                        props.get("javax.jdo.option.ConnectionURL"));
+            }
+        }
+        
+    }
+
+    private static void putIfNotPresent(
+            final Map<String, String> props,
+            final String key,
+            final String value) {
+        
+        if(!props.containsKey(key)) {
+            props.put(key, value);
+        }
+    }
+
+
+    
 }
diff --git a/persistence/jdo/integration/pom.xml b/persistence/jdo/integration/pom.xml
index bcf21eb..056fd4b 100644
--- a/persistence/jdo/integration/pom.xml
+++ b/persistence/jdo/integration/pom.xml
@@ -68,6 +68,10 @@
 			<artifactId>isis-persistence-jdo-datanucleus</artifactId>
 		</dependency>
 
+		<dependency>
+			<groupId>org.apache.isis.persistence</groupId>
+			<artifactId>isis-persistence-jdo-spring</artifactId>
+		</dependency>
 
 		<!-- TESTING -->
 		
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/IsisModuleJdoIntegration.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/IsisModuleJdoIntegration.java
index 2ef182f..b66820e 100644
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/IsisModuleJdoIntegration.java
+++ b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/IsisModuleJdoIntegration.java
@@ -18,18 +18,25 @@
  */
 package org.apache.isis.persistence.jdo.integration;
 
+import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
+import org.springframework.context.annotation.Primary;
 
+import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.runtime.IsisModuleCoreRuntime;
 import org.apache.isis.persistence.jdo.applib.IsisModulePersistenceJdoApplib;
 import org.apache.isis.persistence.jdo.datanucleus.IsisModuleJdoProviderDatanucleus;
+import org.apache.isis.persistence.jdo.datanucleus.config.DnSettings;
 import org.apache.isis.persistence.jdo.integration.jdosupport.IsisJdoSupportDN5;
 import org.apache.isis.persistence.jdo.integration.lifecycles.JdoPersistenceLifecycleService;
 import org.apache.isis.persistence.jdo.integration.metamodel.JdoIntegrationProgrammingModel;
 import org.apache.isis.persistence.jdo.integration.persistence.JdoPersistenceSessionFactory5;
-import org.apache.isis.persistence.jdo.integration.transaction.IsisPlatformTransactionManagerForJdo;
 import org.apache.isis.persistence.jdo.metamodel.IsisModuleJdoMetamodel;
+import org.apache.isis.persistence.jdo.spring.integration.JdoTransactionManager;
+import org.apache.isis.persistence.jdo.spring.integration.LocalPersistenceManagerFactoryBean;
+
+import lombok.val;
 
 @Configuration
 @Import({
@@ -43,11 +50,26 @@ import org.apache.isis.persistence.jdo.metamodel.IsisModuleJdoMetamodel;
         JdoIntegrationProgrammingModel.class,
         
         IsisJdoSupportDN5.class,
-        IsisPlatformTransactionManagerForJdo.class,
+        //IsisPlatformTransactionManagerForJdo.class,
         JdoPersistenceLifecycleService.class,
         JdoPersistenceSessionFactory5.class,
 
 })
 public class IsisModuleJdoIntegration {
     
+    @Bean 
+    public LocalPersistenceManagerFactoryBean getLocalPersistenceManagerFactoryBean(
+            final MetaModelContext metaModelContext,
+            final DnSettings dnSettings) {
+        
+        val lpmfBean = new LocalPersistenceManagerFactoryBean();
+        lpmfBean.setJdoPropertyMap(dnSettings.getAsProperties());
+        return lpmfBean; 
+    }
+
+    @Bean @Primary
+    public JdoTransactionManager getJdoTransactionManager(LocalPersistenceManagerFactoryBean localPmfBean) {
+        return new JdoTransactionManager(localPmfBean.getObject());
+    }
+    
 }
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/lifecycles/JdoPersistenceLifecycleService.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/lifecycles/JdoPersistenceLifecycleService.java
index 8dd8866..67a376b 100644
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/lifecycles/JdoPersistenceLifecycleService.java
+++ b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/lifecycles/JdoPersistenceLifecycleService.java
@@ -37,6 +37,8 @@ import org.apache.isis.core.interaction.events.IsisInteractionLifecycleEvent;
 import org.apache.isis.core.interaction.session.InteractionSession;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.runtime.events.AppLifecycleEvent;
+import org.apache.isis.persistence.jdo.datanucleus.config.DnSettings;
+import org.apache.isis.persistence.jdo.integration.persistence.DnApplication;
 import org.apache.isis.persistence.jdo.integration.persistence.JdoPersistenceSession;
 import org.apache.isis.persistence.jdo.integration.persistence.JdoPersistenceSessionFactory;
 
@@ -54,6 +56,7 @@ public class JdoPersistenceLifecycleService {
     @Inject MetaModelContext metaModelContext;
     @Inject JdoPersistenceSessionFactory persistenceSessionFactory;
     @Inject IsisBeanTypeRegistry isisBeanTypeRegistry;
+    @Inject DnSettings dnSettings;
 
     @PostConstruct
     public void postConstr() {
@@ -70,10 +73,9 @@ public class JdoPersistenceLifecycleService {
 
         switch (event) {
         case PRE_METAMODEL:
-            create();
             break;
         case POST_METAMODEL:
-            init();
+            new DnApplication(metaModelContext, dnSettings); // creates schema
             break;
 
         default:
@@ -124,14 +126,6 @@ public class JdoPersistenceLifecycleService {
         return Optional.ofNullable(interactionSession)
                 .map(session->session.getAttribute(JdoPersistenceSession.class));
     }
-    
-    private void create() {
-        persistenceSessionFactory.init(metaModelContext);
-    }
-
-    private void init() {
-        persistenceSessionFactory.catalogNamedQueries();
-    }
 
 
 }
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/metamodel/facets/entity/JdoEntityFacet.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/metamodel/facets/entity/JdoEntityFacet.java
index 1758b9c..9ef26ec 100644
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/metamodel/facets/entity/JdoEntityFacet.java
+++ b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/metamodel/facets/entity/JdoEntityFacet.java
@@ -245,7 +245,7 @@ implements EntityFacet {
         log.debug("about to persist entity {}", pojo);
         
         getTransactionalProcessor()
-        .executeWithinTransaction(()->{pm.makePersistent(pojo);})
+        .runWithinCurrentTransactionElseCreateNew(()->pm.makePersistent(pojo))
         .nullableOrElseFail();
         
         //TODO integrate with entity change tracking
@@ -267,7 +267,7 @@ implements EntityFacet {
         log.debug("about to delete entity {}", pojo);
         
         getTransactionalProcessor()
-        .executeWithinTransaction(()->{pm.deletePersistent(pojo);})
+        .runWithinCurrentTransactionElseCreateNew(()->pm.deletePersistent(pojo))
         .nullableOrElseFail();
         
         //TODO integrate with entity change tracking
@@ -287,7 +287,7 @@ implements EntityFacet {
         log.debug("about to refresh entity {}", pojo);
         
         getTransactionalProcessor()
-        .executeWithinTransaction(()->{pm.refresh(pojo);})
+        .runWithinCurrentTransactionElseCreateNew(()->pm.refresh(pojo))
         .nullableOrElseFail();
         
         //TODO integrate with entity change tracking
@@ -337,14 +337,14 @@ implements EntityFacet {
     private JdoPersistenceSession getJdoPersistenceSession() {
         return isisInteractionTrackerLazy.get().currentInteractionSession()
                 .map(interactionSession->interactionSession.getAttribute(JdoPersistenceSession.class))
-                .orElse(null);
+                .orElseThrow(()->_Exceptions.illegalState("no JdoPersistenceSession on current thread"));
     }
     
     // -- HELPER
     
     private Can<ManagedObject> fetchWithinTransaction(Supplier<List<?>> fetcher) {
         val fetchResultHandler = getFetchResultHandler();
-        return getTransactionalProcessor().executeWithinTransaction(
+        return getTransactionalProcessor().callWithinCurrentTransactionElseCreateNew(
                 ()->_NullSafe.stream(fetcher.get())
                     .map(fetchedObject->adopt(fetchResultHandler, fetchedObject))
                     .collect(Can.toCan()))
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/DnApplication.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/DnApplication.java
new file mode 100644
index 0000000..29e8b7b
--- /dev/null
+++ b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/DnApplication.java
@@ -0,0 +1,77 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.persistence.jdo.integration.persistence;
+
+import org.apache.isis.commons.internal.base._NullSafe;
+import org.apache.isis.core.config.beans.IsisBeanTypeRegistry;
+import org.apache.isis.core.metamodel.context.MetaModelContext;
+import org.apache.isis.persistence.jdo.datanucleus.config.DnSettings;
+import org.apache.isis.persistence.jdo.integration.config.JdoEntityTypeRegistry;
+
+import lombok.val;
+import lombok.extern.log4j.Log4j2;
+
+@Log4j2
+public class DnApplication {
+    
+    private _DnApplicationComponents dnApplicationComponents;
+    private final JdoEntityTypeRegistry jdoEntityTypeRegistry = new JdoEntityTypeRegistry();
+    
+    public DnApplication(
+            final MetaModelContext metaModelContext,
+            final DnSettings dnSettings) {
+        
+        dnApplicationComponents = createDataNucleusApplicationComponents(
+                metaModelContext,
+                dnSettings);
+    }
+    
+    public void shutdown() {
+        dnApplicationComponents.shutdown();
+    }
+    
+    // -- HELPER
+    
+    private _DnApplicationComponents createDataNucleusApplicationComponents(
+            final MetaModelContext metaModelContext,
+            final DnSettings dnSettings) {
+        
+        val configuration = metaModelContext.getConfiguration();
+        val isisBeanTypeRegistry = metaModelContext.getServiceRegistry()
+                .lookupServiceElseFail(IsisBeanTypeRegistry.class);
+        
+        val classesToBePersisted = jdoEntityTypeRegistry.getEntityTypes(isisBeanTypeRegistry);
+        
+        if(log.isDebugEnabled()) {
+            log.debug("Entity types discovered:");
+            _NullSafe.stream(classesToBePersisted)
+                .forEach(entityClassName->log.debug(" - {}", entityClassName));
+        }
+
+        val dataNucleusApplicationComponents = new _DnApplicationComponents(
+                configuration,
+                dnSettings.getAsProperties(), 
+                classesToBePersisted);
+        
+        _DnApplicationComponents.catalogNamedQueries(metaModelContext, classesToBePersisted);
+        
+        return dataNucleusApplicationComponents;
+    }
+    
+}
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/JdoPersistenceSession5.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/JdoPersistenceSession5.java
index c47c051..7b1f2ae 100644
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/JdoPersistenceSession5.java
+++ b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/JdoPersistenceSession5.java
@@ -28,7 +28,6 @@ import org.apache.isis.core.transaction.changetracking.EntityChangeTracker;
 import org.apache.isis.persistence.jdo.integration.lifecycles.IsisLifecycleListener;
 import org.apache.isis.persistence.jdo.integration.lifecycles.JdoStoreLifecycleListenerForIsis;
 import org.apache.isis.persistence.jdo.integration.lifecycles.LoadLifecycleListenerForIsis;
-import org.apache.isis.persistence.jdo.integration.transaction.TxManagerInternalFactory;
 
 import lombok.Getter;
 import lombok.val;
@@ -49,7 +48,7 @@ implements
     @Getter(onMethod_ = {@Override}) private final MetaModelContext metaModelContext;
     @Getter(onMethod_ = {@Override}) private FetchResultHandler fetchResultHandler;
 
-    private final PersistenceManagerFactory jdoPersistenceManagerFactory;
+    private final PersistenceManagerFactory pmf;
     private Runnable unregisterLifecycleListeners;
 
     // -- CONSTRUCTOR
@@ -57,23 +56,22 @@ implements
     /**
      * Initialize the object store so that calls to this object store access
      * persisted objects and persist changes to the object that are saved.
+     * @param pmf 
      */
     public JdoPersistenceSession5(
-            final MetaModelContext metaModelContext,
-            final PersistenceManagerFactory jdoPersistenceManagerFactory) {
+            final MetaModelContext metaModelContext, 
+            final PersistenceManagerFactory pmf) {
 
         if (log.isDebugEnabled()) {
             log.debug("creating {}", this);
         }
 
         this.metaModelContext = metaModelContext;
-        this.jdoPersistenceManagerFactory = jdoPersistenceManagerFactory;
+        this.pmf = pmf;
 
         // sub-components
-        this.transactionalProcessor = TxManagerInternalFactory.newTransactionalProcessor(
-                metaModelContext, 
-                this); 
-
+        this.transactionalProcessor = metaModelContext.getTransactionService();
+                
         this.state = State.NOT_INITIALIZED;
     }
 
@@ -102,7 +100,6 @@ implements
 
     // -- OPEN
 
-
     @Override
     public void open() {
         state.ensureNotOpened();
@@ -111,8 +108,8 @@ implements
             log.debug("opening {}", this);
         }
 
-        persistenceManager = jdoPersistenceManagerFactory.getPersistenceManager();
-
+        this.persistenceManager = pmf.getPersistenceManager();
+        
         val entityChangeTracker = metaModelContext.getServiceRegistry()
                 .lookupServiceElseFail(EntityChangeTracker.class);
         
@@ -158,6 +155,17 @@ implements
         unregisterLifecycleListeners = null;
         
         try {
+            
+//            if (!participate) {
+//                
+//                val pmf = pmf;
+//                
+//                PersistenceManagerHolder pmHolder = (PersistenceManagerHolder)
+//                        TransactionSynchronizationManager.unbindResource(pmf);
+//                log.debug("Closing JDO PersistenceManager in PersistenceSession");
+//                PersistenceManagerFactoryUtils.releasePersistenceManager(pmHolder.getPersistenceManager(), pmf);
+//            }
+            
             persistenceManager.close();
         } catch(final Throwable ex) {
             // ignore
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/JdoPersistenceSessionFactory.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/JdoPersistenceSessionFactory.java
index f1c4e28..8284e15 100644
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/JdoPersistenceSessionFactory.java
+++ b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/JdoPersistenceSessionFactory.java
@@ -18,16 +18,8 @@
  */
 package org.apache.isis.persistence.jdo.integration.persistence;
 
-import org.apache.isis.core.metamodel.context.MetaModelContext;
-
 public interface JdoPersistenceSessionFactory {
 
     JdoPersistenceSession createPersistenceSession();
 
-    void init(MetaModelContext metaModelContext);
-
-    void catalogNamedQueries();
-
-    boolean isInitialized();
-
 }
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/JdoPersistenceSessionFactory5.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/JdoPersistenceSessionFactory5.java
index a73aee3..20acebe 100644
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/JdoPersistenceSessionFactory5.java
+++ b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/JdoPersistenceSessionFactory5.java
@@ -16,36 +16,22 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package org.apache.isis.persistence.jdo.integration.persistence;
 
-import java.util.Map;
 import java.util.Objects;
 
-import javax.annotation.PreDestroy;
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
-import org.datanucleus.PropertyNames;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.context.annotation.Primary;
 import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
-import org.apache.isis.commons.internal.base._Blackhole;
-import org.apache.isis.commons.internal.base._Lazy;
-import org.apache.isis.commons.internal.base._NullSafe;
-import org.apache.isis.commons.internal.collections._Maps;
-import org.apache.isis.core.config.IsisConfiguration;
-import org.apache.isis.core.config.beans.IsisBeanTypeRegistry;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
-import org.apache.isis.persistence.jdo.datanucleus.config.DnSettings;
-import org.apache.isis.persistence.jdo.integration.config.JdoEntityTypeRegistry;
-
-import lombok.val;
-import lombok.extern.log4j.Log4j2;
+import org.apache.isis.persistence.jdo.spring.integration.LocalPersistenceManagerFactoryBean;
 
 /**
  *
@@ -58,142 +44,22 @@ import lombok.extern.log4j.Log4j2;
 @Primary
 @Qualifier("JdoDN5")
 @Singleton
-@Log4j2
 public class JdoPersistenceSessionFactory5
 implements JdoPersistenceSessionFactory {
     
-    @Inject private IsisBeanTypeRegistry isisBeanTypeRegistry;
-
-    private final _Lazy<_DataNucleusApplicationComponents5> applicationComponents = 
-            _Lazy.threadSafe(this::createDataNucleusApplicationComponents);
+    @Inject private LocalPersistenceManagerFactoryBean localPmfBean;
+    @Inject private MetaModelContext metaModelContext;
     
-    private MetaModelContext metaModelContext;
-    private IsisConfiguration configuration;
-    private final JdoEntityTypeRegistry jdoEntityTypeRegistry = new JdoEntityTypeRegistry();
-
-    @Override
-    public void init(MetaModelContext metaModelContext) {
-        this.metaModelContext = metaModelContext;
-        this.configuration = metaModelContext.getConfiguration();
-        // need to eagerly build, ... must be completed before catalogNamedQueries().
-        // Why? because that method causes entity classes to be loaded which register with DN's EnhancementHelper,
-        // which are then cached in DN.  It results in our CreateSchema listener not firing.
-        _Blackhole.consume(applicationComponents.get());
-    }
-
-
-    @Override
-    public boolean isInitialized() {
-        return this.configuration != null;
-    }
-
-    private _DataNucleusApplicationComponents5 createDataNucleusApplicationComponents() {
-
-        val dnSettings = metaModelContext.getServiceRegistry().lookupServiceElseFail(DnSettings.class);
-        val datanucleusProps = addDataNucleusPropertiesAsRequired(dnSettings);
-        val classesToBePersisted = jdoEntityTypeRegistry.getEntityTypes(isisBeanTypeRegistry);
-
-        val dataNucleusApplicationComponents = new _DataNucleusApplicationComponents5(
-                configuration,
-                datanucleusProps, 
-                classesToBePersisted);
-        
-        return dataNucleusApplicationComponents;
-    }
-
-    @Override
-    public void catalogNamedQueries() {
-        val classesToBePersisted = jdoEntityTypeRegistry.getEntityTypes(isisBeanTypeRegistry);
-        
-        if(log.isDebugEnabled()) {
-            log.debug("Entity types discovered:");
-            _NullSafe.stream(classesToBePersisted)
-                .forEach(entityClassName->log.debug(" - {}", entityClassName));
-        }
-        
-        _DataNucleusApplicationComponents5.catalogNamedQueries(classesToBePersisted, 
-                metaModelContext.getSpecificationLoader());
-    }
-
-    private Map<String, Object> addDataNucleusPropertiesAsRequired(DnSettings dnSettings) {
-        
-        val props = _Maps.<String, Object>newHashMap();
-        props.putAll(dnSettings.getAsMap());
-        _ContextUtil.putMetaModelContext(props, metaModelContext);
-
-        String connectionFactoryName = (String) props.get(PropertyNames.PROPERTY_CONNECTION_FACTORY_NAME);
-        if(connectionFactoryName != null) {
-            String connectionFactory2Name = (String) props.get(PropertyNames.PROPERTY_CONNECTION_FACTORY2_NAME);
-            String transactionType = (String) props.get("javax.jdo.option.TransactionType");
-            // extended logging
-            if(transactionType == null) {
-                log.info("found config properties to use non-JTA JNDI datasource ({})", connectionFactoryName);
-                if(connectionFactory2Name != null) {
-                    log.warn("found config properties to use non-JTA JNDI datasource ({}); second '-nontx' JNDI datasource also configured but will not be used ({})", connectionFactoryName, connectionFactory2Name);
-                }
-            } else {
-                log.info("found config properties to use JTA JNDI datasource ({})", connectionFactoryName);
-            }
-            if(connectionFactory2Name == null) {
-                // JDO/DN itself will (probably) throw an exception
-                log.error("found config properties to use JTA JNDI datasource ({}) but config properties for second '-nontx' JNDI datasource were *not* found", connectionFactoryName);
-            } else {
-                log.info("... and config properties for second '-nontx' JNDI datasource also found; {}", connectionFactory2Name);
-            }
-            // nothing further to do
-        } else {
-            // use JDBC connection properties; put if not present
-
-            putIfNotPresent(props, "javax.jdo.option.ConnectionDriverName", "org.hsqldb.jdbcDriver");
-            putIfNotPresent(props, "javax.jdo.option.ConnectionURL", "jdbc:hsqldb:mem:test");
-            putIfNotPresent(props, "javax.jdo.option.ConnectionUserName", "sa");
-            putIfNotPresent(props, "javax.jdo.option.ConnectionPassword", "");
-
-            if(log.isInfoEnabled()) {
-                log.info("using JDBC connection '{}'", 
-                        props.get("javax.jdo.option.ConnectionURL"));
-            }
-        }
-        
-        return props;
-    }
-
-    private static void putIfNotPresent(
-            Map<String, Object> props,
-            String key,
-            String value) {
-        
-        if(!props.containsKey(key)) {
-            props.put(key, value);
-        }
-    }
-
-
-    @PreDestroy
-    public final void shutdown() {
-        if(!isInitialized()) {
-            return;
-        }
-        if(applicationComponents.isMemoized()) {
-            applicationComponents.get().shutdown();
-            applicationComponents.clear();
-        }
-        this.configuration = null;
-    }
-
     @Override
     public JdoPersistenceSession5 createPersistenceSession() {
 
-        Objects.requireNonNull(applicationComponents.get(),
-                () -> "PersistenceSession5 requires initialization. "+this.hashCode());
-
-        val persistenceManagerFactory =
-                applicationComponents.get().getPersistenceManagerFactory();
+        Objects.requireNonNull(localPmfBean,
+                () -> "PersistenceSessionFactory5 requires initialization. " + this.hashCode());
 
         return new JdoPersistenceSession5(
                 metaModelContext, 
-                persistenceManagerFactory);
+                localPmfBean.getObject());
     }
-
+    
 
 }
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/_ContextUtil.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/_ContextUtil.java
deleted file mode 100644
index 05382b3..0000000
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/_ContextUtil.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.persistence.jdo.integration.persistence;
-
-import java.util.Map;
-import java.util.Optional;
-
-import org.datanucleus.ExecutionContext;
-
-import org.apache.isis.core.metamodel.context.MetaModelContext;
-
-import lombok.val;
-
-/**
- * 
- * @since 2.0
- *
- */
-final class _ContextUtil {
-    
-    // required to be lower-case for DN to be accepted
-    private static final String METAMODELCONTEXT_PROPERTY_KEY = "isis.metamodelcontext"; 
-
-    public static void putMetaModelContext(
-            Map<String, Object> map, 
-            MetaModelContext metaModelContext) {
-
-        map.put(METAMODELCONTEXT_PROPERTY_KEY, metaModelContext);
-    }
-    
-    public static Optional<MetaModelContext> extractMetaModelContext(ExecutionContext ec) {
-
-        val metaModelContext = (MetaModelContext) ec.getNucleusContext()
-                .getConfiguration()
-                .getPersistenceProperties()
-                .get(METAMODELCONTEXT_PROPERTY_KEY);
-        
-        return Optional.ofNullable(metaModelContext);
-    }
-    
-}
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/_DataNucleusApplicationComponents5.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/_DnApplicationComponents.java
similarity index 95%
rename from persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/_DataNucleusApplicationComponents5.java
rename to persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/_DnApplicationComponents.java
index eb80c59..3a350b0 100644
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/_DataNucleusApplicationComponents5.java
+++ b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/_DnApplicationComponents.java
@@ -18,6 +18,8 @@
  */
 package org.apache.isis.persistence.jdo.integration.persistence;
 
+import static org.apache.isis.commons.internal.base._NullSafe.stream;
+
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
@@ -40,22 +42,20 @@ import org.apache.isis.commons.internal.collections._Maps;
 import org.apache.isis.commons.internal.context._Context;
 import org.apache.isis.commons.internal.factory._InstanceUtil;
 import org.apache.isis.core.config.IsisConfiguration;
+import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.spec.ObjectSpecId;
-import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.persistence.jdo.integration.config.DataNucleusPropertiesAware;
 import org.apache.isis.persistence.jdo.integration.lifecycles.DataNucleusLifeCycleHelper;
 import org.apache.isis.persistence.jdo.provider.metamodel.facets.object.query.JdoNamedQuery;
 import org.apache.isis.persistence.jdo.provider.metamodel.facets.object.query.JdoQueryFacet;
 
-import static org.apache.isis.commons.internal.base._NullSafe.stream;
-
 import lombok.Getter;
 import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
 @Vetoed
 @Log4j2
-final class _DataNucleusApplicationComponents5 {
+final class _DnApplicationComponents {
 
     private final Set<String> persistableClassNameSet;
     private final IsisConfiguration configuration;
@@ -63,7 +63,7 @@ final class _DataNucleusApplicationComponents5 {
 
     @Getter private PersistenceManagerFactory persistenceManagerFactory;
 
-    public _DataNucleusApplicationComponents5(
+    public _DnApplicationComponents(
             final IsisConfiguration configuration,
             final Map<String, Object> datanucleusProps,
             final Set<String> persistableClassNameSet) {
@@ -93,7 +93,6 @@ final class _DataNucleusApplicationComponents5 {
         try {
             // this is where DN will throw an exception if we pass it any config props it doesn't like the look of.
             // we want to fail, but let's make sure that the error is visible to help the developer
-            
             return JDOHelper.getPersistenceManagerFactory(datanucleusProps, _Context.getDefaultClassLoader());
         } catch(JDOUserException ex) {
             log.fatal(ex);
@@ -106,7 +105,7 @@ final class _DataNucleusApplicationComponents5 {
             final Set<String> persistableClassNameSet, 
             final Map<String, Object> datanucleusProps) {
 
-        final _DNStoreManagerType dnStoreManagerType = _DNStoreManagerType.typeOf(datanucleusProps);
+        final _DnStoreManagerType dnStoreManagerType = _DnStoreManagerType.typeOf(datanucleusProps);
 
         PersistenceManagerFactory persistenceManagerFactory;
 
@@ -224,11 +223,13 @@ final class _DataNucleusApplicationComponents5 {
     }
 
     static void catalogNamedQueries(
-            Set<String> persistableClassNames, SpecificationLoader specificationLoader) {
+            final MetaModelContext metaModelContext,
+            final Set<String> persistableClassNames) {
         
         val namedQueryByName = _Maps.<String, JdoNamedQuery>newHashMap();
         for (val persistableClassName: persistableClassNames) {
-            val spec = specificationLoader.loadSpecification(ObjectSpecId.of(persistableClassName));
+            val spec = metaModelContext.getSpecificationLoader()
+                    .loadSpecification(ObjectSpecId.of(persistableClassName));
             val jdoQueryFacet = spec.getFacet(JdoQueryFacet.class);
             if (jdoQueryFacet == null) {
                 continue;
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/_DNStoreManagerType.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/_DnStoreManagerType.java
similarity index 93%
rename from persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/_DNStoreManagerType.java
rename to persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/_DnStoreManagerType.java
index 9eea932..8ba0347 100644
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/_DNStoreManagerType.java
+++ b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/persistence/_DnStoreManagerType.java
@@ -35,14 +35,14 @@ import org.datanucleus.store.schema.SchemaAwareStoreManager;
  * 
  * @since 2.0.0-M2
  */
-enum _DNStoreManagerType {
+enum _DnStoreManagerType {
 
     SchemaAware,
     Federated, // [ahuber] not used by now
     Other
     ;
 
-    public static _DNStoreManagerType typeOf(Map<String, Object> datanucleusProps) {
+    public static _DnStoreManagerType typeOf(Map<String, Object> datanucleusProps) {
 
         if(hasSecondaryDataStore(datanucleusProps)) {
             return Federated; 
@@ -108,14 +108,14 @@ enum _DNStoreManagerType {
         return false;
     }
 
-    private static _DNStoreManagerType probe(
+    private static _DnStoreManagerType probe(
             Map<String, Object> datanucleusProps, 
-            Function<StoreManager, _DNStoreManagerType> categorizer) {
+            Function<StoreManager, _DnStoreManagerType> categorizer) {
 
         // we create a throw-away instance of PMF so that we can probe whether DN has
         // been configured with a schema-aware store manager or not.
         final JDOPersistenceManagerFactory probePmf = (JDOPersistenceManagerFactory) 
-                _DataNucleusApplicationComponents5.newPersistenceManagerFactory(datanucleusProps);
+                _DnApplicationComponents.newPersistenceManagerFactory(datanucleusProps);
 
         try {
             final PersistenceNucleusContext nucleusContext = probePmf.getNucleusContext();
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/transaction/IsisPlatformTransactionManagerForJdo.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/transaction/IsisPlatformTransactionManagerForJdoNoMore.java
similarity index 87%
rename from persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/transaction/IsisPlatformTransactionManagerForJdo.java
rename to persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/transaction/IsisPlatformTransactionManagerForJdoNoMore.java
index f395a03..4d19bdd 100644
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/transaction/IsisPlatformTransactionManagerForJdo.java
+++ b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/transaction/IsisPlatformTransactionManagerForJdoNoMore.java
@@ -18,19 +18,11 @@
  */
 package org.apache.isis.persistence.jdo.integration.transaction;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.context.annotation.Primary;
-import org.springframework.core.annotation.Order;
-import org.springframework.stereotype.Service;
 import org.springframework.transaction.TransactionDefinition;
 import org.springframework.transaction.TransactionException;
 import org.springframework.transaction.support.AbstractPlatformTransactionManager;
 import org.springframework.transaction.support.DefaultTransactionStatus;
 
-import org.apache.isis.applib.annotation.OrderPrecedence;
 import org.apache.isis.applib.services.eventbus.EventBusService;
 import org.apache.isis.commons.internal.context._Context;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
@@ -46,24 +38,23 @@ import org.apache.isis.core.transaction.integration.IsisTransactionAspectSupport
 import org.apache.isis.core.transaction.integration.IsisTransactionObject;
 import org.apache.isis.core.transaction.integration.IsisTransactionObject.IsisInteractionScopeType;
 
-import lombok.RequiredArgsConstructor;
 import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
-@Service
-@Named("isisJdoDn5.IsisPlatformTransactionManagerForJdo")
-@Order(OrderPrecedence.MIDPOINT)
-@Primary
-@Qualifier("JdoDN5")
-@RequiredArgsConstructor(onConstructor_ = {@Inject})
+//@Service
+//@Named("isisJdoDn5.IsisPlatformTransactionManagerForJdo")
+//@Order(OrderPrecedence.MIDPOINT)
+//@Primary
+//@Qualifier("JdoDN5")
+//@RequiredArgsConstructor(onConstructor_ = {@Inject})
 @Log4j2
-public class IsisPlatformTransactionManagerForJdo extends AbstractPlatformTransactionManager {
+public class IsisPlatformTransactionManagerForJdoNoMore extends AbstractPlatformTransactionManager {
 
     private static final long serialVersionUID = 1L;
 
-    private final InteractionFactory isisInteractionFactory;
-    private final EventBusService eventBusService;
-    private final InteractionTracker isisInteractionTracker;
+    private InteractionFactory isisInteractionFactory;
+    private EventBusService eventBusService;
+    private InteractionTracker isisInteractionTracker;
 
     @Override
     protected Object doGetTransaction() throws TransactionException {
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/transaction/TxManagerInternalFactory.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/transaction/TxManagerInternalFactory.java
index deefb58..a48e6c4 100644
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/transaction/TxManagerInternalFactory.java
+++ b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/transaction/TxManagerInternalFactory.java
@@ -39,7 +39,7 @@ public class TxManagerInternalFactory {
         isisInteractionTracker.currentInteractionSession()
                 .map(interaction->interaction.putAttribute(_TxProcessor.class, txMan));
         
-        return txMan;
+        return mmc.getTransactionService();
         
     }
 
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/transaction/_TxProcessor.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/transaction/_TxProcessor.java
index ebaf294..7624451 100644
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/transaction/_TxProcessor.java
+++ b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/transaction/_TxProcessor.java
@@ -16,19 +16,15 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package org.apache.isis.persistence.jdo.integration.transaction;
 
-import java.util.concurrent.Callable;
 import java.util.function.Supplier;
 
 import javax.enterprise.inject.Vetoed;
 
 import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.applib.services.iactn.InteractionContext;
-import org.apache.isis.applib.services.xactn.TransactionalProcessor;
 import org.apache.isis.commons.exceptions.IsisException;
-import org.apache.isis.commons.functional.Result;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.transaction.integration.IsisTransactionAspectSupport;
@@ -40,9 +36,7 @@ import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
 @Vetoed @Log4j2
-class _TxProcessor 
-implements 
-    TransactionalProcessor {
+class _TxProcessor {
 
     // -- constructor, fields
 
@@ -319,11 +313,6 @@ implements
         }
     }
     
-    @Override
-    public <T> Result<T> executeWithinTransaction(Callable<T> callable) {
-        return mmc.getTransactionService().executeWithinTransaction(callable);
-    }
-    
     // -- HELPER
     
     private _Tx getCurrentTransaction() {
diff --git a/persistence/jdo/lightweight/src/main/java/org/apache/isis/persistence/jdo/lightweight/IsisModuleJdoLightweight.java b/persistence/jdo/lightweight/src/main/java/org/apache/isis/persistence/jdo/lightweight/IsisModuleJdoLightweight.java
index 232979f..0d51281 100644
--- a/persistence/jdo/lightweight/src/main/java/org/apache/isis/persistence/jdo/lightweight/IsisModuleJdoLightweight.java
+++ b/persistence/jdo/lightweight/src/main/java/org/apache/isis/persistence/jdo/lightweight/IsisModuleJdoLightweight.java
@@ -18,7 +18,6 @@
  */
 package org.apache.isis.persistence.jdo.lightweight;
 
-import java.util.HashMap;
 import java.util.List;
 
 import javax.inject.Named;
@@ -85,7 +84,7 @@ public class IsisModuleJdoLightweight {
         
         val tapmfProxy = new TransactionAwarePersistenceManagerFactoryProxy();
         tapmfProxy.setTargetPersistenceManagerFactory(pmf);
-        tapmfProxy.setAllowCreate(true);
+        tapmfProxy.setAllowCreate(false);
         return tapmfProxy;
     }
     
@@ -93,17 +92,14 @@ public class IsisModuleJdoLightweight {
     public LocalPersistenceManagerFactoryBean getLocalPersistenceManagerFactoryBean(
             final DnSettings dnSettings) {
         
-        val jdoPropertyMap = new HashMap<String, Object>();
-        dnSettings.getAsMap().forEach(jdoPropertyMap::put);
-        
         val lpmfBean = new LocalPersistenceManagerFactoryBean();
-        lpmfBean.setJdoPropertyMap(jdoPropertyMap);
+        lpmfBean.setJdoPropertyMap(dnSettings.getAsProperties());
         return lpmfBean; 
     }
 
     @Bean @Primary
-    public JdoTransactionManager getJdoTransactionManager(TransactionAwarePersistenceManagerFactoryProxy tapmfProxy) {
-        return new JdoTransactionManager(tapmfProxy.getPersistenceManagerFactory());
+    public JdoTransactionManager getJdoTransactionManager(LocalPersistenceManagerFactoryBean localPmf) {
+        return new JdoTransactionManager(localPmf.getObject());
     }
     
 }
diff --git a/persistence/jdo/lightweight/src/main/java/org/apache/isis/persistence/jdo/lightweight/metamodel/facets/entity/JdoEntityFacet.java b/persistence/jdo/lightweight/src/main/java/org/apache/isis/persistence/jdo/lightweight/metamodel/facets/entity/JdoEntityFacet.java
index bb32635..190f018 100644
--- a/persistence/jdo/lightweight/src/main/java/org/apache/isis/persistence/jdo/lightweight/metamodel/facets/entity/JdoEntityFacet.java
+++ b/persistence/jdo/lightweight/src/main/java/org/apache/isis/persistence/jdo/lightweight/metamodel/facets/entity/JdoEntityFacet.java
@@ -28,11 +28,11 @@ import org.apache.isis.applib.query.NamedQuery;
 import org.apache.isis.applib.query.Query;
 import org.apache.isis.applib.services.repository.EntityState;
 import org.apache.isis.commons.collections.Can;
-import org.apache.isis.commons.internal.base._Casts;
-import org.apache.isis.commons.internal.base._Lazy;
+import org.apache.isis.commons.internal.assertions._Assert;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.collections._Maps;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.facetapi.FacetAbstract;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
@@ -40,7 +40,7 @@ import org.apache.isis.core.metamodel.facets.object.entity.EntityFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.persistence.jdo.applib.integration.JdoSupportService;
-import org.apache.isis.persistence.jdo.lightweight.metamodel.facets.entity.JdoEntityFacetFactory.JdoObjectIdSerializer;
+import org.apache.isis.persistence.jdo.datanucleus.oid.JdoObjectIdSerializer;
 import org.apache.isis.persistence.jdo.provider.entities.JdoFacetContext;
 
 import lombok.NonNull;
@@ -102,7 +102,7 @@ implements EntityFacet {
                     pojo.getClass().getName());
         }
         
-        return getObjectIdSerializer().stringify(primaryKey);
+        return JdoObjectIdSerializer.toOidIdentifier(primaryKey);
 
     }
 
@@ -111,7 +111,11 @@ implements EntityFacet {
             final @NonNull ObjectSpecification entitySpec, 
             final @NonNull String identifier) {
         
-        val primaryKey = getObjectIdSerializer().parse(identifier);
+        _Assert.assertTrue(entitySpec.isEntity());
+        
+        val rootOid = Oid.Factory.root(entitySpec.getSpecId(), identifier);
+        
+        val primaryKey = JdoObjectIdSerializer.toJdoObjectId(entitySpec, rootOid);
         val persistenceManager = getPersistenceManager();
         val entity = persistenceManager.getObjectById(entityClass, primaryKey); 
 
@@ -252,17 +256,6 @@ implements EntityFacet {
     
     // -- OBJECT ID SERIALIZATION
     
-    private final _Lazy<JdoObjectIdSerializer<Object>> objectIdSerializerRef = _Lazy.threadSafe(this::createObjectIdSerializer);
-    
-    protected JdoObjectIdSerializer<Object> getObjectIdSerializer() {
-        return objectIdSerializerRef.get();
-    }
-    
-    protected JdoObjectIdSerializer<Object> createObjectIdSerializer() {
-        final Class<?> primaryKeyType = getPersistenceManager().getObjectIdClass(entityClass);
-        return _Casts.uncheckedCast(JdoEntityFacetFactory
-                .createJdoObjectIdSerializer(primaryKeyType, metaModelContext.getServiceRegistry()));
-    }
     
     // -- DEPENDENCIES
     
diff --git a/persistence/jdo/lightweight/src/main/java/org/apache/isis/persistence/jdo/lightweight/metamodel/facets/entity/JdoEntityFacetFactory.java b/persistence/jdo/lightweight/src/main/java/org/apache/isis/persistence/jdo/lightweight/metamodel/facets/entity/JdoEntityFacetFactory.java
index 4562ad9..18127e5 100644
--- a/persistence/jdo/lightweight/src/main/java/org/apache/isis/persistence/jdo/lightweight/metamodel/facets/entity/JdoEntityFacetFactory.java
+++ b/persistence/jdo/lightweight/src/main/java/org/apache/isis/persistence/jdo/lightweight/metamodel/facets/entity/JdoEntityFacetFactory.java
@@ -21,21 +21,13 @@ package org.apache.isis.persistence.jdo.lightweight.metamodel.facets.entity;
 import javax.inject.Inject;
 import javax.jdo.annotations.PersistenceCapable;
 
-import org.apache.isis.applib.services.registry.ServiceRegistry;
-import org.apache.isis.applib.services.urlencoding.UrlEncodingService;
 import org.apache.isis.commons.collections.ImmutableEnumSet;
-import org.apache.isis.commons.internal.base._Casts;
-import org.apache.isis.commons.internal.base._Strings;
-import org.apache.isis.commons.internal.memento._Mementos;
-import org.apache.isis.commons.internal.memento._Mementos.SerializingAdapter;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facets.Annotations;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
 import org.apache.isis.persistence.jdo.applib.integration.JdoSupportService;
 import org.apache.isis.persistence.jdo.provider.entities.JdoFacetContext;
 
-import lombok.NonNull;
-import lombok.RequiredArgsConstructor;
 import lombok.val;
 
 public class JdoEntityFacetFactory extends FacetFactoryAbstract {
@@ -63,108 +55,6 @@ public class JdoEntityFacetFactory extends FacetFactoryAbstract {
             
         addFacet(jdoEntityFacet);
     }
-    
-    
-    // -- HELPER - OBJECT ID SERIALIZATION
-    
-
-    @SuppressWarnings("rawtypes")
-    static JdoObjectIdSerializer createJdoObjectIdSerializer(
-            final @NonNull Class<?> primaryKeyType,
-            final @NonNull ServiceRegistry serviceRegistry) {
-        
-        
-        // not strictly required, but to have simpler entity URLs for simple primary-key types
-        {
-            if(primaryKeyType.equals(Long.class)
-                    || primaryKeyType.equals(long.class)) {
-                return new LongIdSerializer();
-            }
-            if(primaryKeyType.equals(Integer.class)
-                    || primaryKeyType.equals(int.class)) {
-                return new IntegerIdSerializer();
-            }
-            if(primaryKeyType.equals(Short.class)
-                    || primaryKeyType.equals(short.class)) {
-                return new ShortIdSerializer();
-            }
-            if(primaryKeyType.equals(Byte.class)
-                    || primaryKeyType.equals(byte.class)) {
-                return new ByteIdSerializer();
-            }
-        }
-        
-        val codec = serviceRegistry.lookupServiceElseFail(UrlEncodingService.class);
-        val serializer = serviceRegistry.lookupServiceElseFail(SerializingAdapter.class);
-        return new JdoObjectIdSerializerUsingMementos<>(primaryKeyType, codec, serializer);
-    }
-    
-    
-    @RequiredArgsConstructor
-    static abstract class JdoObjectIdSerializer<T> {
-        @SuppressWarnings("unused")
-        final Class<T> primaryKeyType;
-        abstract String stringify(T id);
-        abstract T parse(String stringifiedPrimaryKey);
-    }
-    
-    private static class LongIdSerializer extends JdoObjectIdSerializer<Long> {
-        public LongIdSerializer() { super(Long.class); }
-        @Override String stringify(Long id) { return id.toString(); }
-        @Override Long parse(String stringifiedPrimaryKey) { return Long.parseLong(stringifiedPrimaryKey); }
-    }
-    private static class IntegerIdSerializer extends JdoObjectIdSerializer<Integer> {
-        public IntegerIdSerializer() { super(Integer.class); }
-        @Override String stringify(Integer id) { return id.toString(); }
-        @Override Integer parse(String stringifiedPrimaryKey) { return Integer.parseInt(stringifiedPrimaryKey); }
-    }
-    private static class ShortIdSerializer extends JdoObjectIdSerializer<Short> {
-        public ShortIdSerializer() { super(Short.class); }
-        @Override String stringify(Short id) { return id.toString(); }
-        @Override Short parse(String stringifiedPrimaryKey) { return Short.parseShort(stringifiedPrimaryKey); }
-    }
-    private static class ByteIdSerializer extends JdoObjectIdSerializer<Byte> {
-        public ByteIdSerializer() { super(Byte.class); }
-        @Override String stringify(Byte id) { return id.toString(); }
-        @Override Byte parse(String stringifiedPrimaryKey) { return Byte.parseByte(stringifiedPrimaryKey); }
-    }
-    
-    private static class JdoObjectIdSerializerUsingMementos<T> extends JdoObjectIdSerializer<T> {
-        private final UrlEncodingService codec;
-        private final SerializingAdapter serializer;
-        
-        public JdoObjectIdSerializerUsingMementos(
-                final @NonNull Class<T> primaryKeyType, 
-                final @NonNull UrlEncodingService codec,
-                final @NonNull SerializingAdapter serializer) {
-            super(primaryKeyType);
-            this.codec = codec;
-            this.serializer = serializer;
-        }
-       
-        public String stringify(Object id) {
-            return newMemento().put("id", id).asString();
-        }
-        
-        public T parse(final String stringifiedPrimaryKey) {
-            if(_Strings.isEmpty(stringifiedPrimaryKey)) {
-                return null;
-            }
-            return _Casts.uncheckedCast(parseMemento(stringifiedPrimaryKey).get("id", Object.class));
-        }
-       
-        // -- HELPER
-
-        private _Mementos.Memento newMemento(){
-            return _Mementos.create(codec, serializer);
-        }
-
-        private _Mementos.Memento parseMemento(String input){
-            return _Mementos.parse(codec, serializer, input);
-        }
-        
-    }
-    
 
 
 }
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/ApplicationLayerTestFactory.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/ApplicationLayerTestFactory.java
index 5216021..37091c0 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/ApplicationLayerTestFactory.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/ApplicationLayerTestFactory.java
@@ -190,7 +190,7 @@ public class ApplicationLayerTestFactory {
 
         preCommitListener.setVerifier(verifier);
         
-        transactionService.executeWithinTransaction(()->{
+        transactionService.runWithinCurrentTransactionElseCreateNew(()->{
 
             // when - direct change (circumventing the framework)
             book.setName("Book #2");
diff --git a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/persistence/jpa/JpaBootstrappingTest.java b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/persistence/jpa/JpaBootstrappingTest.java
index 5154db3..2595533 100644
--- a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/persistence/jpa/JpaBootstrappingTest.java
+++ b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/persistence/jpa/JpaBootstrappingTest.java
@@ -18,6 +18,11 @@
  */
 package org.apache.isis.testdomain.persistence.jpa;
 
+import static org.junit.Assert.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
 import java.sql.SQLException;
 import java.util.Optional;
 import java.util.SortedSet;
@@ -38,11 +43,6 @@ import org.springframework.transaction.PlatformTransactionManager;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.support.DefaultTransactionDefinition;
 
-import static org.junit.Assert.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
 import org.apache.isis.applib.services.repository.RepositoryService;
 import org.apache.isis.core.config.presets.IsisPresets;
 import org.apache.isis.core.metamodel.facets.object.entity.EntityFacet;
@@ -122,9 +122,13 @@ class JpaBootstrappingTest extends IsisIntegrationTestAbstract {
 
     @Test @Order(0) 
     void jpaEntities_shouldBeRecognisedAsSuch() {
-        val spec = specLoader.loadSpecification(JpaProduct.class);
-        assertTrue(spec.isEntity());
-        assertNotNull(spec.getFacet(EntityFacet.class));
+        val productSpec = specLoader.loadSpecification(JpaProduct.class);
+        assertTrue(productSpec.isEntity());
+        assertNotNull(productSpec.getFacet(EntityFacet.class));
+        
+        val inventorySpec = specLoader.loadSpecification(JpaInventory.class);
+        assertTrue(inventorySpec.isEntity());
+        assertNotNull(inventorySpec.getFacet(EntityFacet.class));
     }
      
     @Test @Order(1) @Rollback(false) 
diff --git a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/isis/JdoIsisTransactionRollbackTest_usingTransactionService.java b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/isis/JdoIsisTransactionRollbackTest_usingTransactionService.java
index 1a2749f..cc60e39 100644
--- a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/isis/JdoIsisTransactionRollbackTest_usingTransactionService.java
+++ b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/isis/JdoIsisTransactionRollbackTest_usingTransactionService.java
@@ -64,7 +64,7 @@ class JdoIsisTransactionRollbackTest_usingTransactionService extends IsisIntegra
         assertEquals(0, repository.allInstances(JdoBook.class).size());
 
 
-        transactionService.executeWithinTransaction(()->{
+        transactionService.runWithinCurrentTransactionElseCreateNew(()->{
 
             fixtureScripts.runPersona(JdoTestDomainPersona.InventoryWith1Book);
 
@@ -81,7 +81,7 @@ class JdoIsisTransactionRollbackTest_usingTransactionService extends IsisIntegra
         // expected pre condition
         assertEquals(0, repository.allInstances(JdoBook.class).size());
 
-        val result = transactionService.executeWithinTransaction(()->{
+        val result = transactionService.runWithinCurrentTransactionElseCreateNew(()->{
 
             fixtureScripts.runPersona(JdoTestDomainPersona.InventoryWith1Book);
 
diff --git a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/isis/JdoIsisTransactionRollbackTest_usingTransactional.java b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/isis/JdoIsisTransactionRollbackTest_usingTransactional.java
index 7c32036..e055b92 100644
--- a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/isis/JdoIsisTransactionRollbackTest_usingTransactional.java
+++ b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/isis/JdoIsisTransactionRollbackTest_usingTransactional.java
@@ -18,6 +18,8 @@
  */
 package org.apache.isis.testdomain.transactions.jdo.isis;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
 import javax.inject.Inject;
 
 import org.junit.jupiter.api.MethodOrderer;
@@ -26,18 +28,15 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.TestMethodOrder;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.annotation.Commit;
-import org.springframework.test.context.TestPropertySource;
 import org.springframework.transaction.annotation.Transactional;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
 import org.apache.isis.applib.services.repository.RepositoryService;
-import org.apache.isis.core.config.presets.IsisPresets;
+import org.apache.isis.commons.internal.debug._Probe;
+import org.apache.isis.core.interaction.session.InteractionFactory;
 import org.apache.isis.testdomain.conf.Configuration_usingJdoIsis;
 import org.apache.isis.testdomain.jdo.JdoTestDomainPersona;
 import org.apache.isis.testdomain.jdo.entities.JdoBook;
 import org.apache.isis.testing.fixtures.applib.fixturescripts.FixtureScripts;
-import org.apache.isis.testing.integtestsupport.applib.IsisIntegrationTestAbstract;
 
 /**
  * These tests use the {@code @Transactional} annotation as provided by Spring.
@@ -46,40 +45,69 @@ import org.apache.isis.testing.integtestsupport.applib.IsisIntegrationTestAbstra
  */
 @SpringBootTest(
         classes = { 
-                Configuration_usingJdoIsis.class,
+                Configuration_usingJdoIsis.class
+        },
+        properties = {
+                "logging.level.org.apache.isis.persistence.jdo.*=DEBUG",
+                "logging.level.org.springframework.test.context.transaction.*=DEBUG",
+                "logging.level.org.datanucleus.*=DEBUG",
+                "logging.config=log4j2-debug-persistence.xml"
+                
         })
 @Transactional
-@TestPropertySource(IsisPresets.UseLog4j2Test)
+//@TestPropertySource(IsisPresets.UseLog4j2Test)
 @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
-class JdoIsisTransactionRollbackTest_usingTransactional extends IsisIntegrationTestAbstract {
+class JdoIsisTransactionRollbackTest_usingTransactional 
+// extends IsisIntegrationTestAbstract 
+{
     
     @Inject private FixtureScripts fixtureScripts;
     @Inject private RepositoryService repository;
+    @Inject private InteractionFactory interactionFactory;
     
     @Test @Order(1) @Commit
     void cleanup_justInCase() {
+   
         // cleanup just in case
         fixtureScripts.runPersona(JdoTestDomainPersona.PurgeAll);
     }
     
     @Test @Order(2)
     void happyCaseTx_shouldCommit() {
+   
+        _Probe.errOut("before interaction");
         
-        // expected pre condition
-        assertEquals(0, repository.allInstances(JdoBook.class).size());
+        interactionFactory.runAnonymous(()->{
+            
+            // expected pre condition
+            assertEquals(0, repository.allInstances(JdoBook.class).size());
+                
+            _Probe.errOut("before fixture");
+            
+            fixtureScripts.runPersona(JdoTestDomainPersona.InventoryWith1Book);
+            
+            _Probe.errOut("after fixture");
             
-        fixtureScripts.runPersona(JdoTestDomainPersona.InventoryWith1Book);
+            // expected post condition
+            //assertEquals(1, repository.allInstances(JdoBook.class).size());
+            
+            
+        });
         
-        // expected post condition
-        assertEquals(1, repository.allInstances(JdoBook.class).size());
+        _Probe.errOut("after interaction");
         
     }
     
     @Test @Order(3)
     void previousTest_shouldHaveBeenRolledBack() {
-        
+
+        interactionFactory.runAnonymous(()->{
+
         // expected condition
         assertEquals(0, repository.allInstances(JdoBook.class).size());
+        
+        });
+
     }
 
 }
diff --git a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/isis/JdoIsisTransactionScopeListenerTest.java b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/isis/JdoIsisTransactionScopeListenerTest.java
index 7607dc5..f4568aa 100644
--- a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/isis/JdoIsisTransactionScopeListenerTest.java
+++ b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/isis/JdoIsisTransactionScopeListenerTest.java
@@ -88,7 +88,7 @@ class JdoIsisTransactionScopeListenerTest {
             assertEquals(0, repository.allInstances(JdoBook.class).size());
         
             // new transaction (#3)
-            transactionService.executeWithinTransaction(()->{
+            transactionService.runWithinCurrentTransactionElseCreateNew(()->{
                 
                 fixtureScripts.runPersona(JdoTestDomainPersona.InventoryWith1Book);
                 
diff --git a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/spring/JdoSpringTransactionRollbackTest_usingTransactionService.java b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/spring/JdoSpringTransactionRollbackTest_usingTransactionService.java
index 45b9606..05ae949 100644
--- a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/spring/JdoSpringTransactionRollbackTest_usingTransactionService.java
+++ b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/spring/JdoSpringTransactionRollbackTest_usingTransactionService.java
@@ -18,17 +18,16 @@
  */
 package org.apache.isis.testdomain.transactions.jdo.spring;
 
+import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
 import javax.inject.Inject;
 
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.TestPropertySource;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
 import org.apache.isis.applib.services.repository.RepositoryService;
 import org.apache.isis.applib.services.xactn.TransactionService;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
@@ -39,6 +38,8 @@ import org.apache.isis.testdomain.jdo.entities.JdoBook;
 import org.apache.isis.testing.fixtures.applib.fixturescripts.FixtureScripts;
 import org.apache.isis.testing.integtestsupport.applib.IsisIntegrationTestAbstract;
 
+import lombok.val;
+
 @SpringBootTest(
         classes = { 
                 Configuration_usingJdoSpring.class,
@@ -56,44 +57,48 @@ class JdoSpringTransactionRollbackTest_usingTransactionService extends IsisInteg
         fixtureScripts.runPersona(JdoTestDomainPersona.PurgeAll);
     }
     
-    @Test @Disabled("wip")
+    @Test
     void happyCaseTx_shouldCommit() {
         
-        // expected pre condition
-        assertEquals(0, repository.allInstances(JdoBook.class).size());
-        
-        
-        transactionService.executeWithinTransaction(()->{
+        transactionService.runWithinCurrentTransactionElseCreateNew(()->{
+            
+            // expected pre condition
+            assertEquals(0, repository.allInstances(JdoBook.class).size());
             
             fixtureScripts.runPersona(JdoTestDomainPersona.InventoryWith1Book);
             
+            // expected post condition
+            assertEquals(1, repository.allInstances(JdoBook.class).size());
+            
         });
-        
-        // expected post condition
-        assertEquals(1, repository.allInstances(JdoBook.class).size());
 
     }
     
-    @Test @Disabled("wip")
+    @Test
     void whenExceptionWithinTx_shouldRollback() {
         
-        // expected pre condition
-        assertEquals(0, repository.allInstances(JdoBook.class).size());
-            
-        assertThrows(RuntimeException.class, ()->{
+        transactionService.runWithinCurrentTransactionElseCreateNew(()->{
             
-            transactionService.executeWithinTransaction(()->{
+            // expected pre condition
+            assertEquals(0, repository.allInstances(JdoBook.class).size());
+        });    
                 
-                fixtureScripts.runPersona(JdoTestDomainPersona.InventoryWith1Book);
+        val result = transactionService.runWithinCurrentTransactionElseCreateNew(()->{
+            
+            fixtureScripts.runPersona(JdoTestDomainPersona.InventoryWith1Book);
 
-                throw _Exceptions.unrecoverable("Test: force current tx to rollback");            
-                
-            });    
+            throw _Exceptions.unrecoverable("Test: force current tx to rollback");            
             
         });
         
-        // expected post condition
-        assertEquals(0, repository.allInstances(JdoBook.class).size());
+        assertTrue(result.isFailure());
+        
+        transactionService.runWithinCurrentTransactionElseCreateNew(()->{
+        
+            // expected post condition
+            assertEquals(0, repository.allInstances(JdoBook.class).size());
+            
+        });
         
     }
     
diff --git a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/spring/JdoSpringTransactionRollbackTest_usingTransactional.java b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/spring/JdoSpringTransactionRollbackTest_usingTransactional.java
index 4b85d56..6b96f13 100644
--- a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/spring/JdoSpringTransactionRollbackTest_usingTransactional.java
+++ b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/spring/JdoSpringTransactionRollbackTest_usingTransactional.java
@@ -18,9 +18,12 @@
  */
 package org.apache.isis.testdomain.transactions.jdo.spring;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.HashSet;
+
 import javax.inject.Inject;
 
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.MethodOrderer;
 import org.junit.jupiter.api.Order;
 import org.junit.jupiter.api.Test;
@@ -30,15 +33,14 @@ import org.springframework.test.annotation.Commit;
 import org.springframework.test.context.TestPropertySource;
 import org.springframework.transaction.annotation.Transactional;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
 import org.apache.isis.applib.services.repository.RepositoryService;
 import org.apache.isis.core.config.presets.IsisPresets;
 import org.apache.isis.testdomain.conf.Configuration_usingJdoSpring;
-import org.apache.isis.testdomain.jdo.JdoTestDomainPersona;
 import org.apache.isis.testdomain.jdo.entities.JdoBook;
-import org.apache.isis.testing.fixtures.applib.fixturescripts.FixtureScripts;
-import org.apache.isis.testing.integtestsupport.applib.IsisIntegrationTestAbstract;
+import org.apache.isis.testdomain.jdo.entities.JdoInventory;
+import org.apache.isis.testdomain.jdo.entities.JdoProduct;
+
+import lombok.val;
 
 /**
  * These tests use the {@code @Transactional} annotation as provided by Spring.
@@ -48,37 +50,59 @@ import org.apache.isis.testing.integtestsupport.applib.IsisIntegrationTestAbstra
 @SpringBootTest(
         classes = { 
                 Configuration_usingJdoSpring.class,
+        },
+        properties = {
+                "logging.level.org.apache.isis.persistence.jdo.*=DEBUG",
+                "logging.level.org.springframework.test.context.transaction.*=DEBUG"
         })
 @Transactional
 @TestPropertySource(IsisPresets.UseLog4j2Test)
 @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
-class JdoSpringTransactionRollbackTest_usingTransactional extends IsisIntegrationTestAbstract {
-    
-    @Inject private FixtureScripts fixtureScripts;
+class JdoSpringTransactionRollbackTest_usingTransactional 
+//extends IsisIntegrationTestAbstract 
+{
+
     @Inject private RepositoryService repository;
-    
+
     @Test @Order(1) @Commit
     void cleanup_justInCase() {
         // cleanup just in case
-        fixtureScripts.runPersona(JdoTestDomainPersona.PurgeAll);
+        repository.removeAll(JdoProduct.class);
+        repository.removeAll(JdoInventory.class);
     }
-    
+
     @Test @Order(2)
     void happyCaseTx_shouldCommit() {
-        
+
+        System.err.println("== ENTER TEST");
+
         // expected pre condition
         assertEquals(0, repository.allInstances(JdoBook.class).size());
-            
-        fixtureScripts.runPersona(JdoTestDomainPersona.InventoryWith1Book);
-        
+
+        val products = new HashSet<JdoProduct>();
+
+        products.add(JdoBook.of(
+                "Sample Book", "A sample book for testing.", 99.,
+                "Sample Author", "Sample ISBN", "Sample Publisher"));
+
+        val inventory = JdoInventory.of("Sample Inventory", products);
+
+        System.err.println("== ENTER PERSIST");
+
+        repository.persist(inventory);
+
+        System.err.println("== EXIT PERSIST");
+
         // expected post condition
         assertEquals(1, repository.allInstances(JdoBook.class).size());
-        
+
+        System.err.println("== EXIT TEST");
+
     }
-    
-    @Test @Order(3) @Disabled("wip")
+
+    @Test @Order(3)
     void previousTest_shouldHaveBeenRolledBack() {
-        
+
         // expected condition
         assertEquals(0, repository.allInstances(JdoBook.class).size());
     }
diff --git a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/spring/JdoSpringTransactionScopeListenerTest.java b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/spring/JdoSpringTransactionScopeListenerTest.java
index ee2ff49..8a0dc9a 100644
--- a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/spring/JdoSpringTransactionScopeListenerTest.java
+++ b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jdo/spring/JdoSpringTransactionScopeListenerTest.java
@@ -89,7 +89,7 @@ class JdoSpringTransactionScopeListenerTest {
             assertEquals(0, repository.allInstances(JdoBook.class).size());
         
             // new transaction (#3)
-            transactionService.executeWithinTransaction(()->{
+            transactionService.runWithinCurrentTransactionElseCreateNew(()->{
                 
                 fixtureScripts.runPersona(JdoTestDomainPersona.InventoryWith1Book);
                 
diff --git a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jpa/JpaTransactionRollbackTest_usingTransactionService.java b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jpa/JpaTransactionRollbackTest_usingTransactionService.java
index 31eda05..740672d 100644
--- a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jpa/JpaTransactionRollbackTest_usingTransactionService.java
+++ b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jpa/JpaTransactionRollbackTest_usingTransactionService.java
@@ -18,83 +18,95 @@
  */
 package org.apache.isis.testdomain.transactions.jpa;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
 import javax.inject.Inject;
 
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.TestPropertySource;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
 import org.apache.isis.applib.services.repository.RepositoryService;
 import org.apache.isis.applib.services.xactn.TransactionService;
-import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.config.presets.IsisPresets;
 import org.apache.isis.testdomain.conf.Configuration_usingJpa;
-import org.apache.isis.testdomain.jdo.JdoTestDomainPersona;
 import org.apache.isis.testdomain.jpa.JpaTestDomainPersona;
 import org.apache.isis.testdomain.jpa.entities.JpaBook;
 import org.apache.isis.testing.fixtures.applib.fixturescripts.FixtureScripts;
-import org.apache.isis.testing.integtestsupport.applib.IsisIntegrationTestAbstract;
+
+import lombok.val;
 
 @SpringBootTest(
         classes = { 
                 Configuration_usingJpa.class,
+        },
+        properties = {
+                "logging.level.org.apache.isis.persistence.jdo.spring.*=DEBUG",
+                "logging.level.org.springframework.test.context.transaction.*=DEBUG"
         })
 @TestPropertySource(IsisPresets.UseLog4j2Test)
-class JpaTransactionRollbackTest_usingTransactionService extends IsisIntegrationTestAbstract {
+class JpaTransactionRollbackTest_usingTransactionService 
+//extends IsisIntegrationTestAbstract 
+{
     
     @Inject private FixtureScripts fixtureScripts;
     @Inject private TransactionService transactionService;
     @Inject private RepositoryService repository;
-    
+
     @BeforeEach
     void setUp() {
+       
         // cleanup
-        fixtureScripts.runPersona(JdoTestDomainPersona.PurgeAll);
+        fixtureScripts.runPersona(JpaTestDomainPersona.PurgeAll);
     }
     
-    @Test @Disabled("wip")
+    @Test
     void happyCaseTx_shouldCommit() {
         
-        // expected pre condition
-        assertEquals(0, repository.allInstances(JpaBook.class).size());
+        transactionService.runWithinCurrentTransactionElseCreateNew(()->{
         
+            // expected pre condition
+            assertEquals(0, repository.allInstances(JpaBook.class).size());
+        });
         
-        transactionService.executeWithinTransaction(()->{
+        transactionService.runWithinCurrentTransactionElseCreateNew(()->{
             
             fixtureScripts.runPersona(JpaTestDomainPersona.InventoryWith1Book);
-            
         });
         
-        // expected post condition
-        assertEquals(1, repository.allInstances(JpaBook.class).size());
+        transactionService.runWithinCurrentTransactionElseCreateNew(()->{
+        
+            // expected post condition
+            assertEquals(1, repository.allInstances(JpaBook.class).size());
+        });
 
     }
     
-    @Test @Disabled("wip")
+    @Test
     void whenExceptionWithinTx_shouldRollback() {
         
-        // expected pre condition
-        assertEquals(0, repository.allInstances(JpaBook.class).size());
-            
-        assertThrows(RuntimeException.class, ()->{
-            
-            transactionService.executeWithinTransaction(()->{
-                
-                fixtureScripts.runPersona(JpaTestDomainPersona.InventoryWith1Book);
-
-                throw _Exceptions.unrecoverable("Test: force current tx to rollback");            
-                
-            });    
-            
+        transactionService.runWithinCurrentTransactionElseCreateNew(()->{
+        
+            // expected pre condition
+            assertEquals(0, repository.allInstances(JpaBook.class).size());
         });
         
-        // expected post condition
-        assertEquals(0, repository.allInstances(JpaBook.class).size());
+        val result = transactionService.runWithinCurrentTransactionElseCreateNew(()->{
+
+            fixtureScripts.runPersona(JpaTestDomainPersona.InventoryWith1Book);
+
+            throw new RuntimeException("Test: force current tx to rollback");            
+        });    
+        
+        assertTrue(result.isFailure());
+        
+        transactionService.runWithinCurrentTransactionElseCreateNew(()->{
+        
+            // expected post condition
+            assertEquals(0, repository.allInstances(JpaBook.class).size());
+        });
         
     }
     
diff --git a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jpa/JpaTransactionRollbackTest_usingTransactional.java b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jpa/JpaTransactionRollbackTest_usingTransactional.java
index 513d66c..8a68009 100644
--- a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jpa/JpaTransactionRollbackTest_usingTransactional.java
+++ b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jpa/JpaTransactionRollbackTest_usingTransactional.java
@@ -18,6 +18,8 @@
  */
 package org.apache.isis.testdomain.transactions.jpa;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
 import javax.inject.Inject;
 
 import org.junit.jupiter.api.MethodOrderer;
@@ -29,15 +31,13 @@ import org.springframework.test.annotation.Commit;
 import org.springframework.test.context.TestPropertySource;
 import org.springframework.transaction.annotation.Transactional;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
 import org.apache.isis.applib.services.repository.RepositoryService;
+import org.apache.isis.commons.internal.debug._Probe;
 import org.apache.isis.core.config.presets.IsisPresets;
 import org.apache.isis.testdomain.conf.Configuration_usingJpa;
 import org.apache.isis.testdomain.jpa.JpaTestDomainPersona;
 import org.apache.isis.testdomain.jpa.entities.JpaBook;
 import org.apache.isis.testing.fixtures.applib.fixturescripts.FixtureScripts;
-import org.apache.isis.testing.integtestsupport.applib.IsisIntegrationTestAbstract;
 
 /**
  * These tests use the {@code @Transactional} annotation as provided by Spring.
@@ -47,11 +47,18 @@ import org.apache.isis.testing.integtestsupport.applib.IsisIntegrationTestAbstra
 @SpringBootTest(
         classes = { 
                 Configuration_usingJpa.class,
-        })
+        },
+        properties = {
+                "logging.level.org.apache.isis.core.runtimeservices.session.InteractionFactoryDefault=DEBUG",
+                "logging.level.org.apache.isis.persistence.*=DEBUG",
+                "logging.level.org.springframework.test.context.transaction.*=DEBUG"
+        })  
 @Transactional
 @TestPropertySource(IsisPresets.UseLog4j2Test)
 @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
-class JpaTransactionRollbackTest_usingTransactional extends IsisIntegrationTestAbstract {
+class JpaTransactionRollbackTest_usingTransactional 
+//extends IsisIntegrationTestAbstract 
+{
     
     @Inject private FixtureScripts fixtureScripts;
     @Inject private RepositoryService repository;
@@ -67,15 +74,19 @@ class JpaTransactionRollbackTest_usingTransactional extends IsisIntegrationTestA
         
         // expected pre condition
         assertEquals(0, repository.allInstances(JpaBook.class).size());
+        
+        _Probe.errOut("before fixture");
             
         fixtureScripts.runPersona(JpaTestDomainPersona.InventoryWith1Book);
         
+        _Probe.errOut("after fixture");
+        
         // expected post condition
         assertEquals(1, repository.allInstances(JpaBook.class).size());
         
     }
     
-    @Test @Order(3) //@Disabled("wip")
+    @Test @Order(3)
     void previousTest_shouldHaveBeenRolledBack() {
         
         // expected condition
diff --git a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jpa/JpaTransactionScopeListenerTest.java b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jpa/JpaTransactionScopeListenerTest.java
index 1df816d..e37024d 100644
--- a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jpa/JpaTransactionScopeListenerTest.java
+++ b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/transactions/jpa/JpaTransactionScopeListenerTest.java
@@ -90,7 +90,7 @@ class JpaTransactionScopeListenerTest {
             assertEquals(0, repository.allInstances(JpaBook.class).size());
         
             // new transaction (#3)
-            transactionService.executeWithinTransaction(()->{
+            transactionService.runWithinCurrentTransactionElseCreateNew(()->{
                 
                 fixtureScripts.runPersona(JpaTestDomainPersona.InventoryWith1Book);
                 
diff --git a/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/fixturescripts/FixtureScripts.java b/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/fixturescripts/FixtureScripts.java
index 967c81b..dbb3d2b 100644
--- a/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/fixturescripts/FixtureScripts.java
+++ b/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/fixturescripts/FixtureScripts.java
@@ -351,7 +351,7 @@ public class FixtureScripts {
     	String parameters = null;
     	
     	isisInteractionFactory.runAnonymous(()->{
-    	    transactionService.executeWithinTransaction(()->{
+    	    transactionService.runWithinCurrentTransactionElseCreateNew(()->{
                 runScript(singleScript, parameters);
             });    
     	});
@@ -386,7 +386,7 @@ public class FixtureScripts {
     public <T> T runBuilder(final BuilderScriptAbstract<T> builderScript) {
         
         return isisInteractionFactory.callAnonymous(()->
-            transactionService.executeWithinTransaction(()->
+            transactionService.callWithinCurrentTransactionElseCreateNew(()->
                 runBuilderScriptNonTransactional(builderScript)
             )
         )
diff --git a/testing/integtestsupport/applib/src/main/java/org/apache/isis/testing/integtestsupport/applib/IsisInteractionHandler.java b/testing/integtestsupport/applib/src/main/java/org/apache/isis/testing/integtestsupport/applib/IsisInteractionHandler.java
index 342a475..4066828 100644
--- a/testing/integtestsupport/applib/src/main/java/org/apache/isis/testing/integtestsupport/applib/IsisInteractionHandler.java
+++ b/testing/integtestsupport/applib/src/main/java/org/apache/isis/testing/integtestsupport/applib/IsisInteractionHandler.java
@@ -24,20 +24,31 @@ import org.junit.jupiter.api.extension.AfterEachCallback;
 import org.junit.jupiter.api.extension.BeforeEachCallback;
 import org.junit.jupiter.api.extension.ExtensionContext;
 
+import org.apache.isis.commons.internal.debug._Probe;
 import org.apache.isis.core.interaction.session.InteractionFactory;
 
 public class IsisInteractionHandler implements BeforeEachCallback, AfterEachCallback {
 
     @Override
     public void beforeEach(ExtensionContext extensionContext) throws Exception {
+        
+        _Probe.errOut("before interaction in");
+        
         isisInteractionFactory(extensionContext)
         .ifPresent(isisInteractionFactory->isisInteractionFactory.openInteraction());
+        
+        _Probe.errOut("before interaction out");
     }
     
     @Override
     public void afterEach(ExtensionContext extensionContext) throws Exception {
+        
+        _Probe.errOut("after interaction in");
+        
         isisInteractionFactory(extensionContext)
         .ifPresent(InteractionFactory::closeSessionStack);
+        
+        _Probe.errOut("after interaction out");
     }
 
     // -- HELPER
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/IsisRestfulObjectsInteractionFilter.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/IsisRestfulObjectsInteractionFilter.java
index c3a7006..9ff6973 100644
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/IsisRestfulObjectsInteractionFilter.java
+++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/webmodule/IsisRestfulObjectsInteractionFilter.java
@@ -19,6 +19,8 @@
 
 package org.apache.isis.viewer.restfulobjects.viewer.webmodule;
 
+import static org.apache.isis.commons.internal.base._With.requires;
+
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collection;
@@ -53,8 +55,6 @@ import org.apache.isis.core.webapp.modules.templresources.TemplateResourceCachin
 import org.apache.isis.viewer.restfulobjects.viewer.webmodule.auth.AuthenticationStrategy;
 import org.apache.isis.viewer.restfulobjects.viewer.webmodule.auth.AuthenticationStrategyDefault;
 
-import static org.apache.isis.commons.internal.base._With.requires;
-
 import lombok.val;
 
 /**
@@ -382,13 +382,10 @@ public class IsisRestfulObjectsInteractionFilter implements Filter {
                         authentication,
                         ()->{
                             
-                            transactionService.executeWithinTransaction(()->{
-                                try {
-                                    chain.doFilter(request, response);
-                                } catch (IOException | ServletException e) {
-                                    throw new TransactionalException("", e);
-                                }
-                            });
+                            transactionService.runWithinCurrentTransactionElseCreateNew(()->
+                                chain.doFilter(request, response))
+                            .mapFailure(e->new TransactionalException("", e))
+                            .nullableOrElseFail();
                             
                         });
                                 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/accmngt/register/RegisterPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/accmngt/register/RegisterPanel.java
index b153e60..21d8112 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/accmngt/register/RegisterPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/accmngt/register/RegisterPanel.java
@@ -142,7 +142,7 @@ public abstract class RegisterPanel extends PanelBase<UserDetails> {
             final UserDetails userDetails = getModelObject();
 
             isisInteractionFactory.runAnonymous(() -> {
-                transactionService.executeWithinTransaction(() -> {
+                transactionService.runWithinCurrentTransactionElseCreateNew(() -> {
                     userRegistrationService.registerUser(userDetails);
                     removeAccountConfirmation();
                 });