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:43 UTC

[isis] branch 2033-Spring_Data_Integration created (now e7f6276)

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

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


      at e7f6276  ISIS-2033: Let Spring take over Transaction Management

This branch includes the following new commits:

     new e7f6276  ISIS-2033: Let Spring take over Transaction Management

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



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

Posted by ah...@apache.org.
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();
                 });