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 2021/07/21 18:20:12 UTC

[isis] branch master updated: ISIS-2573: prepare publishing tests for JPA (wip/incubating)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new da10cb4  ISIS-2573: prepare publishing tests for JPA (wip/incubating)
da10cb4 is described below

commit da10cb4da43bd0d4ae2301a79af91a19c783fcb5
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed Jul 21 20:19:54 2021 +0200

    ISIS-2573: prepare publishing tests for JPA (wip/incubating)
---
 .../EntityPropertyChangePublisherDefault.java      |   4 +-
 .../changetracking/_PropertyChangeRecord.java      |   8 +-
 .../jdo/JdoEntityChangePublishingTest.java         |   6 +-
 .../publishing/jdo/JdoCommandPublishingTest.java   |  20 +-
 .../jdo/JdoEntityChangesPublishingTest.java        |  30 +--
 .../jdo/JdoEntityPropertyChangePublishingTest.java |  20 +-
 .../publishing/jdo/JdoExecutionPublishingTest.java |  24 +--
 .../jpa/JpaCommandPublishingTest.java}             |  36 ++--
 .../jpa/JpaEntityChangesPublishingTest.java}       |  38 ++--
 .../JpaEntityPropertyChangePublishingTest.java}    |  29 ++-
 .../jpa/JpaExecutionPublishingTest.java}           |  38 ++--
 .../isis/testdomain/jpa/entities/JpaInventory.java |  10 +-
 .../ApplicationLayerTestFactoryAbstract.java       | 217 +++++++++++++++++++
 .../ApplicationLayerTestFactoryJdo.java}           | 189 +++-------------
 .../ApplicationLayerTestFactoryJpa.java}           | 240 +++++----------------
 .../conf/Configuration_usingCommandPublishing.java |   4 +-
 ...Configuration_usingEntityChangesPublishing.java |   4 +-
 ...ration_usingEntityPropertyChangePublishing.java |   4 +-
 .../Configuration_usingExecutionPublishing.java    |   4 +-
 .../subscriber}/CommandSubscriberForTesting.java   |   2 +-
 .../EntityChangesSubscriberForTesting.java         |   2 +-
 .../EntityPropertyChangeSubscriberForTesting.java  |   2 +-
 .../subscriber}/ExecutionSubscriberForTesting.java |   2 +-
 .../util/interaction/InteractionTestAbstract.java  |   2 +-
 24 files changed, 435 insertions(+), 500 deletions(-)

diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/publish/EntityPropertyChangePublisherDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/publish/EntityPropertyChangePublisherDefault.java
index fae555e..ea70c90 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/publish/EntityPropertyChangePublisherDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/publish/EntityPropertyChangePublisherDefault.java
@@ -70,7 +70,7 @@ public class EntityPropertyChangePublisherDefault implements EntityPropertyChang
             final HasEnlistedEntityPropertyChanges hasEnlistedEntityPropertyChanges) {
 
         val payload = getPayload(hasEnlistedEntityPropertyChanges);
-        val handle = _Xray.enterEntityPropertyChangePublishing(
+        val xrayHandle = _Xray.enterEntityPropertyChangePublishing(
                 iaTracker,
                 payload,
                 enabledSubscribers,
@@ -83,7 +83,7 @@ public class EntityPropertyChangePublisherDefault implements EntityPropertyChang
             }
         });
 
-        _Xray.exitPublishing(handle);
+        _Xray.exitPublishing(xrayHandle);
     }
 
     // -- HELPER
diff --git a/core/transaction/src/main/java/org/apache/isis/core/transaction/changetracking/_PropertyChangeRecord.java b/core/transaction/src/main/java/org/apache/isis/core/transaction/changetracking/_PropertyChangeRecord.java
index 54f2fc4..7d37fb4 100644
--- a/core/transaction/src/main/java/org/apache/isis/core/transaction/changetracking/_PropertyChangeRecord.java
+++ b/core/transaction/src/main/java/org/apache/isis/core/transaction/changetracking/_PropertyChangeRecord.java
@@ -51,7 +51,7 @@ final class _PropertyChangeRecord {
         return new _PropertyChangeRecord(entity, property);
     }
 
