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 2019/08/05 07:20:53 UTC

[isis] branch v2 updated: ISIS-2158 refining TransactionService (API)

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

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


The following commit(s) were added to refs/heads/v2 by this push:
     new 3b7b166  ISIS-2158 refining TransactionService (API)
3b7b166 is described below

commit 3b7b1666c4f5f53fdd9b8c1ba96845b26225c9ee
Author: Andi Huber <ah...@apache.org>
AuthorDate: Mon Aug 5 09:20:35 2019 +0200

    ISIS-2158 refining TransactionService (API)
    
    - executeWithinTransaction(task) now reuses any existing tx boundary
    - executeWithinNewTransaction(task) forces creation of a new tx boundary
    
    JDO does not support transaction nesting, so we reuse tx boundaries by
    default. This should allow for better tx rollback support.
---
 .../applib/services/xactn/TransactionService.java  |  38 ++++++--
 .../jdo/persistence/IsisTransactionManagerJdo.java |   1 +
 .../isis/jdo/persistence/PersistenceSession5.java  |  39 ++------
 .../services/xactn/TransactionServiceSpring.java   |  34 ++++++-
 .../isis/testdomain/jdo/JdoTestDomainPersona.java  |  35 +++----
 .../testdomain/auditing/AuditerServiceTest.java    |   4 +-
 .../JdoBootstrappingTest_usingFixtures.java        |   4 +-
 .../commandexecution/BackgroundExecutionTest.java  |  16 ++-
 .../publishing/PublisherServiceTest.java           |   4 +-
 .../transactions/TransactionRollbackTest.java      | 108 +++++++++++++++++++++
 .../IsisIntegrationTestAbstactWithFixtures.java    |   2 +-
 .../fixtures/fixturescripts/FixtureScript.java     |   7 +-
 .../fixtures/fixturescripts/FixtureScripts.java    |  57 ++++++++---
 13 files changed, 265 insertions(+), 84 deletions(-)

diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java b/core/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java
index 65c9b56..0477fe8 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java
@@ -21,13 +21,16 @@ package org.apache.isis.applib.services.xactn;
 
 import java.util.function.Supplier;
 
+/**
+ * @since 2.0
+ */
 public interface TransactionService {
 
-    public enum Policy {
-        UNLESS_MARKED_FOR_ABORT,
-        ALWAYS
-    }
-
+    /**
+     * When called within an existing transactional boundary returns an unique id, 
+     * {@code null} otherwise.
+     * @return nullable
+     */
     TransactionId currentTransactionId();
 
     /**
@@ -50,7 +53,30 @@ public interface TransactionService {
      */
     TransactionState currentTransactionState();
 
+    /**
+     * Runs given {@code task} within an existing transactional boundary, or in the absence of such a 
+     * boundary creates a new one.
+     * @param task
+     */
     void executeWithinTransaction(Runnable task);
+    
+    /**
+     * Runs given {@code task} within an existing transactional boundary, or in the absence of such a 
+     * boundary creates a new one.
+     * @param task
+     */
     <T> T executeWithinTransaction(Supplier<T> task);
-
+    
+    /**
+     * Runs given {@code task} within its own (new) transactional boundary.
+     * @param task
+     */
+    void executeWithinNewTransaction(Runnable task);
+    
+    /**
+     * Runs given {@code task} within its own (new) transactional boundary.
+     * @param task
+     */
+    <T> T executeWithinNewTransaction(Supplier<T> task);
+    
 }
diff --git a/core/plugins/jdo-common/src/main/java/org/apache/isis/jdo/persistence/IsisTransactionManagerJdo.java b/core/plugins/jdo-common/src/main/java/org/apache/isis/jdo/persistence/IsisTransactionManagerJdo.java
index 83e6a29..78668b4 100644
--- a/core/plugins/jdo-common/src/main/java/org/apache/isis/jdo/persistence/IsisTransactionManagerJdo.java
+++ b/core/plugins/jdo-common/src/main/java/org/apache/isis/jdo/persistence/IsisTransactionManagerJdo.java
@@ -308,6 +308,7 @@ class IsisTransactionManagerJdo implements SessionScopedComponent {
     public void abortTransaction(IsisTransactionObject txObject) {
         val transaction = (IsisTransactionJdo) txObject.getCurrentTransaction();
         if (transaction != null) {
+            System.out.println("!!!!!!!!!!! " + transaction.getState());
             transaction.markAsAborted();
             persistenceSession.abortTransaction();
             txObject.clear();
diff --git a/core/plugins/jdo-datanucleus-5/src/main/java/org/apache/isis/jdo/persistence/PersistenceSession5.java b/core/plugins/jdo-datanucleus-5/src/main/java/org/apache/isis/jdo/persistence/PersistenceSession5.java
index 027e5a5..7ef2189 100644
--- a/core/plugins/jdo-datanucleus-5/src/main/java/org/apache/isis/jdo/persistence/PersistenceSession5.java
+++ b/core/plugins/jdo-datanucleus-5/src/main/java/org/apache/isis/jdo/persistence/PersistenceSession5.java
@@ -584,42 +584,21 @@ implements IsisLifecycleListener.PersistenceSessionLifecycleManagement {
         if (adapter.isRepresentingPersistent()) {
             throw new NotPersistableException("Object already persistent: " + adapter);
         }
-        final ObjectSpecification specification = adapter.getSpecification();
-        if (specification.isManagedBean()) {
+        if (adapter.isParentedCollection()) {
+            //or should we just ignore this?
+            throw new NotPersistableException("Cannot persist parented collection: " + adapter);
+        }
+        val spec = adapter.getSpecification();
+        if (spec.isManagedBean()) {
             throw new NotPersistableException("Can only persist entity beans: " + adapter);
         }
-
         transactionService.executeWithinTransaction(()->{
-            makePersistentTransactionAssumed(adapter);
+            log.debug("persist {}", adapter);               
+            val createObjectCommand = newCreateObjectCommand(adapter);
+            transactionManager.addCommand(createObjectCommand);
         });
     }
 
-    private void makePersistentTransactionAssumed(final ObjectAdapter adapter) {
-        if (alreadyPersistedOrNotPersistable(adapter)) {
-            return;
-        }
-        log.debug("persist {}", adapter);				
-        addCreateObjectCommand(adapter);
-    }
-
-    /**
-     * {@link #newCreateObjectCommand(ObjectAdapter) Create}s a {@link CreateObjectCommand}, 
-     * and adds to the {@link IsisTransactionManagerJdo}.
-     */
-    private void addCreateObjectCommand(final ObjectAdapter object) {
-        val createObjectCommand = newCreateObjectCommand(object);
-        transactionManager.addCommand(createObjectCommand);
-    }
-
-
-    private static boolean alreadyPersistedOrNotPersistable(final ObjectAdapter adapter) {
-        return adapter.isRepresentingPersistent() || objectSpecNotPersistable(adapter);
-    }
-
-
-    private static boolean objectSpecNotPersistable(final ObjectAdapter adapter) {
-        return adapter.isParentedCollection();
-    }
 
     // -- destroyObjectInTransaction
 
diff --git a/core/runtime-services/src/main/java/org/apache/isis/runtime/services/xactn/TransactionServiceSpring.java b/core/runtime-services/src/main/java/org/apache/isis/runtime/services/xactn/TransactionServiceSpring.java
index 2b6c73e..15bd24f 100644
--- a/core/runtime-services/src/main/java/org/apache/isis/runtime/services/xactn/TransactionServiceSpring.java
+++ b/core/runtime-services/src/main/java/org/apache/isis/runtime/services/xactn/TransactionServiceSpring.java
@@ -95,7 +95,8 @@ public class TransactionServiceSpring implements TransactionService {
     }
 
     @Override
-    public void executeWithinTransaction(Runnable task) {
+    public void executeWithinNewTransaction(Runnable task) {
+        
         transactionTemplate.execute(new TransactionCallbackWithoutResult() {
             // the code in this method executes in a transactional context
             @Override
@@ -106,7 +107,8 @@ public class TransactionServiceSpring implements TransactionService {
     }
 
     @Override
-    public <T> T executeWithinTransaction(Supplier<T> task) {
+    public <T> T executeWithinNewTransaction(Supplier<T> task) {
+        
         return transactionTemplate.execute(new TransactionCallback<T>() {
             // the code in this method executes in a transactional context
             @Override
@@ -115,6 +117,34 @@ public class TransactionServiceSpring implements TransactionService {
             }
         });
     }
+    
+    @Override
+    public void executeWithinTransaction(Runnable task) {
+        
+        val txState = currentTransactionState();
+        if(txState != TransactionState.NONE) {
+            task.run();
+            flushTransaction();
+            return;
+        }
+        
+        executeWithinNewTransaction(task);
+        
+    }
+
+    @Override
+    public <T> T executeWithinTransaction(Supplier<T> task) {
+        
+        val txState = currentTransactionState();
+        if(txState != TransactionState.NONE) {
+            val result = task.get();
+            flushTransaction();
+            return result;
+        }
+        
+        return executeWithinNewTransaction(task);
+        
+    }
 
     // -- HELPER
 
diff --git a/examples/smoketests/src/main/java/org/apache/isis/testdomain/jdo/JdoTestDomainPersona.java b/examples/smoketests/src/main/java/org/apache/isis/testdomain/jdo/JdoTestDomainPersona.java
index 3dfd1f5..ff76643 100644
--- a/examples/smoketests/src/main/java/org/apache/isis/testdomain/jdo/JdoTestDomainPersona.java
+++ b/examples/smoketests/src/main/java/org/apache/isis/testdomain/jdo/JdoTestDomainPersona.java
@@ -19,12 +19,14 @@
 package org.apache.isis.testdomain.jdo;
 
 import java.util.HashSet;
-import java.util.Set;
+
+import javax.inject.Inject;
 
 import org.apache.isis.applib.services.repository.RepositoryService;
 import org.apache.isis.extensions.fixtures.api.PersonaWithBuilderScript;
 import org.apache.isis.extensions.fixtures.fixturescripts.BuilderScriptAbstract;
-import org.apache.isis.runtime.system.context.IsisContext;
+
+import lombok.val;
 
 public enum JdoTestDomainPersona 
 implements PersonaWithBuilderScript<BuilderScriptAbstract<Inventory>>  {
@@ -37,10 +39,6 @@ implements PersonaWithBuilderScript<BuilderScriptAbstract<Inventory>>  {
                 @Override
                 protected void execute(ExecutionContext ec) {
 
-                    //XXX lombok issue, cannot use val here (https://github.com/rzwitserloot/lombok/issues/434)
-                    RepositoryService repository = IsisContext.getServiceRegistry()
-                            .lookupServiceElseFail(RepositoryService.class);
-
                     repository.allInstances(Inventory.class)
                     .forEach(repository::remove);
 
@@ -56,6 +54,8 @@ implements PersonaWithBuilderScript<BuilderScriptAbstract<Inventory>>  {
                 public Inventory getObject() {
                     return null;
                 }
+                
+                @Inject private RepositoryService repository;
 
             };
         }    
@@ -71,17 +71,7 @@ implements PersonaWithBuilderScript<BuilderScriptAbstract<Inventory>>  {
                 @Override
                 protected void execute(ExecutionContext ec) {
 
-                    //don't use lombok's val here (https://github.com/rzwitserloot/lombok/issues/434)
-                    RepositoryService repository = IsisContext.getServiceRegistry()
-                            .lookupServiceElseFail(RepositoryService.class);
-
-                    Set<Product> products = new HashSet<>();
-
-                    products.add(Book.of(
-                            "Sample Book", "A sample book for testing.", 99.,
-                            "Sample Author", "Sample ISBN", "Sample Publisher"));
-
-                    inventory = Inventory.of("Sample Inventory", products);
+                    inventory = sampleInventoryWith1Book();
                     repository.persist(inventory);
 
                 }
@@ -90,6 +80,8 @@ implements PersonaWithBuilderScript<BuilderScriptAbstract<Inventory>>  {
                 public Inventory getObject() {
                     return inventory;
                 }
+                
+                @Inject private RepositoryService repository;
 
             };
         }    
@@ -97,6 +89,15 @@ implements PersonaWithBuilderScript<BuilderScriptAbstract<Inventory>>  {
 
     ;
 
+    private static Inventory sampleInventoryWith1Book() {
+        val products = new HashSet<Product>();
+
+        products.add(Book.of(
+                "Sample Book", "A sample book for testing.", 99.,
+                "Sample Author", "Sample ISBN", "Sample Publisher"));
+
+        return Inventory.of("Sample Inventory", products);
+    }
 
 
 }
diff --git a/examples/smoketests/src/test/java/org/apache/isis/testdomain/auditing/AuditerServiceTest.java b/examples/smoketests/src/test/java/org/apache/isis/testdomain/auditing/AuditerServiceTest.java
index f02803d..dfdec4e 100644
--- a/examples/smoketests/src/test/java/org/apache/isis/testdomain/auditing/AuditerServiceTest.java
+++ b/examples/smoketests/src/test/java/org/apache/isis/testdomain/auditing/AuditerServiceTest.java
@@ -73,10 +73,10 @@ class AuditerServiceTest {
         transactionTemplate.execute(status -> {
 
             // cleanup
-            fixtureScripts.runBuilderScript(JdoTestDomainPersona.PurgeAll.builder());
+            fixtureScripts.runPersona(JdoTestDomainPersona.PurgeAll);
 
             // given
-            fixtureScripts.runBuilderScript(JdoTestDomainPersona.InventoryWith1Book.builder());
+            fixtureScripts.runPersona(JdoTestDomainPersona.InventoryWith1Book);
 
             return null;
 
diff --git a/examples/smoketests/src/test/java/org/apache/isis/testdomain/bootstrapping/JdoBootstrappingTest_usingFixtures.java b/examples/smoketests/src/test/java/org/apache/isis/testdomain/bootstrapping/JdoBootstrappingTest_usingFixtures.java
index 0904a58..393ab1a 100644
--- a/examples/smoketests/src/test/java/org/apache/isis/testdomain/bootstrapping/JdoBootstrappingTest_usingFixtures.java
+++ b/examples/smoketests/src/test/java/org/apache/isis/testdomain/bootstrapping/JdoBootstrappingTest_usingFixtures.java
@@ -55,10 +55,10 @@ class JdoBootstrappingTest_usingFixtures {
     void setUp() {
 
         // cleanup
-        fixtureScripts.runBuilderScript(JdoTestDomainPersona.PurgeAll.builder());
+        fixtureScripts.runPersona(JdoTestDomainPersona.PurgeAll);
 
         // given
-        fixtureScripts.runBuilderScript(JdoTestDomainPersona.InventoryWith1Book.builder());
+        fixtureScripts.runPersona(JdoTestDomainPersona.InventoryWith1Book);
     }
 
     @Test @Rollback(false)
diff --git a/examples/smoketests/src/test/java/org/apache/isis/testdomain/commandexecution/BackgroundExecutionTest.java b/examples/smoketests/src/test/java/org/apache/isis/testdomain/commandexecution/BackgroundExecutionTest.java
index b537e5c..3299d45 100644
--- a/examples/smoketests/src/test/java/org/apache/isis/testdomain/commandexecution/BackgroundExecutionTest.java
+++ b/examples/smoketests/src/test/java/org/apache/isis/testdomain/commandexecution/BackgroundExecutionTest.java
@@ -58,16 +58,19 @@ import lombok.val;
         })
 class BackgroundExecutionTest {
 
-    @Inject private FixtureScripts fixtureScripts;
-    @Inject private RepositoryService repository;
+    @Inject FixtureScripts fixtureScripts;
+    @Inject RepositoryService repository;
+    @Inject BackgroundService backgroundService;
+    @Inject FactoryService facoryService;
+    @Inject ActionDomainEventListener actionDomainEventListener;
 
     @BeforeEach
     void setUp() {
         // cleanup
-        fixtureScripts.runBuilderScript(JdoTestDomainPersona.PurgeAll.builder());
+        fixtureScripts.runPersona(JdoTestDomainPersona.PurgeAll);
 
         // given
-        fixtureScripts.runBuilderScript(JdoTestDomainPersona.InventoryWith1Book.builder());
+        fixtureScripts.runPersona(JdoTestDomainPersona.InventoryWith1Book);
     }
 
     @Test
@@ -122,10 +125,5 @@ class BackgroundExecutionTest {
 
     }
 
-    // -- DEPS
-
-    @Inject BackgroundService backgroundService;
-    @Inject FactoryService facoryService;
-    @Inject ActionDomainEventListener actionDomainEventListener;
 
 }
diff --git a/examples/smoketests/src/test/java/org/apache/isis/testdomain/publishing/PublisherServiceTest.java b/examples/smoketests/src/test/java/org/apache/isis/testdomain/publishing/PublisherServiceTest.java
index 3b3e504..e35acb2 100644
--- a/examples/smoketests/src/test/java/org/apache/isis/testdomain/publishing/PublisherServiceTest.java
+++ b/examples/smoketests/src/test/java/org/apache/isis/testdomain/publishing/PublisherServiceTest.java
@@ -72,10 +72,10 @@ class PublisherServiceTest {
         transactionTemplate.execute(status -> {
 
             // cleanup
-            fixtureScripts.runBuilderScript(JdoTestDomainPersona.PurgeAll.builder());
+            fixtureScripts.runPersona(JdoTestDomainPersona.PurgeAll);
 
             // given
-            fixtureScripts.runBuilderScript(JdoTestDomainPersona.InventoryWith1Book.builder());
+            fixtureScripts.runPersona(JdoTestDomainPersona.InventoryWith1Book);
 
             return null;
 
diff --git a/examples/smoketests/src/test/java/org/apache/isis/testdomain/transactions/TransactionRollbackTest.java b/examples/smoketests/src/test/java/org/apache/isis/testdomain/transactions/TransactionRollbackTest.java
new file mode 100644
index 0000000..b32f9e6
--- /dev/null
+++ b/examples/smoketests/src/test/java/org/apache/isis/testdomain/transactions/TransactionRollbackTest.java
@@ -0,0 +1,108 @@
+/*
+ *  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.transactions;
+
+import javax.inject.Inject;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import org.apache.isis.applib.services.repository.RepositoryService;
+import org.apache.isis.applib.services.xactn.TransactionService;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.extensions.fixtures.fixturescripts.FixtureScripts;
+import org.apache.isis.testdomain.jdo.Book;
+import org.apache.isis.testdomain.jdo.JdoTestDomainModule;
+import org.apache.isis.testdomain.jdo.JdoTestDomainPersona;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+@SpringBootTest(
+        classes = { 
+                JdoTestDomainModule.class,
+        }, 
+        properties = {
+                "logging.config=log4j2-test.xml",
+                "logging.level.org.apache.isis.jdo.persistence.IsisPlatformTransactionManagerForJdo=DEBUG",
+                "logging.level.org.apache.isis.jdo.persistence.PersistenceSession5=DEBUG",
+                "logging.level.org.apache.isis.jdo.persistence.IsisTransactionJdo=DEBUG",
+        })
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+class TransactionRollbackTest {
+    
+    @Inject FixtureScripts fixtureScripts;
+    @Inject private TransactionService transactionService;
+    @Inject private RepositoryService repository;
+    
+    @BeforeEach
+    void setUp() {
+        // cleanup
+        fixtureScripts.runPersona(JdoTestDomainPersona.PurgeAll);
+
+    }
+    
+    @Test
+    void happyCaseTx_shouldCommit() {
+        
+        // expected pre condition
+        assertEquals(0, repository.allInstances(Book.class).size());
+        
+        transactionService.executeWithinTransaction(()->{
+            
+            fixtureScripts.runPersona(JdoTestDomainPersona.InventoryWith1Book);
+            
+        });
+        
+        // expected post condition
+        assertEquals(1, repository.allInstances(Book.class).size());
+        
+    }
+    
+    @Test
+    void whenExceptionWithinTx_shouldRollback() {
+        
+        // expected pre condition
+        assertEquals(0, repository.allInstances(Book.class).size());
+        
+        System.out.println("!!! ROLLBACK TEST TX IN");
+        
+        transactionService.executeWithinTransaction(()->{
+        
+            System.out.println("!!! PRE FIXTURE");
+            
+            fixtureScripts.runPersona(JdoTestDomainPersona.InventoryWith1Book);
+            
+            System.out.println("!!! POST FIXTURE");
+            
+            throw _Exceptions.unrecoverable("Test: force current tx to rollback");            
+            
+        });
+        
+        System.out.println("!!! ROLLBACK TEST TX OUT");
+        
+        // expected post condition
+        assertEquals(0, repository.allInstances(Book.class).size());
+        
+    }
+    
+
+}
diff --git a/extensions/fixtures/src/main/java/org/apache/isis/extensions/fixtures/IsisIntegrationTestAbstactWithFixtures.java b/extensions/fixtures/src/main/java/org/apache/isis/extensions/fixtures/IsisIntegrationTestAbstactWithFixtures.java
index 339a979..d708059 100644
--- a/extensions/fixtures/src/main/java/org/apache/isis/extensions/fixtures/IsisIntegrationTestAbstactWithFixtures.java
+++ b/extensions/fixtures/src/main/java/org/apache/isis/extensions/fixtures/IsisIntegrationTestAbstactWithFixtures.java
@@ -35,7 +35,7 @@ import org.apache.isis.integtestsupport.IsisIntegrationTestAbstact;
 public abstract class IsisIntegrationTestAbstactWithFixtures extends IsisIntegrationTestAbstact {
 
     protected void runFixtureScript(final FixtureScript... fixtureScriptList) {
-        this.fixtureScripts.runFixtureScript(fixtureScriptList);
+        this.fixtureScripts.run(fixtureScriptList);
     }
 
     protected <T> T runBuilderScript(final BuilderScriptAbstract<T> fixtureScript) {
diff --git a/extensions/fixtures/src/main/java/org/apache/isis/extensions/fixtures/fixturescripts/FixtureScript.java b/extensions/fixtures/src/main/java/org/apache/isis/extensions/fixtures/fixturescripts/FixtureScript.java
index f0c8382..b6d024f 100644
--- a/extensions/fixtures/src/main/java/org/apache/isis/extensions/fixtures/fixturescripts/FixtureScript.java
+++ b/extensions/fixtures/src/main/java/org/apache/isis/extensions/fixtures/fixturescripts/FixtureScript.java
@@ -883,7 +883,8 @@ extends AbstractViewModel {
     private ExecutionContext executionContext;
 
     /**
-     * Entry point for {@link org.apache.isis.extensions.fixtures.fixturescripts.FixtureScripts} service to call.
+     * Entry point for {@link org.apache.isis.extensions.fixtures.fixturescripts.FixtureScripts} 
+     * service to call.
      *
      * <p>
      *     Package-visibility only, not public API.
@@ -914,7 +915,9 @@ extends AbstractViewModel {
      * Subclasses should <b>implement this</b> but SHOULD <i>NOT</i> CALL DIRECTLY.
      *
      * <p>
-     *  Instead call sub fixture scripts using {@link org.apache.isis.extensions.fixtures.fixturescripts.FixtureScript.ExecutionContext#executeChild(org.apache.isis.extensions.fixtures.fixturescripts.FixtureScript, org.apache.isis.extensions.fixtures.fixturescripts.FixtureScript)} or {@link org.apache.isis.extensions.fixtures.fixturescripts.FixtureScript.ExecutionContext#executeChild(org.apache.isis.extensions.fixtures.fixturescripts.FixtureScript, String, org.apache.isis.extensions.fixt [...]
+     *  Instead call sub fixture scripts using 
+     *  {@link FixtureScript.ExecutionContext#executeChild(FixtureScript, FixtureScript)} 
+     *  or {@link FixtureScript.ExecutionContext#executeChild(FixtureScript, String, FixtureScript)}.
      * </p>
      */
     @Programmatic
diff --git a/extensions/fixtures/src/main/java/org/apache/isis/extensions/fixtures/fixturescripts/FixtureScripts.java b/extensions/fixtures/src/main/java/org/apache/isis/extensions/fixtures/fixturescripts/FixtureScripts.java
index 49db1ca..5eb394b 100644
--- a/extensions/fixtures/src/main/java/org/apache/isis/extensions/fixtures/fixturescripts/FixtureScripts.java
+++ b/extensions/fixtures/src/main/java/org/apache/isis/extensions/fixtures/fixturescripts/FixtureScripts.java
@@ -350,7 +350,7 @@ public abstract class FixtureScripts extends AbstractService {
     // -- programmatic API
 
     @Programmatic
-    public void runFixtureScript(final FixtureScript... fixtureScriptList) {
+    public void run(final FixtureScript... fixtureScriptList) {
 
         val singleScript = toSingleScript(fixtureScriptList);
         val parameters = (String)null;
@@ -362,24 +362,40 @@ public abstract class FixtureScripts extends AbstractService {
     }
 
     @Programmatic
-    public <T> T fixtureScript(final PersonaWithBuilderScript<BuilderScriptAbstract<T>> persona) {
-        final BuilderScriptAbstract<T> fixtureScript = persona.builder();
-        return runBuilderScript(fixtureScript);
+    public <T> T runPersona(final PersonaWithBuilderScript<BuilderScriptAbstract<T>> persona) {
+        val builderScript = persona.builder();
+        return runBuilderScript(builderScript);
     }
 
+    /**
+     * Runs the builderScript within its own transactional boundary.
+     * @param <T>
+     * @param builderScript
+     * @return
+     */
     @Programmatic
     public <T> T runBuilderScript(final BuilderScriptAbstract<T> builderScript) {
 
-        serviceInjector.injectServicesInto(builderScript);
-
         return transactionService.executeWithinTransaction(()->{
-
-            builderScript.run(null);
-            final T object = builderScript.getObject();
-            return object;
-
+            return runBuilderScriptNonTransactional(builderScript);
         });
+    }
+    
+    /**
+     * Runs the builderScript without its own transactional boundary.<br>
+     * The caller is responsible to provide a transactional context/boundary.
+     * @param <T>
+     * @param builderScript
+     * @return
+     */
+    @Programmatic
+    public <T> T runBuilderScriptNonTransactional(final BuilderScriptAbstract<T> builderScript) {
 
+        serviceInjector.injectServicesInto(builderScript);
+
+        builderScript.run(null);
+        final T object = builderScript.getObject();
+        return object;
     }
 
     @Programmatic
@@ -502,5 +518,24 @@ public abstract class FixtureScripts extends AbstractService {
     @Inject RepositoryService repositoryService;
     @Inject TransactionService transactionService;
     @Inject ExecutionParametersService executionParametersService;
+    
+    // -- DEPRECATIONS
+ 
+    /**
+     * @deprecated renamed to {@link #runPersona(PersonaWithBuilderScript)}
+     */
+    @Programmatic @Deprecated
+    public <T> T fixtureScript(final PersonaWithBuilderScript<BuilderScriptAbstract<T>> persona) {
+        return runPersona(persona);
+    }
+    
+    /**
+     * @deprecated renamed to {@link #run(FixtureScript...)}
+     */
+    @Programmatic
+    public void runFixtureScript(final FixtureScript... fixtureScriptList) {
+        run(fixtureScriptList);
+    }
+    
 
 }
\ No newline at end of file