-    private _PropertyChangeRecord(ManagedObject entity, ObjectAssociation property) {
+    private _PropertyChangeRecord(final ManagedObject entity, final ObjectAssociation property) {
         this.entity = entity;
         this.property = property;
         this.propertyId = property.getId();
@@ -64,7 +64,7 @@ final class _PropertyChangeRecord {
         return property.getFeatureIdentifier().getFullIdentityString();
     }
 
-    void setPreValue(Object pre) {
+    void setPreValue(final Object pre) {
         preAndPostValue = _PreAndPostValue.pre(pre);
     }
 
@@ -72,8 +72,8 @@ final class _PropertyChangeRecord {
         setPreValue(getPropertyValue());
     }
 
-    void updatePostValue() {
-        preAndPostValue = EntityUtil.isDetachedOrRemoved(entity)
+    void updatePostValue(/*final boolean isEntityDeleted*/) {
+        preAndPostValue = EntityUtil.isDetachedOrRemoved(entity) //TODO[ISIS-2573] when detached, logic is wrong
                 ? preAndPostValue.withPost(IsisTransactionPlaceholder.DELETED)
                 : preAndPostValue.withPost(getPropertyValue());
     }
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/entitychangetracking/jdo/JdoEntityChangePublishingTest.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/entitychangetracking/jdo/JdoEntityChangePublishingTest.java
index 140b888..16fcf72 100644
--- a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/entitychangetracking/jdo/JdoEntityChangePublishingTest.java
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/entitychangetracking/jdo/JdoEntityChangePublishingTest.java
@@ -30,14 +30,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.core.config.presets.IsisPresets;
-import org.apache.isis.testdomain.applayer.publishing.EntityPropertyChangeSubscriberForTesting;
-import org.apache.isis.testdomain.applayer.publishing.conf.Configuration_usingEntityChangesPublishing;
-import org.apache.isis.testdomain.applayer.publishing.conf.Configuration_usingEntityPropertyChangePublishing;
 import org.apache.isis.testdomain.conf.Configuration_usingJdo;
 import org.apache.isis.testdomain.jdo.JdoInventoryManager;
 import org.apache.isis.testdomain.jdo.JdoTestDomainPersona;
 import org.apache.isis.testdomain.jdo.entities.JdoBook;
 import org.apache.isis.testdomain.jdo.entities.JdoProduct;
+import org.apache.isis.testdomain.publishing.conf.Configuration_usingEntityChangesPublishing;
+import org.apache.isis.testdomain.publishing.conf.Configuration_usingEntityPropertyChangePublishing;
+import org.apache.isis.testdomain.publishing.subscriber.EntityPropertyChangeSubscriberForTesting;
 import org.apache.isis.testdomain.util.interaction.InteractionBoundaryProbe;
 import org.apache.isis.testdomain.util.interaction.InteractionTestAbstract;
 import org.apache.isis.testing.fixtures.applib.fixturescripts.FixtureScripts;
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoCommandPublishingTest.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoCommandPublishingTest.java
similarity index 85%
copy from regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoCommandPublishingTest.java
copy to regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoCommandPublishingTest.java
index c5c09e6..11c68b3 100644
--- a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoCommandPublishingTest.java
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoCommandPublishingTest.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.applayer.publishing.jdo;
+package org.apache.isis.testdomain.publishing.jdo;
 
 import java.util.List;
 import java.util.Objects;
@@ -36,11 +36,11 @@ import org.apache.isis.commons.internal.debug.xray.XrayEnable;
 import org.apache.isis.core.config.presets.IsisPresets;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 import org.apache.isis.schema.cmd.v2.PropertyDto;
-import org.apache.isis.testdomain.applayer.ApplicationLayerTestFactory;
-import org.apache.isis.testdomain.applayer.ApplicationLayerTestFactory.VerificationStage;
-import org.apache.isis.testdomain.applayer.publishing.CommandSubscriberForTesting;
-import org.apache.isis.testdomain.applayer.publishing.conf.Configuration_usingCommandPublishing;
 import org.apache.isis.testdomain.conf.Configuration_usingJdo;
+import org.apache.isis.testdomain.publishing.ApplicationLayerTestFactoryJdo;
+import org.apache.isis.testdomain.publishing.ApplicationLayerTestFactoryAbstract.VerificationStage;
+import org.apache.isis.testdomain.publishing.conf.Configuration_usingCommandPublishing;
+import org.apache.isis.testdomain.publishing.subscriber.CommandSubscriberForTesting;
 import org.apache.isis.testdomain.util.CollectionAssertions;
 import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
 
@@ -50,7 +50,7 @@ import lombok.val;
         classes = {
                 Configuration_usingJdo.class,
                 Configuration_usingCommandPublishing.class,
-                ApplicationLayerTestFactory.class,
+                ApplicationLayerTestFactoryJdo.class,
                 XrayEnable.class
         },
         properties = {
@@ -63,7 +63,7 @@ import lombok.val;
 })
 class JdoCommandPublishingTest {
 
-    @Inject private ApplicationLayerTestFactory testFactory;
+    @Inject private ApplicationLayerTestFactoryJdo testFactory;
     @Inject private KVStoreForTesting kvStore;
 
     @TestFactory @DisplayName("Application Layer")
@@ -75,7 +75,7 @@ class JdoCommandPublishingTest {
         CommandSubscriberForTesting.clearPublishedCommands(kvStore);
     }
 
-    private void verify(VerificationStage verificationStage) {
+    private void verify(final VerificationStage verificationStage) {
         switch(verificationStage) {
 
         case FAILURE_CASE:
@@ -110,13 +110,13 @@ class JdoCommandPublishingTest {
 
     // -- HELPER
 
-    private void assertHasCommandEntries(Can<Command> expectedCommands) {
+    private void assertHasCommandEntries(final Can<Command> expectedCommands) {
         val actualCommands = CommandSubscriberForTesting.getPublishedCommands(kvStore);
         CollectionAssertions.assertComponentWiseEquals(
                 expectedCommands, actualCommands, this::commandDifference);
     }
 
-    private String commandDifference(Command a, Command b) {
+    private String commandDifference(final Command a, final Command b) {
         if(!Objects.equals(a.getLogicalMemberIdentifier(), b.getLogicalMemberIdentifier())) {
             return String.format("differing member identifier %s != %s",
                     a.getLogicalMemberIdentifier(), b.getLogicalMemberIdentifier());
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoEntityChangesPublishingTest.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoEntityChangesPublishingTest.java
similarity index 73%
copy from regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoEntityChangesPublishingTest.java
copy to regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoEntityChangesPublishingTest.java
index 1e9aa8b..3c2f4e3 100644
--- a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoEntityChangesPublishingTest.java
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoEntityChangesPublishingTest.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.applayer.publishing.jdo;
+package org.apache.isis.testdomain.publishing.jdo;
 
 import java.util.List;
 
@@ -32,26 +32,26 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import org.apache.isis.commons.internal.debug.xray.XrayEnable;
 import org.apache.isis.core.config.presets.IsisPresets;
-import org.apache.isis.testdomain.applayer.ApplicationLayerTestFactory;
-import org.apache.isis.testdomain.applayer.ApplicationLayerTestFactory.VerificationStage;
-import org.apache.isis.testdomain.applayer.publishing.conf.Configuration_usingEntityChangesPublishing;
 import org.apache.isis.testdomain.conf.Configuration_usingJdo;
+import org.apache.isis.testdomain.publishing.ApplicationLayerTestFactoryJdo;
+import org.apache.isis.testdomain.publishing.ApplicationLayerTestFactoryAbstract.VerificationStage;
+import org.apache.isis.testdomain.publishing.conf.Configuration_usingEntityChangesPublishing;
 import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
 
-import static org.apache.isis.testdomain.applayer.publishing.EntityChangesSubscriberForTesting.clearPublishedEntries;
-import static org.apache.isis.testdomain.applayer.publishing.EntityChangesSubscriberForTesting.getCreated;
-import static org.apache.isis.testdomain.applayer.publishing.EntityChangesSubscriberForTesting.getDeleted;
-import static org.apache.isis.testdomain.applayer.publishing.EntityChangesSubscriberForTesting.getLoaded;
-import static org.apache.isis.testdomain.applayer.publishing.EntityChangesSubscriberForTesting.getModified;
-import static org.apache.isis.testdomain.applayer.publishing.EntityChangesSubscriberForTesting.getUpdated;
+import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.clearPublishedEntries;
+import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getCreated;
+import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getDeleted;
+import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getLoaded;
+import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getModified;
+import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getUpdated;
 
 @SpringBootTest(
         classes = {
                 Configuration_usingJdo.class,
                 Configuration_usingEntityChangesPublishing.class,
-                ApplicationLayerTestFactory.class,
+                ApplicationLayerTestFactoryJdo.class,
                 XrayEnable.class
-        }, 
+        },
         properties = {
                 "logging.level.org.apache.isis.persistence.jdo.datanucleus5.persistence.IsisTransactionJdo=DEBUG",
                 "logging.level.org.apache.isis.core.runtimeservices.session.IsisInteractionFactoryDefault=DEBUG",
@@ -63,7 +63,7 @@ import static org.apache.isis.testdomain.applayer.publishing.EntityChangesSubscr
 })
 class JdoEntityChangesPublishingTest {
 
-    @Inject private ApplicationLayerTestFactory testFactory;
+    @Inject private ApplicationLayerTestFactoryJdo testFactory;
     @Inject private KVStoreForTesting kvStore;
 
     @DisplayName("Application Layer")
@@ -75,8 +75,8 @@ class JdoEntityChangesPublishingTest {
     private void given() {
         clearPublishedEntries(kvStore);
     }
-    
-    private void verify(VerificationStage verificationStage) {
+
+    private void verify(final VerificationStage verificationStage) {
         switch(verificationStage) {
         case PRE_COMMIT:
         case FAILURE_CASE:
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoEntityPropertyChangePublishingTest.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoEntityPropertyChangePublishingTest.java
similarity index 82%
copy from regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoEntityPropertyChangePublishingTest.java
copy to regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoEntityPropertyChangePublishingTest.java
index 18624bd..14874be 100644
--- a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoEntityPropertyChangePublishingTest.java
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoEntityPropertyChangePublishingTest.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.applayer.publishing.jdo;
+package org.apache.isis.testdomain.publishing.jdo;
 
 import java.util.List;
 
@@ -33,11 +33,11 @@ import org.springframework.test.context.TestPropertySource;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.debug.xray.XrayEnable;
 import org.apache.isis.core.config.presets.IsisPresets;
-import org.apache.isis.testdomain.applayer.ApplicationLayerTestFactory;
-import org.apache.isis.testdomain.applayer.ApplicationLayerTestFactory.VerificationStage;
-import org.apache.isis.testdomain.applayer.publishing.EntityPropertyChangeSubscriberForTesting;
-import org.apache.isis.testdomain.applayer.publishing.conf.Configuration_usingEntityPropertyChangePublishing;
 import org.apache.isis.testdomain.conf.Configuration_usingJdo;
+import org.apache.isis.testdomain.publishing.ApplicationLayerTestFactoryJdo;
+import org.apache.isis.testdomain.publishing.ApplicationLayerTestFactoryAbstract.VerificationStage;
+import org.apache.isis.testdomain.publishing.conf.Configuration_usingEntityPropertyChangePublishing;
+import org.apache.isis.testdomain.publishing.subscriber.EntityPropertyChangeSubscriberForTesting;
 import org.apache.isis.testdomain.util.CollectionAssertions;
 import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
 
@@ -47,9 +47,9 @@ import lombok.val;
         classes = {
                 Configuration_usingJdo.class,
                 Configuration_usingEntityPropertyChangePublishing.class,
-                ApplicationLayerTestFactory.class,
+                ApplicationLayerTestFactoryJdo.class,
                 XrayEnable.class
-        }, 
+        },
         properties = {
                 "logging.level.org.apache.isis.applib.services.publishing.log.*=DEBUG",
                 "logging.level.org.apache.isis.testdomain.util.rest.KVStoreForTesting=DEBUG",
@@ -62,7 +62,7 @@ import lombok.val;
 @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
 class JdoEntityPropertyChangePublishingTest {
 
-    @Inject private ApplicationLayerTestFactory testFactory;
+    @Inject private ApplicationLayerTestFactoryJdo testFactory;
     @Inject private KVStoreForTesting kvStore;
 
     @DisplayName("Application Layer")
@@ -75,7 +75,7 @@ class JdoEntityPropertyChangePublishingTest {
         EntityPropertyChangeSubscriberForTesting.clearPropertyChangeEntries(kvStore);
     }
 
-    private void verify(VerificationStage verificationStage) {
+    private void verify(final VerificationStage verificationStage) {
         switch(verificationStage) {
         case PRE_COMMIT:
         case FAILURE_CASE:
@@ -93,7 +93,7 @@ class JdoEntityPropertyChangePublishingTest {
 
     // -- HELPER
 
-    private void assertHasPropertyChangeEntries(Can<String> expectedAuditEntries) {
+    private void assertHasPropertyChangeEntries(final Can<String> expectedAuditEntries) {
         val actualAuditEntries = EntityPropertyChangeSubscriberForTesting.getPropertyChangeEntries(kvStore);
         CollectionAssertions.assertComponentWiseEquals(expectedAuditEntries, actualAuditEntries);
     }
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoExecutionPublishingTest.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoExecutionPublishingTest.java
similarity index 84%
copy from regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoExecutionPublishingTest.java
copy to regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoExecutionPublishingTest.java
index 7c53276..a7c7a21 100644
--- a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoExecutionPublishingTest.java
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jdo/JdoExecutionPublishingTest.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.applayer.publishing.jdo;
+package org.apache.isis.testdomain.publishing.jdo;
 
 import java.util.List;
 import java.util.Objects;
@@ -39,12 +39,12 @@ import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.debug.xray.XrayEnable;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.config.presets.IsisPresets;
-import org.apache.isis.testdomain.applayer.ApplicationLayerTestFactory;
-import org.apache.isis.testdomain.applayer.ApplicationLayerTestFactory.VerificationStage;
-import org.apache.isis.testdomain.applayer.publishing.ExecutionSubscriberForTesting;
-import org.apache.isis.testdomain.applayer.publishing.conf.Configuration_usingExecutionPublishing;
 import org.apache.isis.testdomain.conf.Configuration_usingJdo;
 import org.apache.isis.testdomain.jdo.entities.JdoBook;
+import org.apache.isis.testdomain.publishing.ApplicationLayerTestFactoryJdo;
+import org.apache.isis.testdomain.publishing.ApplicationLayerTestFactoryAbstract.VerificationStage;
+import org.apache.isis.testdomain.publishing.conf.Configuration_usingExecutionPublishing;
+import org.apache.isis.testdomain.publishing.subscriber.ExecutionSubscriberForTesting;
 import org.apache.isis.testdomain.util.CollectionAssertions;
 import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
 
@@ -54,7 +54,7 @@ import lombok.val;
         classes = {
                 Configuration_usingJdo.class,
                 Configuration_usingExecutionPublishing.class,
-                ApplicationLayerTestFactory.class,
+                ApplicationLayerTestFactoryJdo.class,
                 XrayEnable.class
         },
         properties = {
@@ -67,7 +67,7 @@ import lombok.val;
 })
 class JdoExecutionPublishingTest {
 
-    @Inject private ApplicationLayerTestFactory testFactory;
+    @Inject private ApplicationLayerTestFactoryJdo testFactory;
     @Inject private KVStoreForTesting kvStore;
 
     @TestFactory @DisplayName("Application Layer")
@@ -79,7 +79,7 @@ class JdoExecutionPublishingTest {
         ExecutionSubscriberForTesting.clearPublishedEntries(kvStore);
     }
 
-    private void verify(VerificationStage verificationStage) {
+    private void verify(final VerificationStage verificationStage) {
         switch(verificationStage) {
 
         case FAILURE_CASE:
@@ -104,13 +104,13 @@ class JdoExecutionPublishingTest {
 
     // -- HELPER
 
-    private void assertHasExecutionEntries(Can<Execution<?, ?>> expectedExecutions) {
+    private void assertHasExecutionEntries(final Can<Execution<?, ?>> expectedExecutions) {
         val actualExecutions = ExecutionSubscriberForTesting.getPublishedExecutions(kvStore);
         CollectionAssertions.assertComponentWiseEquals(
                 expectedExecutions, actualExecutions, this::executionDifference);
     }
 
-    private String executionDifference(Execution<?, ?> a, Execution<?, ?> b) {
+    private String executionDifference(final Execution<?, ?> a, final Execution<?, ?> b) {
         if(!Objects.equals(a.getMemberIdentifier(), b.getMemberIdentifier())) {
             return String.format("differing member identifier %s != %s",
                     a.getMemberIdentifier(), b.getMemberIdentifier());
@@ -132,12 +132,12 @@ class JdoExecutionPublishingTest {
         }
     }
 
-    private String actionInvocationDifference(ActionInvocation a, ActionInvocation b) {
+    private String actionInvocationDifference(final ActionInvocation a, final ActionInvocation b) {
         return null; // no difference
     }
 
 
-    private String porpertyEditDifference(PropertyEdit a, PropertyEdit b) {
+    private String porpertyEditDifference(final PropertyEdit a, final PropertyEdit b) {
         if(!Objects.equals(a.getNewValue(), b.getNewValue())) {
             return String.format("differing new value %s != %s",
                     a.getNewValue(), b.getNewValue());
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoCommandPublishingTest.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaCommandPublishingTest.java
similarity index 75%
rename from regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoCommandPublishingTest.java
rename to regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaCommandPublishingTest.java
index c5c09e6..3a62549 100644
--- a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoCommandPublishingTest.java
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaCommandPublishingTest.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.applayer.publishing.jdo;
+package org.apache.isis.testdomain.publishing.jpa;
 
 import java.util.List;
 import java.util.Objects;
@@ -36,11 +36,11 @@ import org.apache.isis.commons.internal.debug.xray.XrayEnable;
 import org.apache.isis.core.config.presets.IsisPresets;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 import org.apache.isis.schema.cmd.v2.PropertyDto;
-import org.apache.isis.testdomain.applayer.ApplicationLayerTestFactory;
-import org.apache.isis.testdomain.applayer.ApplicationLayerTestFactory.VerificationStage;
-import org.apache.isis.testdomain.applayer.publishing.CommandSubscriberForTesting;
-import org.apache.isis.testdomain.applayer.publishing.conf.Configuration_usingCommandPublishing;
-import org.apache.isis.testdomain.conf.Configuration_usingJdo;
+import org.apache.isis.testdomain.conf.Configuration_usingJpa;
+import org.apache.isis.testdomain.publishing.ApplicationLayerTestFactoryJpa;
+import org.apache.isis.testdomain.publishing.ApplicationLayerTestFactoryAbstract.VerificationStage;
+import org.apache.isis.testdomain.publishing.conf.Configuration_usingCommandPublishing;
+import org.apache.isis.testdomain.publishing.subscriber.CommandSubscriberForTesting;
 import org.apache.isis.testdomain.util.CollectionAssertions;
 import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
 
@@ -48,22 +48,20 @@ import lombok.val;
 
 @SpringBootTest(
         classes = {
-                Configuration_usingJdo.class,
+                Configuration_usingJpa.class,
                 Configuration_usingCommandPublishing.class,
-                ApplicationLayerTestFactory.class,
+                ApplicationLayerTestFactoryJpa.class,
                 XrayEnable.class
         },
         properties = {
-                "logging.level.org.apache.isis.persistence.jdo.datanucleus5.persistence.IsisTransactionJdo=DEBUG",
-                "logging.level.org.apache.isis.core.runtimeservices.session.IsisInteractionFactoryDefault=DEBUG",
-                "logging.level.org.apache.isis.persistence.jdo.datanucleus5.datanucleus.service.JdoPersistenceLifecycleService=DEBUG"
+                "logging.level.org.apache.isis.core.runtimeservices.session.IsisInteractionFactoryDefault=DEBUG"
         })
 @TestPropertySource({
     IsisPresets.UseLog4j2Test
 })
-class JdoCommandPublishingTest {
+class JpaCommandPublishingTest {
 
-    @Inject private ApplicationLayerTestFactory testFactory;
+    @Inject private ApplicationLayerTestFactoryJpa testFactory;
     @Inject private KVStoreForTesting kvStore;
 
     @TestFactory @DisplayName("Application Layer")
@@ -75,7 +73,7 @@ class JdoCommandPublishingTest {
         CommandSubscriberForTesting.clearPublishedCommands(kvStore);
     }
 
-    private void verify(VerificationStage verificationStage) {
+    private void verify(final VerificationStage verificationStage) {
         switch(verificationStage) {
 
         case FAILURE_CASE:
@@ -85,14 +83,14 @@ class JdoCommandPublishingTest {
 
 
 //            Interaction interaction = null;
-//            String propertyId = "org.apache.isis.testdomain.jdo.entities.JdoBook#name";
+//            String propertyId = "org.apache.isis.testdomain.jpa.entities.JpaBook#name";
 //            Object target = null;
 //            Object argValue = "Book #2";
 //            String targetMemberName = "name???";
-//            String targetClass = "org.apache.isis.testdomain.jdo.entities.JdoBook";
+//            String targetClass = "org.apache.isis.testdomain.jpa.entities.JpaBook";
 
             val propertyDto = new PropertyDto();
-            propertyDto.setLogicalMemberIdentifier("testdomain.jdo.Book#name");
+            propertyDto.setLogicalMemberIdentifier("testdomain.jpa.Book#name");
 
             val command = new Command(UUID.randomUUID());
             val commandDto = new CommandDto();
@@ -110,13 +108,13 @@ class JdoCommandPublishingTest {
 
     // -- HELPER
 
-    private void assertHasCommandEntries(Can<Command> expectedCommands) {
+    private void assertHasCommandEntries(final Can<Command> expectedCommands) {
         val actualCommands = CommandSubscriberForTesting.getPublishedCommands(kvStore);
         CollectionAssertions.assertComponentWiseEquals(
                 expectedCommands, actualCommands, this::commandDifference);
     }
 
-    private String commandDifference(Command a, Command b) {
+    private String commandDifference(final Command a, final Command b) {
         if(!Objects.equals(a.getLogicalMemberIdentifier(), b.getLogicalMemberIdentifier())) {
             return String.format("differing member identifier %s != %s",
                     a.getLogicalMemberIdentifier(), b.getLogicalMemberIdentifier());
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoEntityChangesPublishingTest.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaEntityChangesPublishingTest.java
similarity index 64%
rename from regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoEntityChangesPublishingTest.java
rename to regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaEntityChangesPublishingTest.java
index 1e9aa8b..2cfecb7 100644
--- a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoEntityChangesPublishingTest.java
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaEntityChangesPublishingTest.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.applayer.publishing.jdo;
+package org.apache.isis.testdomain.publishing.jpa;
 
 import java.util.List;
 
@@ -32,38 +32,36 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 
 import org.apache.isis.commons.internal.debug.xray.XrayEnable;
 import org.apache.isis.core.config.presets.IsisPresets;
-import org.apache.isis.testdomain.applayer.ApplicationLayerTestFactory;
-import org.apache.isis.testdomain.applayer.ApplicationLayerTestFactory.VerificationStage;
-import org.apache.isis.testdomain.applayer.publishing.conf.Configuration_usingEntityChangesPublishing;
-import org.apache.isis.testdomain.conf.Configuration_usingJdo;
+import org.apache.isis.testdomain.conf.Configuration_usingJpa;
+import org.apache.isis.testdomain.publishing.ApplicationLayerTestFactoryAbstract.VerificationStage;
+import org.apache.isis.testdomain.publishing.ApplicationLayerTestFactoryJpa;
+import org.apache.isis.testdomain.publishing.conf.Configuration_usingEntityChangesPublishing;
 import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
 
-import static org.apache.isis.testdomain.applayer.publishing.EntityChangesSubscriberForTesting.clearPublishedEntries;
-import static org.apache.isis.testdomain.applayer.publishing.EntityChangesSubscriberForTesting.getCreated;
-import static org.apache.isis.testdomain.applayer.publishing.EntityChangesSubscriberForTesting.getDeleted;
-import static org.apache.isis.testdomain.applayer.publishing.EntityChangesSubscriberForTesting.getLoaded;
-import static org.apache.isis.testdomain.applayer.publishing.EntityChangesSubscriberForTesting.getModified;
-import static org.apache.isis.testdomain.applayer.publishing.EntityChangesSubscriberForTesting.getUpdated;
+import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.clearPublishedEntries;
+import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getCreated;
+import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getDeleted;
+import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getLoaded;
+import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getModified;
+import static org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting.getUpdated;
 
 @SpringBootTest(
         classes = {
-                Configuration_usingJdo.class,
+                Configuration_usingJpa.class,
                 Configuration_usingEntityChangesPublishing.class,
-                ApplicationLayerTestFactory.class,
+                ApplicationLayerTestFactoryJpa.class,
                 XrayEnable.class
-        }, 
+        },
         properties = {
-                "logging.level.org.apache.isis.persistence.jdo.datanucleus5.persistence.IsisTransactionJdo=DEBUG",
                 "logging.level.org.apache.isis.core.runtimeservices.session.IsisInteractionFactoryDefault=DEBUG",
-                "logging.level.org.apache.isis.persistence.jdo.integration.changetracking.JdoLifecycleListener=DEBUG",
                 "logging.level.org.apache.isis.testdomain.util.kv.KVStoreForTesting=DEBUG",
         })
 @TestPropertySource({
     IsisPresets.UseLog4j2Test
 })
-class JdoEntityChangesPublishingTest {
+class JpaEntityChangesPublishingTest {
 
-    @Inject private ApplicationLayerTestFactory testFactory;
+    @Inject private ApplicationLayerTestFactoryJpa testFactory;
     @Inject private KVStoreForTesting kvStore;
 
     @DisplayName("Application Layer")
@@ -75,8 +73,8 @@ class JdoEntityChangesPublishingTest {
     private void given() {
         clearPublishedEntries(kvStore);
     }
-    
-    private void verify(VerificationStage verificationStage) {
+
+    private void verify(final VerificationStage verificationStage) {
         switch(verificationStage) {
         case PRE_COMMIT:
         case FAILURE_CASE:
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoEntityPropertyChangePublishingTest.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaEntityPropertyChangePublishingTest.java
similarity index 74%
rename from regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoEntityPropertyChangePublishingTest.java
rename to regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaEntityPropertyChangePublishingTest.java
index 18624bd..204a78b 100644
--- a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoEntityPropertyChangePublishingTest.java
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaEntityPropertyChangePublishingTest.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.applayer.publishing.jdo;
+package org.apache.isis.testdomain.publishing.jpa;
 
 import java.util.List;
 
@@ -33,11 +33,11 @@ import org.springframework.test.context.TestPropertySource;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.debug.xray.XrayEnable;
 import org.apache.isis.core.config.presets.IsisPresets;
-import org.apache.isis.testdomain.applayer.ApplicationLayerTestFactory;
-import org.apache.isis.testdomain.applayer.ApplicationLayerTestFactory.VerificationStage;
-import org.apache.isis.testdomain.applayer.publishing.EntityPropertyChangeSubscriberForTesting;
-import org.apache.isis.testdomain.applayer.publishing.conf.Configuration_usingEntityPropertyChangePublishing;
-import org.apache.isis.testdomain.conf.Configuration_usingJdo;
+import org.apache.isis.testdomain.conf.Configuration_usingJpa;
+import org.apache.isis.testdomain.publishing.ApplicationLayerTestFactoryAbstract.VerificationStage;
+import org.apache.isis.testdomain.publishing.ApplicationLayerTestFactoryJpa;
+import org.apache.isis.testdomain.publishing.conf.Configuration_usingEntityPropertyChangePublishing;
+import org.apache.isis.testdomain.publishing.subscriber.EntityPropertyChangeSubscriberForTesting;
 import org.apache.isis.testdomain.util.CollectionAssertions;
 import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
 
@@ -45,24 +45,23 @@ import lombok.val;
 
 @SpringBootTest(
         classes = {
-                Configuration_usingJdo.class,
+                Configuration_usingJpa.class,
                 Configuration_usingEntityPropertyChangePublishing.class,
-                ApplicationLayerTestFactory.class,
+                ApplicationLayerTestFactoryJpa.class,
                 XrayEnable.class
-        }, 
+        },
         properties = {
                 "logging.level.org.apache.isis.applib.services.publishing.log.*=DEBUG",
                 "logging.level.org.apache.isis.testdomain.util.rest.KVStoreForTesting=DEBUG",
-                "logging.level.org.apache.isis.persistence.jdo.integration.changetracking.JdoLifecycleListener=DEBUG",
                 "logging.level.org.apache.isis.core.transaction.changetracking.EntityChangeTrackerDefault=DEBUG",
         })
 @TestPropertySource({
     IsisPresets.UseLog4j2Test
 })
 @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
-class JdoEntityPropertyChangePublishingTest {
+class JpaEntityPropertyChangePublishingTest {
 
-    @Inject private ApplicationLayerTestFactory testFactory;
+    @Inject private ApplicationLayerTestFactoryJpa testFactory;
     @Inject private KVStoreForTesting kvStore;
 
     @DisplayName("Application Layer")
@@ -75,7 +74,7 @@ class JdoEntityPropertyChangePublishingTest {
         EntityPropertyChangeSubscriberForTesting.clearPropertyChangeEntries(kvStore);
     }
 
-    private void verify(VerificationStage verificationStage) {
+    private void verify(final VerificationStage verificationStage) {
         switch(verificationStage) {
         case PRE_COMMIT:
         case FAILURE_CASE:
@@ -84,7 +83,7 @@ class JdoEntityPropertyChangePublishingTest {
         case POST_COMMIT_WHEN_PROGRAMMATIC:
         case POST_COMMIT:
             assertHasPropertyChangeEntries(Can.of(
-                    "Jdo Book/name: 'Sample Book' -> 'Book #2'"));
+                    "Jpa Book/name: 'Sample Book' -> 'Book #2'"));
             break;
         default:
             // ignore ... no checks
@@ -93,7 +92,7 @@ class JdoEntityPropertyChangePublishingTest {
 
     // -- HELPER
 
-    private void assertHasPropertyChangeEntries(Can<String> expectedAuditEntries) {
+    private void assertHasPropertyChangeEntries(final Can<String> expectedAuditEntries) {
         val actualAuditEntries = EntityPropertyChangeSubscriberForTesting.getPropertyChangeEntries(kvStore);
         CollectionAssertions.assertComponentWiseEquals(expectedAuditEntries, actualAuditEntries);
     }
diff --git a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoExecutionPublishingTest.java b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaExecutionPublishingTest.java
similarity index 75%
rename from regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoExecutionPublishingTest.java
rename to regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaExecutionPublishingTest.java
index 7c53276..22b6601 100644
--- a/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/applayer/publishing/jdo/JdoExecutionPublishingTest.java
+++ b/regressiontests/incubating/src/test/java/org/apache/isis/testdomain/publishing/jpa/JpaExecutionPublishingTest.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.applayer.publishing.jdo;
+package org.apache.isis.testdomain.publishing.jpa;
 
 import java.util.List;
 import java.util.Objects;
@@ -39,12 +39,12 @@ import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.debug.xray.XrayEnable;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.config.presets.IsisPresets;
-import org.apache.isis.testdomain.applayer.ApplicationLayerTestFactory;
-import org.apache.isis.testdomain.applayer.ApplicationLayerTestFactory.VerificationStage;
-import org.apache.isis.testdomain.applayer.publishing.ExecutionSubscriberForTesting;
-import org.apache.isis.testdomain.applayer.publishing.conf.Configuration_usingExecutionPublishing;
-import org.apache.isis.testdomain.conf.Configuration_usingJdo;
-import org.apache.isis.testdomain.jdo.entities.JdoBook;
+import org.apache.isis.testdomain.conf.Configuration_usingJpa;
+import org.apache.isis.testdomain.jpa.entities.JpaBook;
+import org.apache.isis.testdomain.publishing.ApplicationLayerTestFactoryAbstract.VerificationStage;
+import org.apache.isis.testdomain.publishing.ApplicationLayerTestFactoryJpa;
+import org.apache.isis.testdomain.publishing.conf.Configuration_usingExecutionPublishing;
+import org.apache.isis.testdomain.publishing.subscriber.ExecutionSubscriberForTesting;
 import org.apache.isis.testdomain.util.CollectionAssertions;
 import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
 
@@ -52,22 +52,20 @@ import lombok.val;
 
 @SpringBootTest(
         classes = {
-                Configuration_usingJdo.class,
+                Configuration_usingJpa.class,
                 Configuration_usingExecutionPublishing.class,
-                ApplicationLayerTestFactory.class,
+                ApplicationLayerTestFactoryJpa.class,
                 XrayEnable.class
         },
         properties = {
-                "logging.level.org.apache.isis.persistence.jdo.datanucleus5.persistence.IsisTransactionJdo=DEBUG",
                 "logging.level.org.apache.isis.core.runtimeservices.session.IsisInteractionFactoryDefault=DEBUG",
-                "logging.level.org.apache.isis.persistence.jdo.datanucleus5.datanucleus.service.JdoPersistenceLifecycleService=DEBUG"
         })
 @TestPropertySource({
     IsisPresets.UseLog4j2Test
 })
-class JdoExecutionPublishingTest {
+class JpaExecutionPublishingTest {
 
-    @Inject private ApplicationLayerTestFactory testFactory;
+    @Inject private ApplicationLayerTestFactoryJpa testFactory;
     @Inject private KVStoreForTesting kvStore;
 
     @TestFactory @DisplayName("Application Layer")
@@ -79,7 +77,7 @@ class JdoExecutionPublishingTest {
         ExecutionSubscriberForTesting.clearPublishedEntries(kvStore);
     }
 
-    private void verify(VerificationStage verificationStage) {
+    private void verify(final VerificationStage verificationStage) {
         switch(verificationStage) {
 
         case FAILURE_CASE:
@@ -88,11 +86,11 @@ class JdoExecutionPublishingTest {
         case POST_COMMIT:
             Interaction interaction = null;
             Identifier propertyId = Identifier.propertyOrCollectionIdentifier(
-                    LogicalType.fqcn(JdoBook.class), "name");
+                    LogicalType.fqcn(JpaBook.class), "name");
             Object target = null;
             Object argValue = "Book #2";
             String targetMemberName = "name???";
-            String targetClass = "org.apache.isis.testdomain.jdo.entities.JdoBook";
+            String targetClass = "org.apache.isis.testdomain.jpa.entities.JpaBook";
             assertHasExecutionEntries(Can.of(
                     new PropertyEdit(interaction, propertyId, target, argValue, targetMemberName, targetClass)
                     ));
@@ -104,13 +102,13 @@ class JdoExecutionPublishingTest {
 
     // -- HELPER
 
-    private void assertHasExecutionEntries(Can<Execution<?, ?>> expectedExecutions) {
+    private void assertHasExecutionEntries(final Can<Execution<?, ?>> expectedExecutions) {
         val actualExecutions = ExecutionSubscriberForTesting.getPublishedExecutions(kvStore);
         CollectionAssertions.assertComponentWiseEquals(
                 expectedExecutions, actualExecutions, this::executionDifference);
     }
 
-    private String executionDifference(Execution<?, ?> a, Execution<?, ?> b) {
+    private String executionDifference(final Execution<?, ?> a, final Execution<?, ?> b) {
         if(!Objects.equals(a.getMemberIdentifier(), b.getMemberIdentifier())) {
             return String.format("differing member identifier %s != %s",
                     a.getMemberIdentifier(), b.getMemberIdentifier());
@@ -132,12 +130,12 @@ class JdoExecutionPublishingTest {
         }
     }
 
-    private String actionInvocationDifference(ActionInvocation a, ActionInvocation b) {
+    private String actionInvocationDifference(final ActionInvocation a, final ActionInvocation b) {
         return null; // no difference
     }
 
 
-    private String porpertyEditDifference(PropertyEdit a, PropertyEdit b) {
+    private String porpertyEditDifference(final PropertyEdit a, final PropertyEdit b) {
         if(!Objects.equals(a.getNewValue(), b.getNewValue())) {
             return String.format("differing new value %s != %s",
                     a.getNewValue(), b.getNewValue());
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/jpa/entities/JpaInventory.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/jpa/entities/JpaInventory.java
index b904488..dc49ee5 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/jpa/entities/JpaInventory.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/jpa/entities/JpaInventory.java
@@ -18,7 +18,7 @@
  */
 package org.apache.isis.testdomain.jpa.entities;
 
-import java.util.SortedSet;
+import java.util.Set;
 
 import javax.persistence.CascadeType;
 import javax.persistence.Column;
@@ -51,7 +51,11 @@ import lombok.ToString;
 @ToString
 public class JpaInventory {
 
-    public JpaInventory(String name, SortedSet<JpaProduct> products) {
+    public static JpaInventory of(final String name, final Set<JpaProduct> products) {
+        return new JpaInventory(name, products);
+    }
+
+    public JpaInventory(final String name, final Set<JpaProduct> products) {
         super();
         this.name = name;
         this.products = products;
@@ -73,5 +77,7 @@ public class JpaInventory {
     @Collection
     @OneToMany(cascade = CascadeType.PERSIST) @JoinColumn(nullable = true)
     private @Getter @Setter java.util.Collection<JpaProduct> products;
+
+
 }
 
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/ApplicationLayerTestFactoryAbstract.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/ApplicationLayerTestFactoryAbstract.java
new file mode 100644
index 0000000..c154984
--- /dev/null
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/ApplicationLayerTestFactoryAbstract.java
@@ -0,0 +1,217 @@
+/*
+ *  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.testdomain.publishing;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
+import java.util.function.Consumer;
+
+import org.junit.jupiter.api.DynamicTest;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.DynamicTest.dynamicTest;
+
+import org.apache.isis.applib.services.iactn.Interaction;
+import org.apache.isis.applib.services.iactnlayer.InteractionService;
+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.internal.debug.xray.XrayUi;
+import org.apache.isis.core.security.util.XrayUtil;
+import org.apache.isis.core.transaction.events.TransactionBeforeCompletionEvent;
+
+import lombok.Setter;
+import lombok.val;
+
+public abstract class ApplicationLayerTestFactoryAbstract {
+
+    public static enum VerificationStage {
+        PRE_COMMIT,
+        POST_COMMIT,
+        POST_COMMIT_WHEN_PROGRAMMATIC,
+        FAILURE_CASE,
+        POST_INTERACTION,
+        POST_INTERACTION_WHEN_PROGRAMMATIC,
+    }
+
+    @FunctionalInterface
+    private static interface InteractionTestRunner {
+        boolean run(Runnable given, Consumer<VerificationStage> verifier) throws Exception;
+    }
+
+    @Service
+    public static class PreCommitListener {
+
+        @Setter private Consumer<VerificationStage> verifier;
+
+        /** TRANSACTION END BOUNDARY */
+        @EventListener(TransactionBeforeCompletionEvent.class)
+        public void onPreCommit(final TransactionBeforeCompletionEvent event) {
+            if(verifier!=null) {
+                verifier.accept(VerificationStage.PRE_COMMIT);
+            }
+        }
+    }
+
+    // -- DEPENDENCIES
+
+    protected abstract InteractionService getInteractionService();
+    protected abstract TransactionService getTransactionService();
+
+    // -- CREATE DYNAMIC TESTS
+
+    public final List<DynamicTest> generateTests(
+            final Runnable given,
+            final Consumer<VerificationStage> verifier) {
+
+        val dynamicTests = Can.<DynamicTest>of(
+
+                interactionTest("Programmatic Execution",
+                        given, verifier,
+                        VerificationStage.POST_INTERACTION_WHEN_PROGRAMMATIC,
+                        this::programmaticExecution),
+                interactionTest("Interaction Api Execution",
+                        given, verifier,
+                        VerificationStage.POST_INTERACTION,
+                        this::interactionApiExecution),
+                interactionTest("Wrapper Sync Execution w/o Rules",
+                        given, verifier,
+                        VerificationStage.POST_INTERACTION,
+                        this::wrapperSyncExecutionNoRules),
+                interactionTest("Wrapper Sync Execution w/ Rules (expected to fail w/ DisabledException)",
+                        given, verifier,
+                        VerificationStage.POST_INTERACTION,
+                        this::wrapperSyncExecutionWithFailure),
+                interactionTest("Wrapper Async Execution w/o Rules",
+                        given, verifier,
+                        VerificationStage.POST_INTERACTION,
+                        this::wrapperAsyncExecutionNoRules),
+                interactionTest("Wrapper Async Execution w/ Rules (expected to fail w/ DisabledException)",
+                        given, verifier,
+                        VerificationStage.POST_INTERACTION,
+                        this::wrapperAsyncExecutionWithFailure)
+                );
+
+        return XrayUi.isXrayEnabled()
+                ? dynamicTests
+                        .add(dynamicTest("wait for xray viewer", XrayUi::waitForShutdown))
+                        .toList()
+                : dynamicTests
+                        .toList();
+
+    }
+
+    protected abstract boolean programmaticExecution(
+            final Runnable given,
+            final Consumer<VerificationStage> verifier);
+
+    protected abstract boolean interactionApiExecution(
+            final Runnable given,
+            final Consumer<VerificationStage> verifier);
+
+    protected abstract boolean wrapperSyncExecutionNoRules(
+            final Runnable given,
+            final Consumer<VerificationStage> verifier);
+
+    protected abstract boolean wrapperSyncExecutionWithFailure(
+            final Runnable given,
+            final Consumer<VerificationStage> verifier);
+
+    protected abstract boolean wrapperAsyncExecutionNoRules(
+            final Runnable given,
+            final Consumer<VerificationStage> verifier) throws InterruptedException, ExecutionException, TimeoutException;
+
+    protected abstract boolean wrapperAsyncExecutionWithFailure(
+            final Runnable given,
+            final Consumer<VerificationStage> verifier);
+
+
+    // -- HELPER
+
+    private final DynamicTest interactionTest(
+            final String displayName,
+            final Runnable given,
+            final Consumer<VerificationStage> verifier,
+            final VerificationStage onSuccess,
+            final InteractionTestRunner interactionTestRunner) {
+
+        return dynamicTest(displayName, ()->{
+
+            xrayAddTest(displayName);
+
+            assertFalse(getInteractionService().isInInteraction());
+            assert_no_initial_tx_context();
+
+            final boolean isSuccesfulRun = getInteractionService().callAnonymous(()->{
+                val currentInteraction = getInteractionService().currentInteraction();
+                xrayEnterInteraction(currentInteraction);
+                val result = interactionTestRunner.run(given, verifier);
+                xrayExitInteraction();
+                return result;
+            });
+
+            getInteractionService().closeInteractionLayers();
+
+            if(isSuccesfulRun) {
+                verifier.accept(onSuccess);
+            }
+
+        });
+    }
+
+    private final void assert_no_initial_tx_context() {
+        val txState = getTransactionService().currentTransactionState();
+        assertEquals(TransactionState.NONE, txState);
+    }
+
+    // -- XRAY
+
+    private final void xrayAddTest(final String name) {
+
+        val threadId = XrayUtil.currentThreadAsMemento();
+
+        XrayUi.updateModel(model->{
+            model.addContainerNode(
+                    model.getThreadNode(threadId),
+                    String.format("Test: %s", name));
+
+        });
+
+    }
+
+    protected void xrayEnterTansaction(final Propagation propagation) {
+    }
+
+    protected void xrayExitTansaction() {
+    }
+
+    private void xrayEnterInteraction(final Optional<Interaction> currentInteraction) {
+    }
+
+    private void xrayExitInteraction() {
+    }
+
+
+}
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/publishing/ApplicationLayerTestFactoryJdo.java
similarity index 61%
copy from regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/ApplicationLayerTestFactory.java
copy to regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/ApplicationLayerTestFactoryJdo.java
index 5f93b59..f796df1 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/ApplicationLayerTestFactory.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/ApplicationLayerTestFactoryJdo.java
@@ -16,11 +16,9 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.applayer;
+package org.apache.isis.testdomain.publishing;
 
 import java.util.HashSet;
-import java.util.List;
-import java.util.Optional;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -31,183 +29,67 @@ import javax.inject.Named;
 import javax.jdo.JDOHelper;
 import javax.jdo.PersistenceManagerFactory;
 
-import org.junit.jupiter.api.DynamicTest;
 import org.springframework.context.annotation.Import;
-import org.springframework.context.event.EventListener;
 import org.springframework.stereotype.Component;
-import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Propagation;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.fail;
-import static org.junit.jupiter.api.DynamicTest.dynamicTest;
 
 import org.apache.isis.applib.annotation.Where;
-import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.applib.services.iactnlayer.InteractionService;
 import org.apache.isis.applib.services.repository.RepositoryService;
 import org.apache.isis.applib.services.wrapper.DisabledException;
 import org.apache.isis.applib.services.wrapper.WrapperFactory;
 import org.apache.isis.applib.services.wrapper.control.SyncControl;
 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.internal.debug._Probe;
-import org.apache.isis.commons.internal.debug.xray.XrayUi;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.commons.internal.functions._Functions.CheckedConsumer;
-import org.apache.isis.applib.services.iactnlayer.InteractionLayerTracker;
 import org.apache.isis.core.metamodel.interactions.managed.PropertyInteraction;
 import org.apache.isis.core.metamodel.objectmanager.ObjectManager;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.core.security.util.XrayUtil;
-import org.apache.isis.core.transaction.events.TransactionBeforeCompletionEvent;
 import org.apache.isis.testdomain.jdo.JdoTestDomainPersona;
 import org.apache.isis.testdomain.jdo.entities.JdoBook;
 import org.apache.isis.testdomain.jdo.entities.JdoInventory;
 import org.apache.isis.testdomain.jdo.entities.JdoProduct;
+import org.apache.isis.testdomain.publishing.ApplicationLayerTestFactoryAbstract.PreCommitListener;
 import org.apache.isis.testing.fixtures.applib.fixturescripts.FixtureScripts;
 
 import static org.apache.isis.applib.services.wrapper.control.AsyncControl.returningVoid;
 
+import lombok.AccessLevel;
+import lombok.Getter;
 import lombok.RequiredArgsConstructor;
-import lombok.Setter;
 import lombok.val;
 
 @Component
 @Import({
-    ApplicationLayerTestFactory.PreCommitListener.class
+    PreCommitListener.class
 })
 @RequiredArgsConstructor(onConstructor_ = {@Inject})
-public class ApplicationLayerTestFactory {
+public class ApplicationLayerTestFactoryJdo
+extends ApplicationLayerTestFactoryAbstract {
 
     private final RepositoryService repository;
     private final WrapperFactory wrapper;
-    private final TransactionService transactionService;
     private final ObjectManager objectManager;
     private final FixtureScripts fixtureScripts;
     private final PreCommitListener preCommitListener;
+
+    @Getter(onMethod_ = {@Override}, value = AccessLevel.PROTECTED)
     private final InteractionService interactionService;
-    private final InteractionLayerTracker interactionLayerTracker;
+
+    @Getter(onMethod_ = {@Override}, value = AccessLevel.PROTECTED)
+    private final TransactionService transactionService;
 
     @Named("transaction-aware-pmf-proxy")
     private final PersistenceManagerFactory pmf;
 
-    public static enum VerificationStage {
-        PRE_COMMIT,
-        POST_COMMIT,
-        POST_COMMIT_WHEN_PROGRAMMATIC,
-        FAILURE_CASE,
-        POST_INTERACTION,
-        POST_INTERACTION_WHEN_PROGRAMMATIC,
-    }
-
-    @Service
-    public static class PreCommitListener {
-
-        @Setter private Consumer<VerificationStage> verifier;
-
-        /** TRANSACTION END BOUNDARY */
-        @EventListener(TransactionBeforeCompletionEvent.class)
-        public void onPreCommit(TransactionBeforeCompletionEvent event) {
-            if(verifier!=null) {
-                verifier.accept(VerificationStage.PRE_COMMIT);
-            }
-        }
-    }
-
-    public List<DynamicTest> generateTests(
-            final Runnable given,
-            final Consumer<VerificationStage> verifier) {
-
-        val dynamicTests = Can.<DynamicTest>of(
-
-                interactionTest("Programmatic Execution",
-                        given, verifier,
-                        VerificationStage.POST_INTERACTION_WHEN_PROGRAMMATIC,
-                        this::programmaticExecution),
-                interactionTest("Interaction Api Execution",
-                        given, verifier,
-                        VerificationStage.POST_INTERACTION,
-                        this::interactionApiExecution),
-                interactionTest("Wrapper Sync Execution w/o Rules",
-                        given, verifier,
-                        VerificationStage.POST_INTERACTION,
-                        this::wrapperSyncExecutionNoRules),
-                interactionTest("Wrapper Sync Execution w/ Rules (expected to fail w/ DisabledException)",
-                        given, verifier,
-                        VerificationStage.POST_INTERACTION,
-                        this::wrapperSyncExecutionWithFailure),
-                interactionTest("Wrapper Async Execution w/o Rules",
-                        given, verifier,
-                        VerificationStage.POST_INTERACTION,
-                        this::wrapperAsyncExecutionNoRules),
-                interactionTest("Wrapper Async Execution w/ Rules (expected to fail w/ DisabledException)",
-                        given, verifier,
-                        VerificationStage.POST_INTERACTION,
-                        this::wrapperAsyncExecutionWithFailure)
-                );
-
-        return XrayUi.isXrayEnabled()
-                ? dynamicTests
-                        .add(dynamicTest("wait for xray viewer", XrayUi::waitForShutdown))
-                        .toList()
-                : dynamicTests
-                        .toList();
-
-    }
-
-    // -- INTERACTION TEST FACTORY
-
-    @FunctionalInterface
-    private static interface InteractionTestRunner {
-        boolean run(Runnable given, Consumer<VerificationStage> verifier) throws Exception;
-    }
-
-    private DynamicTest interactionTest(
-            final String displayName,
-            final Runnable given,
-            final Consumer<VerificationStage> verifier,
-            final VerificationStage onSuccess,
-            final InteractionTestRunner interactionTestRunner) {
-
-        return dynamicTest(displayName, ()->{
-
-            xrayAddTest(displayName);
-
-            assertFalse(interactionService.isInInteraction());
-            assert_no_initial_tx_context();
-
-            final boolean isSuccesfulRun = interactionService.callAnonymous(()->{
-                val currentInteraction = interactionLayerTracker.currentInteraction();
-                xrayEnterInteraction(currentInteraction);
-                val result = interactionTestRunner.run(given, verifier);
-                xrayExitInteraction();
-                return result;
-            });
-
-            interactionService.closeInteractionLayers();
-
-            if(isSuccesfulRun) {
-                verifier.accept(onSuccess);
-            }
-
-        });
-    }
-
-
-    // -- TESTS - ENSURE TESTS ARE CORRECTLY INVOKED
-
-    void assert_no_initial_tx_context() {
-        val txState = transactionService.currentTransactionState();
-        assertEquals(TransactionState.NONE, txState);
-    }
-
     // -- TESTS - WRAPPER SYNC
 
-    private boolean programmaticExecution(
+    @Override
+    protected boolean programmaticExecution(
             final Runnable given,
             final Consumer<VerificationStage> verifier) {
 
@@ -239,7 +121,8 @@ public class ApplicationLayerTestFactory {
 
     // -- TESTS - INTERACTION API
 
-    private boolean interactionApiExecution(
+    @Override
+    protected boolean interactionApiExecution(
             final Runnable given,
             final Consumer<VerificationStage> verifier) {
 
@@ -274,7 +157,8 @@ public class ApplicationLayerTestFactory {
 
     // -- TESTS - WRAPPER SYNC
 
-    private boolean wrapperSyncExecutionNoRules(
+    @Override
+    protected boolean wrapperSyncExecutionNoRules(
             final Runnable given,
             final Consumer<VerificationStage> verifier) {
 
@@ -302,7 +186,8 @@ public class ApplicationLayerTestFactory {
         return true;
     }
 
-    private boolean wrapperSyncExecutionWithFailure(
+    @Override
+    protected boolean wrapperSyncExecutionWithFailure(
             final Runnable given,
             final Consumer<VerificationStage> verifier) {
 
@@ -336,7 +221,8 @@ public class ApplicationLayerTestFactory {
 
     // -- TESTS - WRAPPER ASYNC
 
-    private boolean wrapperAsyncExecutionNoRules(
+    @Override
+    protected boolean wrapperAsyncExecutionNoRules(
             final Runnable given,
             final Consumer<VerificationStage> verifier) throws InterruptedException, ExecutionException, TimeoutException {
 
@@ -368,7 +254,8 @@ public class ApplicationLayerTestFactory {
         return true;
     }
 
-    private boolean wrapperAsyncExecutionWithFailure(
+    @Override
+    protected boolean wrapperAsyncExecutionWithFailure(
             final Runnable given,
             final Consumer<VerificationStage> verifier) {
 
@@ -437,7 +324,7 @@ public class ApplicationLayerTestFactory {
         });
     }
 
-    private void withBookDoTransactional(CheckedConsumer<JdoBook> transactionalBookConsumer) {
+    private void withBookDoTransactional(final CheckedConsumer<JdoBook> transactionalBookConsumer) {
 
         xrayEnterTansaction(Propagation.REQUIRES_NEW);
 
@@ -451,31 +338,5 @@ public class ApplicationLayerTestFactory {
         xrayExitTansaction();
     }
 
-    // -- XRAY
-
-    private void xrayAddTest(String name) {
-
-        val threadId = XrayUtil.currentThreadAsMemento();
-
-        XrayUi.updateModel(model->{
-            model.addContainerNode(
-                    model.getThreadNode(threadId),
-                    String.format("Test: %s", name));
-
-        });
-
-    }
-
-    private void xrayEnterTansaction(Propagation propagation) {
-    }
-
-    private void xrayExitTansaction() {
-    }
-
-    private void xrayEnterInteraction(Optional<Interaction> currentInteraction) {
-    }
-
-    private void xrayExitInteraction() {
-    }
 
 }
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/publishing/ApplicationLayerTestFactoryJpa.java
similarity index 53%
rename from regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/ApplicationLayerTestFactory.java
rename to regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/ApplicationLayerTestFactoryJpa.java
index 5f93b59..688ba0c0 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/ApplicationLayerTestFactory.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/ApplicationLayerTestFactoryJpa.java
@@ -16,203 +16,82 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.applayer;
+package org.apache.isis.testdomain.publishing;
 
 import java.util.HashSet;
-import java.util.List;
-import java.util.Optional;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.function.Consumer;
 
 import javax.inject.Inject;
-import javax.inject.Named;
-import javax.jdo.JDOHelper;
-import javax.jdo.PersistenceManagerFactory;
 
-import org.junit.jupiter.api.DynamicTest;
 import org.springframework.context.annotation.Import;
-import org.springframework.context.event.EventListener;
 import org.springframework.stereotype.Component;
-import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Propagation;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.fail;
-import static org.junit.jupiter.api.DynamicTest.dynamicTest;
 
 import org.apache.isis.applib.annotation.Where;
-import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.applib.services.iactnlayer.InteractionService;
 import org.apache.isis.applib.services.repository.RepositoryService;
 import org.apache.isis.applib.services.wrapper.DisabledException;
 import org.apache.isis.applib.services.wrapper.WrapperFactory;
 import org.apache.isis.applib.services.wrapper.control.SyncControl;
 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.internal.debug._Probe;
-import org.apache.isis.commons.internal.debug.xray.XrayUi;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.commons.internal.functions._Functions.CheckedConsumer;
-import org.apache.isis.applib.services.iactnlayer.InteractionLayerTracker;
 import org.apache.isis.core.metamodel.interactions.managed.PropertyInteraction;
 import org.apache.isis.core.metamodel.objectmanager.ObjectManager;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.core.security.util.XrayUtil;
-import org.apache.isis.core.transaction.events.TransactionBeforeCompletionEvent;
-import org.apache.isis.testdomain.jdo.JdoTestDomainPersona;
-import org.apache.isis.testdomain.jdo.entities.JdoBook;
-import org.apache.isis.testdomain.jdo.entities.JdoInventory;
-import org.apache.isis.testdomain.jdo.entities.JdoProduct;
+import org.apache.isis.persistence.jpa.applib.services.JpaSupportService;
+import org.apache.isis.testdomain.jpa.JpaTestDomainPersona;
+import org.apache.isis.testdomain.jpa.entities.JpaBook;
+import org.apache.isis.testdomain.jpa.entities.JpaInventory;
+import org.apache.isis.testdomain.jpa.entities.JpaProduct;
+import org.apache.isis.testdomain.publishing.ApplicationLayerTestFactoryAbstract.PreCommitListener;
 import org.apache.isis.testing.fixtures.applib.fixturescripts.FixtureScripts;
 
 import static org.apache.isis.applib.services.wrapper.control.AsyncControl.returningVoid;
 
+import lombok.AccessLevel;
+import lombok.Getter;
 import lombok.RequiredArgsConstructor;
-import lombok.Setter;
 import lombok.val;
 
 @Component
 @Import({
-    ApplicationLayerTestFactory.PreCommitListener.class
+    PreCommitListener.class
 })
 @RequiredArgsConstructor(onConstructor_ = {@Inject})
-public class ApplicationLayerTestFactory {
+public class ApplicationLayerTestFactoryJpa
+extends ApplicationLayerTestFactoryAbstract {
 
     private final RepositoryService repository;
     private final WrapperFactory wrapper;
-    private final TransactionService transactionService;
     private final ObjectManager objectManager;
     private final FixtureScripts fixtureScripts;
     private final PreCommitListener preCommitListener;
-    private final InteractionService interactionService;
-    private final InteractionLayerTracker interactionLayerTracker;
-
-    @Named("transaction-aware-pmf-proxy")
-    private final PersistenceManagerFactory pmf;
-
-    public static enum VerificationStage {
-        PRE_COMMIT,
-        POST_COMMIT,
-        POST_COMMIT_WHEN_PROGRAMMATIC,
-        FAILURE_CASE,
-        POST_INTERACTION,
-        POST_INTERACTION_WHEN_PROGRAMMATIC,
-    }
-
-    @Service
-    public static class PreCommitListener {
-
-        @Setter private Consumer<VerificationStage> verifier;
-
-        /** TRANSACTION END BOUNDARY */
-        @EventListener(TransactionBeforeCompletionEvent.class)
-        public void onPreCommit(TransactionBeforeCompletionEvent event) {
-            if(verifier!=null) {
-                verifier.accept(VerificationStage.PRE_COMMIT);
-            }
-        }
-    }
-
-    public List<DynamicTest> generateTests(
-            final Runnable given,
-            final Consumer<VerificationStage> verifier) {
-
-        val dynamicTests = Can.<DynamicTest>of(
-
-                interactionTest("Programmatic Execution",
-                        given, verifier,
-                        VerificationStage.POST_INTERACTION_WHEN_PROGRAMMATIC,
-                        this::programmaticExecution),
-                interactionTest("Interaction Api Execution",
-                        given, verifier,
-                        VerificationStage.POST_INTERACTION,
-                        this::interactionApiExecution),
-                interactionTest("Wrapper Sync Execution w/o Rules",
-                        given, verifier,
-                        VerificationStage.POST_INTERACTION,
-                        this::wrapperSyncExecutionNoRules),
-                interactionTest("Wrapper Sync Execution w/ Rules (expected to fail w/ DisabledException)",
-                        given, verifier,
-                        VerificationStage.POST_INTERACTION,
-                        this::wrapperSyncExecutionWithFailure),
-                interactionTest("Wrapper Async Execution w/o Rules",
-                        given, verifier,
-                        VerificationStage.POST_INTERACTION,
-                        this::wrapperAsyncExecutionNoRules),
-                interactionTest("Wrapper Async Execution w/ Rules (expected to fail w/ DisabledException)",
-                        given, verifier,
-                        VerificationStage.POST_INTERACTION,
-                        this::wrapperAsyncExecutionWithFailure)
-                );
-
-        return XrayUi.isXrayEnabled()
-                ? dynamicTests
-                        .add(dynamicTest("wait for xray viewer", XrayUi::waitForShutdown))
-                        .toList()
-                : dynamicTests
-                        .toList();
-
-    }
-
-    // -- INTERACTION TEST FACTORY
-
-    @FunctionalInterface
-    private static interface InteractionTestRunner {
-        boolean run(Runnable given, Consumer<VerificationStage> verifier) throws Exception;
-    }
-
-    private DynamicTest interactionTest(
-            final String displayName,
-            final Runnable given,
-            final Consumer<VerificationStage> verifier,
-            final VerificationStage onSuccess,
-            final InteractionTestRunner interactionTestRunner) {
-
-        return dynamicTest(displayName, ()->{
-
-            xrayAddTest(displayName);
-
-            assertFalse(interactionService.isInInteraction());
-            assert_no_initial_tx_context();
-
-            final boolean isSuccesfulRun = interactionService.callAnonymous(()->{
-                val currentInteraction = interactionLayerTracker.currentInteraction();
-                xrayEnterInteraction(currentInteraction);
-                val result = interactionTestRunner.run(given, verifier);
-                xrayExitInteraction();
-                return result;
-            });
-
-            interactionService.closeInteractionLayers();
-
-            if(isSuccesfulRun) {
-                verifier.accept(onSuccess);
-            }
-
-        });
-    }
+    private final JpaSupportService jpaSupport;
 
+    @Getter(onMethod_ = {@Override}, value = AccessLevel.PROTECTED)
+    private final InteractionService interactionService;
 
-    // -- TESTS - ENSURE TESTS ARE CORRECTLY INVOKED
+    @Getter(onMethod_ = {@Override}, value = AccessLevel.PROTECTED)
+    private final TransactionService transactionService;
 
-    void assert_no_initial_tx_context() {
-        val txState = transactionService.currentTransactionState();
-        assertEquals(TransactionState.NONE, txState);
-    }
 
     // -- TESTS - WRAPPER SYNC
 
-    private boolean programmaticExecution(
+    @Override
+    protected boolean programmaticExecution(
             final Runnable given,
             final Consumer<VerificationStage> verifier) {
 
         // given
-        setupBookForJdo();
+        setupBookForJpa();
 
         preCommitListener.setVerifier(verifier);
 
@@ -239,12 +118,13 @@ public class ApplicationLayerTestFactory {
 
     // -- TESTS - INTERACTION API
 
-    private boolean interactionApiExecution(
+    @Override
+    protected boolean interactionApiExecution(
             final Runnable given,
             final Consumer<VerificationStage> verifier) {
 
         // given
-        setupBookForJdo();
+        setupBookForJpa();
 
         // when
         withBookDoTransactional(book->{
@@ -274,12 +154,13 @@ public class ApplicationLayerTestFactory {
 
     // -- TESTS - WRAPPER SYNC
 
-    private boolean wrapperSyncExecutionNoRules(
+    @Override
+    protected boolean wrapperSyncExecutionNoRules(
             final Runnable given,
             final Consumer<VerificationStage> verifier) {
 
         // given
-        setupBookForJdo();
+        setupBookForJpa();
 
         // when
         withBookDoTransactional(book->{
@@ -302,12 +183,13 @@ public class ApplicationLayerTestFactory {
         return true;
     }
 
-    private boolean wrapperSyncExecutionWithFailure(
+    @Override
+    protected boolean wrapperSyncExecutionWithFailure(
             final Runnable given,
             final Consumer<VerificationStage> verifier) {
 
         // given
-        setupBookForJdo();
+        setupBookForJpa();
 
         // when
         withBookDoTransactional(book->{
@@ -336,12 +218,13 @@ public class ApplicationLayerTestFactory {
 
     // -- TESTS - WRAPPER ASYNC
 
-    private boolean wrapperAsyncExecutionNoRules(
+    @Override
+    protected boolean wrapperAsyncExecutionNoRules(
             final Runnable given,
             final Consumer<VerificationStage> verifier) throws InterruptedException, ExecutionException, TimeoutException {
 
         // given
-        setupBookForJdo();
+        setupBookForJpa();
         val asyncControl = returningVoid().withSkipRules(); // don't enforce rules
 
         // when
@@ -368,12 +251,13 @@ public class ApplicationLayerTestFactory {
         return true;
     }
 
-    private boolean wrapperAsyncExecutionWithFailure(
+    @Override
+    protected boolean wrapperAsyncExecutionWithFailure(
             final Runnable given,
             final Consumer<VerificationStage> verifier) {
 
         // given
-        setupBookForJdo();
+        setupBookForJpa();
 
         // when
         withBookDoTransactional(book->{
@@ -404,45 +288,46 @@ public class ApplicationLayerTestFactory {
 
     // -- TEST SETUP
 
-    private void setupBookForJdo() {
+    private void setupBookForJpa() {
 
         transactionService.runTransactional(Propagation.REQUIRES_NEW, ()->{
-            val pm = pmf.getPersistenceManager();
+
+            val em = jpaSupport.getEntityManagerElseFail(JpaBook.class);
 
             // cleanup
-            fixtureScripts.runPersona(JdoTestDomainPersona.PurgeAll);
+            fixtureScripts.runPersona(JpaTestDomainPersona.PurgeAll);
 
             // given Inventory with 1 Book
 
-            val products = new HashSet<JdoProduct>();
+            val products = new HashSet<JpaProduct>();
 
-            products.add(JdoBook.of(
+            products.add(JpaBook.of(
                     "Sample Book", "A sample book for testing.", 99.,
                     "Sample Author", "Sample ISBN", "Sample Publisher"));
 
-            val inventory = JdoInventory.of("Sample Inventory", products);
-            pm.makePersistent(inventory);
+            val inventory = JpaInventory.of("Sample Inventory", products);
+            em.persist(inventory);
 
             inventory.getProducts().forEach(product->{
-                val prod = pm.makePersistent(product);
+                em.persist(product);
 
-                _Probe.errOut("PROD ID: %s", JDOHelper.getObjectId(prod));
+                _Probe.errOut("PROD ID: %s", product.getId());
 
             });
 
-            //fixtureScripts.runPersona(JdoTestDomainPersona.InventoryWith1Book);
+            //fixtureScripts.runPersona(JpaTestDomainPersona.InventoryWith1Book);
 
-            pm.flush();
+            em.flush();
 
         });
     }
 
-    private void withBookDoTransactional(CheckedConsumer<JdoBook> transactionalBookConsumer) {
+    private void withBookDoTransactional(final CheckedConsumer<JpaBook> transactionalBookConsumer) {
 
         xrayEnterTansaction(Propagation.REQUIRES_NEW);
 
         transactionService.runTransactional(Propagation.REQUIRES_NEW, ()->{
-            val book = repository.allInstances(JdoBook.class).listIterator().next();
+            val book = repository.allInstances(JpaBook.class).listIterator().next();
             transactionalBookConsumer.accept(book);
 
         })
@@ -451,31 +336,4 @@ public class ApplicationLayerTestFactory {
         xrayExitTansaction();
     }
 
-    // -- XRAY
-
-    private void xrayAddTest(String name) {
-
-        val threadId = XrayUtil.currentThreadAsMemento();
-
-        XrayUi.updateModel(model->{
-            model.addContainerNode(
-                    model.getThreadNode(threadId),
-                    String.format("Test: %s", name));
-
-        });
-
-    }
-
-    private void xrayEnterTansaction(Propagation propagation) {
-    }
-
-    private void xrayExitTansaction() {
-    }
-
-    private void xrayEnterInteraction(Optional<Interaction> currentInteraction) {
-    }
-
-    private void xrayExitInteraction() {
-    }
-
 }
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/conf/Configuration_usingCommandPublishing.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/conf/Configuration_usingCommandPublishing.java
similarity index 88%
rename from regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/conf/Configuration_usingCommandPublishing.java
rename to regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/conf/Configuration_usingCommandPublishing.java
index 84addf9..c53ce75 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/conf/Configuration_usingCommandPublishing.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/conf/Configuration_usingCommandPublishing.java
@@ -16,12 +16,12 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.applayer.publishing.conf;
+package org.apache.isis.testdomain.publishing.conf;
 
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
 
-import org.apache.isis.testdomain.applayer.publishing.CommandSubscriberForTesting;
+import org.apache.isis.testdomain.publishing.subscriber.CommandSubscriberForTesting;
 import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
 
 @Configuration
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/conf/Configuration_usingEntityChangesPublishing.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/conf/Configuration_usingEntityChangesPublishing.java
similarity index 88%
rename from regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/conf/Configuration_usingEntityChangesPublishing.java
rename to regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/conf/Configuration_usingEntityChangesPublishing.java
index ef77cef..db24303 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/conf/Configuration_usingEntityChangesPublishing.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/conf/Configuration_usingEntityChangesPublishing.java
@@ -16,12 +16,12 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.applayer.publishing.conf;
+package org.apache.isis.testdomain.publishing.conf;
 
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
 
-import org.apache.isis.testdomain.applayer.publishing.EntityChangesSubscriberForTesting;
+import org.apache.isis.testdomain.publishing.subscriber.EntityChangesSubscriberForTesting;
 import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
 
 @Configuration
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/conf/Configuration_usingEntityPropertyChangePublishing.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/conf/Configuration_usingEntityPropertyChangePublishing.java
similarity index 87%
rename from regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/conf/Configuration_usingEntityPropertyChangePublishing.java
rename to regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/conf/Configuration_usingEntityPropertyChangePublishing.java
index 337a3a0..b2a530e 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/conf/Configuration_usingEntityPropertyChangePublishing.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/conf/Configuration_usingEntityPropertyChangePublishing.java
@@ -16,12 +16,12 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.applayer.publishing.conf;
+package org.apache.isis.testdomain.publishing.conf;
 
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
 
-import org.apache.isis.testdomain.applayer.publishing.EntityPropertyChangeSubscriberForTesting;
+import org.apache.isis.testdomain.publishing.subscriber.EntityPropertyChangeSubscriberForTesting;
 
 @Configuration
 @Import({
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/conf/Configuration_usingExecutionPublishing.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/conf/Configuration_usingExecutionPublishing.java
similarity index 88%
rename from regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/conf/Configuration_usingExecutionPublishing.java
rename to regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/conf/Configuration_usingExecutionPublishing.java
index 55a0d83..d091389 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/conf/Configuration_usingExecutionPublishing.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/conf/Configuration_usingExecutionPublishing.java
@@ -16,12 +16,12 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.applayer.publishing.conf;
+package org.apache.isis.testdomain.publishing.conf;
 
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
 
-import org.apache.isis.testdomain.applayer.publishing.ExecutionSubscriberForTesting;
+import org.apache.isis.testdomain.publishing.subscriber.ExecutionSubscriberForTesting;
 import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
 
 @Configuration
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/CommandSubscriberForTesting.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/subscriber/CommandSubscriberForTesting.java
similarity index 97%
rename from regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/CommandSubscriberForTesting.java
rename to regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/subscriber/CommandSubscriberForTesting.java
index 8ede87d..0675385 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/CommandSubscriberForTesting.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/subscriber/CommandSubscriberForTesting.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.applayer.publishing;
+package org.apache.isis.testdomain.publishing.subscriber;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/EntityChangesSubscriberForTesting.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/subscriber/EntityChangesSubscriberForTesting.java
similarity index 98%
rename from regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/EntityChangesSubscriberForTesting.java
rename to regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/subscriber/EntityChangesSubscriberForTesting.java
index 10fa91b..5f0cbdf 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/EntityChangesSubscriberForTesting.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/subscriber/EntityChangesSubscriberForTesting.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.applayer.publishing;
+package org.apache.isis.testdomain.publishing.subscriber;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/EntityPropertyChangeSubscriberForTesting.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/subscriber/EntityPropertyChangeSubscriberForTesting.java
similarity index 97%
rename from regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/EntityPropertyChangeSubscriberForTesting.java
rename to regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/subscriber/EntityPropertyChangeSubscriberForTesting.java
index 2b8bd6a..d16f413 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/EntityPropertyChangeSubscriberForTesting.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/subscriber/EntityPropertyChangeSubscriberForTesting.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.applayer.publishing;
+package org.apache.isis.testdomain.publishing.subscriber;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/ExecutionSubscriberForTesting.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/subscriber/ExecutionSubscriberForTesting.java
similarity index 97%
rename from regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/ExecutionSubscriberForTesting.java
rename to regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/subscriber/ExecutionSubscriberForTesting.java
index 27f951b..3fdd75f 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/applayer/publishing/ExecutionSubscriberForTesting.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/publishing/subscriber/ExecutionSubscriberForTesting.java
@@ -16,7 +16,7 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.testdomain.applayer.publishing;
+package org.apache.isis.testdomain.publishing.subscriber;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/util/interaction/InteractionTestAbstract.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/util/interaction/InteractionTestAbstract.java
index 6293088..1d5f387 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/util/interaction/InteractionTestAbstract.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/util/interaction/InteractionTestAbstract.java
@@ -43,7 +43,7 @@ import org.apache.isis.core.metamodel.interactions.managed.CollectionInteraction
 import org.apache.isis.core.metamodel.interactions.managed.PropertyInteraction;
 import org.apache.isis.core.metamodel.objectmanager.ObjectManager;
 import org.apache.isis.core.transaction.changetracking.EntityChangeTracker;
-import org.apache.isis.testdomain.applayer.publishing.EntityPropertyChangeSubscriberForTesting;
+import org.apache.isis.testdomain.publishing.subscriber.EntityPropertyChangeSubscriberForTesting;
 import org.apache.isis.testdomain.util.CollectionAssertions;
 import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
 import org.apache.isis.testing.integtestsupport.applib.IsisIntegrationTestAbstract;