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

[isis] branch master updated: ISIS-2033: slight improvements for the TransactionService (Applib)

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 4bd31c4  ISIS-2033: slight improvements for the TransactionService (Applib)
4bd31c4 is described below

commit 4bd31c4ac25b63275d2cbeacb7fcb1a2e6ca139d
Author: Andi Huber <ah...@apache.org>
AuthorDate: Mon Dec 21 18:12:57 2020 +0100

    ISIS-2033: slight improvements for the TransactionService (Applib)
---
 .../isis/applib/services/command/Command.java      | 13 ++--
 .../services/command/CommandOutcomeHandler.java    |  8 +--
 .../applib/services/xactn/TransactionService.java  | 30 ++++++---
 .../org/apache/isis/commons/functional/Result.java |  2 +-
 ...ctionInvocationFacetForDomainEventAbstract.java |  5 +-
 ...tySetterOrClearFacetForDomainEventAbstract.java | 11 +++-
 .../command/CommandExecutorServiceDefault.java     | 33 +++++-----
 .../executor/MemberExecutorServiceDefault.java     |  3 +-
 .../wrapper/WrapperFactoryDefault.java             |  6 +-
 .../xactn/TransactionServiceSpring.java            | 73 ++++++----------------
 .../extensions/commandlog/impl/jdo/CommandJdo.java | 12 ++--
 .../jobcallables/IsTickingClockInitialized.java    |  3 +-
 .../jobcallables/ReplicateAndRunCommands.java      |  6 +-
 .../persistence/PersistenceSession5.java           |  6 +-
 .../applib/fixturescripts/FixtureScripts.java      |  3 +-
 .../wicket/ui/panels/FormExecutorDefault.java      |  3 +-
 16 files changed, 99 insertions(+), 118 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/command/Command.java b/api/applib/src/main/java/org/apache/isis/applib/services/command/Command.java
index 03a1b06..99afe4a 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/command/Command.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/command/Command.java
@@ -28,6 +28,7 @@ import org.apache.isis.applib.services.commanddto.HasCommandDto;
 import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.applib.services.wrapper.WrapperFactory;
 import org.apache.isis.applib.services.wrapper.control.AsyncControl;
+import org.apache.isis.commons.functional.Result;
 import org.apache.isis.commons.having.HasUniqueId;
 import org.apache.isis.commons.having.HasUsername;
 import org.apache.isis.schema.cmd.v2.CommandDto;
@@ -310,19 +311,13 @@ public class Command implements HasUniqueId, HasUsername, HasCommandDto {
          * <b>NOT API</b>: intended to be called only by the framework.
          */
         @Override
-        public void setResult(final Bookmark result) {
-            Command.this.result = result;
+        public void setResult(final Result<Bookmark> resultBookmark) {
+            Command.this.result = resultBookmark.value().orElse(null);
+            Command.this.exception = resultBookmark.failure().orElse(null);
         }
 
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
-         */
-        @Override
-        public void setException(final Throwable exception) {
-            Command.this.exception = exception;
-        }
-        /**
-         * <b>NOT API</b>: intended to be called only by the framework.
          *
          * <p>
          * Hint that this {@link Command} has resulted in a change of state to the system.
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandOutcomeHandler.java b/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandOutcomeHandler.java
index 35a0c14..46598fc 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandOutcomeHandler.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/command/CommandOutcomeHandler.java
@@ -21,6 +21,7 @@ package org.apache.isis.applib.services.command;
 import java.sql.Timestamp;
 
 import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.commons.functional.Result;
 
 /**
  * 
@@ -32,8 +33,7 @@ public interface CommandOutcomeHandler {
         @Override public Timestamp getStartedAt() { return null; }
         @Override public void setStartedAt(Timestamp startedAt) { }
         @Override public void setCompletedAt(Timestamp completedAt) { }
-        @Override public void setResult(Bookmark resultBookmark) { }
-        @Override public void setException(Throwable throwable) { }
+        @Override public void setResult(Result<Bookmark> resultBookmark) { }
     };
 
     Timestamp getStartedAt();
@@ -41,6 +41,6 @@ public interface CommandOutcomeHandler {
 
     void setCompletedAt(Timestamp completedAt);
 
-    void setResult(Bookmark resultBookmark);
-    void setException(Throwable throwable);
+    void setResult(Result<Bookmark> resultBookmark);
+    
 }
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java b/api/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java
index 5bde8e6..bc232bb 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java
@@ -19,10 +19,17 @@
 
 package org.apache.isis.applib.services.xactn;
 
-import java.util.function.Supplier;
+import java.util.Optional;
+import java.util.concurrent.Callable;
+
+import org.apache.isis.commons.functional.Result;
+import org.apache.isis.commons.functional.ThrowingRunnable;
+
+import lombok.val;
 
 /**
- * 
+ * Handles <i>global</i> transactions. 
+ * Global transactions enable you to work with multiple transactional resources, typically relational databases.
  * @since 2.0 {@index}
  */
 public interface TransactionService {
@@ -50,7 +57,6 @@ public interface TransactionService {
      */
     void flushTransaction();
 
-
     /**
      * Commits the current transaction (if there is one), and begins a new one.
      *
@@ -59,20 +65,24 @@ public interface TransactionService {
     void nextTransaction();
 
     /**
-     * Runs given {@code task} within an existing transactional boundary, or in the absence of such a
+     * Runs given {@code callable} within an existing transactional boundary, or in the absence of such a
      * boundary creates a new one.
      *
-     * @param task
+     * @param callable
      */
-    void executeWithinTransaction(Runnable task);
-
+    <T> Result<T> executeWithinTransaction(Callable<T> callable);
+    
     /**
-     * Runs given {@code task} within an existing transactional boundary, or in the absence of such a
+     * Runs given {@code runnable} within an existing transactional boundary, or in the absence of such a
      * boundary creates a new one.
      *
-     * @param task
+     * @param runnable
      */
-    <T> T executeWithinTransaction(Supplier<T> task);
+    default Optional<Throwable> executeWithinTransaction(ThrowingRunnable runnable) {
+        val callable = ThrowingRunnable.toCallable(runnable);
+        return executeWithinTransaction(callable)
+                .failure();
+    }
 
 
 }
diff --git a/commons/src/main/java/org/apache/isis/commons/functional/Result.java b/commons/src/main/java/org/apache/isis/commons/functional/Result.java
index d855dcd..160a6b3 100644
--- a/commons/src/main/java/org/apache/isis/commons/functional/Result.java
+++ b/commons/src/main/java/org/apache/isis/commons/functional/Result.java
@@ -107,7 +107,7 @@ public final class Result<L> {
         return Optional.ofNullable(value); 
     }
 
-    public Optional<Throwable> exception() {
+    public Optional<Throwable> failure() {
         return Optional.ofNullable(throwable); 
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java
index 12571e4..2158073 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java
@@ -107,13 +107,14 @@ implements ImperativeFacet {
             final Can<ManagedObject> argumentAdapters,
             final InteractionInitiatedBy interactionInitiatedBy) {
 
-        final ManagedObject executionResult = 
+        val executionResult = 
                 getTransactionService().executeWithinTransaction(()->
                     doInvoke(owningAction, head, argumentAdapters, interactionInitiatedBy));
 
         //PersistableTypeGuard.instate(executionResult);
 
-        return executionResult;
+        return executionResult
+                .orElseFail();
     }
 
     @Override 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterOrClearFacetForDomainEventAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterOrClearFacetForDomainEventAbstract.java
index 203fc06..7cdac25 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterOrClearFacetForDomainEventAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterOrClearFacetForDomainEventAbstract.java
@@ -148,8 +148,15 @@ extends SingleValueFacetAbstract<Class<? extends PropertyDomainEvent<?,?>>> {
             final ManagedObject newValueAdapter,
             final InteractionInitiatedBy interactionInitiatedBy) {
 
-        return getTransactionService().executeWithinTransaction(() ->
-                doSetOrClearProperty(style, owningProperty, InteractionHead.simple(targetAdapter), newValueAdapter, interactionInitiatedBy));
+        return getTransactionService()
+                .executeWithinTransaction(() ->
+                    doSetOrClearProperty(
+                            style, 
+                            owningProperty, 
+                            InteractionHead.simple(targetAdapter), 
+                            newValueAdapter, 
+                            interactionInitiatedBy))
+                .orElseFail();
         }
 
     @RequiredArgsConstructor
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java
index 884a357..e440ac1 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java
@@ -49,6 +49,7 @@ import org.apache.isis.applib.services.xactn.TransactionService;
 import org.apache.isis.applib.util.schema.CommandDtoUtils;
 import org.apache.isis.applib.util.schema.CommonDtoUtils;
 import org.apache.isis.commons.collections.Can;
+import org.apache.isis.commons.functional.Result;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
@@ -147,23 +148,19 @@ public class CommandExecutorServiceDefault implements CommandExecutorService {
 
         copyStartedAtFromInteractionExecution(commandUpdater);
 
-        try {
-            val result = transactionService.executeWithinTransaction(
-                () -> sudoPolicy == SudoPolicy.SWITCH
-                    ? sudoService.call(
-                            context->context.withUser(UserMemento.ofName(dto.getUser())),
-                            () -> doExecuteCommand(dto))
-                    : doExecuteCommand(dto));
-
-            return handleOutcomeAndSetCompletedAt(commandUpdater, result, null);
-
-        } catch (Exception ex) {
+        val result = transactionService.executeWithinTransaction(
+            () -> sudoPolicy == SudoPolicy.SWITCH
+                ? sudoService.call(
+                        context->context.withUser(UserMemento.ofName(dto.getUser())),
+                        () -> doExecuteCommand(dto))
+                : doExecuteCommand(dto));
 
+        result.ifFailure(ex->{
             log.warn("Exception when executing : {}",
                     dto.getMember().getLogicalMemberIdentifier(), ex);
-
-            return handleOutcomeAndSetCompletedAt(commandUpdater, null, ex);
-        }
+        });
+        
+        return handleOutcomeAndSetCompletedAt(commandUpdater, result);
     }
 
     private void copyStartedAtFromInteractionExecution(
@@ -256,13 +253,13 @@ public class CommandExecutorServiceDefault implements CommandExecutorService {
 
     private Bookmark handleOutcomeAndSetCompletedAt(
             final CommandOutcomeHandler outcomeHandler,
-            Bookmark resultIfAny, final Exception exceptionIfAny) {
+            final Result<Bookmark> result) {
 
+        
         //
         // copy over the outcome
         //
-        outcomeHandler.setResult(resultIfAny);
-        outcomeHandler.setException(exceptionIfAny);
+        outcomeHandler.setResult(result);
 
         //
         // also, copy over the completedAt at to the command.
@@ -286,7 +283,7 @@ public class CommandExecutorServiceDefault implements CommandExecutorService {
             outcomeHandler.setCompletedAt(completedAt);
         }
 
-        return resultIfAny;
+        return result.value().orElse(null);
     }
 
     // //////////////////////////////////////
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/executor/MemberExecutorServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/executor/MemberExecutorServiceDefault.java
index b6ce255..1291d81 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/executor/MemberExecutorServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/executor/MemberExecutorServiceDefault.java
@@ -20,6 +20,7 @@ import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.applib.services.metrics.MetricsService;
 import org.apache.isis.applib.services.xactn.TransactionService;
 import org.apache.isis.commons.collections.Can;
+import org.apache.isis.commons.functional.Result;
 import org.apache.isis.commons.internal.assertions._Assert;
 import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.commons.internal.collections._Lists;
@@ -240,7 +241,7 @@ implements MemberExecutorService {
         if(entityState.isAttached()) {
             resultAdapter.getRootOid().ifPresent(rootOid->{
                 val bookmark = rootOid.asBookmark();
-                command.updater().setResult(bookmark);
+                command.updater().setResult(Result.success(bookmark));
             });
         } else {
             if(entityState.isPersistable()) {
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefault.java
index 3e2aeca..31fb607 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefault.java
@@ -577,7 +577,8 @@ public class WrapperFactoryDefault implements WrapperFactory {
             return isisInteractionFactory.callAuthenticated(authentication, () -> {
                 val childCommand = interactionContextProvider.get().currentInteractionElseFail().getCommand();
                 childCommand.updater().setParent(parentCommand);
-                return transactionService.executeWithinTransaction(() -> {
+                return transactionService
+                        .executeWithinTransaction(() -> {
                         val bookmark = commandExecutorService.executeCommand(commandDto, CommandOutcomeHandler.NULL);
                         if (bookmark == null) {
                             return null;
@@ -587,7 +588,8 @@ public class WrapperFactoryDefault implements WrapperFactory {
                             entity = repositoryService.detach(entity);
                         }
                         return entity;
-                    });
+                    })
+                        .orElseFail();
             });
         }
     }
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/xactn/TransactionServiceSpring.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/xactn/TransactionServiceSpring.java
index 3a0cd61..1fd290a 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/xactn/TransactionServiceSpring.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/xactn/TransactionServiceSpring.java
@@ -20,7 +20,6 @@
 package org.apache.isis.core.runtimeservices.xactn;
 
 import java.util.concurrent.Callable;
-import java.util.function.Supplier;
 
 import javax.annotation.Nonnull;
 import javax.inject.Inject;
@@ -33,17 +32,18 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.PlatformTransactionManager;
 import org.springframework.transaction.TransactionStatus;
 import org.springframework.transaction.support.TransactionCallback;
-import org.springframework.transaction.support.TransactionCallbackWithoutResult;
 import org.springframework.transaction.support.TransactionTemplate;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
 import org.apache.isis.applib.services.xactn.TransactionId;
 import org.apache.isis.applib.services.xactn.TransactionService;
 import org.apache.isis.applib.services.xactn.TransactionState;
+import org.apache.isis.commons.functional.Result;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.runtime.persistence.transaction.IsisTransactionAspectSupport;
 import org.apache.isis.core.runtime.persistence.transaction.IsisTransactionObject;
 
+import lombok.NonNull;
 import lombok.SneakyThrows;
 import lombok.val;
 import lombok.extern.log4j.Log4j2;
@@ -123,63 +123,14 @@ public class TransactionServiceSpring implements TransactionService {
         platformTransactionManager.getTransaction(transactionTemplate);
     }
 
-    private void executeWithinNewTransaction(Runnable task) {
-        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
-            // the code in this method executes in a transactional context
-            @Override
-            protected void doInTransactionWithoutResult(TransactionStatus status) {
-                task.run();
-            }
-        });
-    }
-
-    private <T> T executeWithinNewTransaction(Callable<T> callable) {
-
-        return transactionTemplate.execute(new TransactionCallback<T>() {
-            // the code in this method executes in a transactional context
-            @SneakyThrows
-            @Override
-            public T doInTransaction(TransactionStatus status) {
-                return callable.call();
-            }
-        });
-    }
-
-    private <T> T executeWithinNewTransaction(Supplier<T> task) {
-
-        return transactionTemplate.execute(new TransactionCallback<T>() {
-            // the code in this method executes in a transactional context
-            @Override
-            public T doInTransaction(TransactionStatus status) {
-                return task.get();
-            }
-        });
-    }
-
-    @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) {
+    public <T> Result<T> executeWithinTransaction(final @NonNull Callable<T> callable) {
 
-        val txState = currentTransactionState();
-        if(txState != TransactionState.NONE) {
-            val result = task.get();
-            flushTransaction();
-            return result;
+        if(currentTransactionState() != TransactionState.NONE) {
+            return Result.of(callable);
         }
 
-        return executeWithinNewTransaction(task);
+        return Result.of(()->executeWithinNewTransaction(callable));
     }
 
     // -- HELPER
@@ -189,6 +140,18 @@ public class TransactionServiceSpring implements TransactionService {
         LOG
     }
 
+    private <T> T executeWithinNewTransaction(Callable<T> callable) {
+
+        return transactionTemplate.execute(new TransactionCallback<T>() {
+            // the code in this method executes in a transactional context
+            @SneakyThrows
+            @Override
+            public T doInTransaction(TransactionStatus status) {
+                return callable.call();
+            }
+        });
+    }
+    
     private IsisTransactionObject currentTransactionObject(WarnIfNonePolicy warnIfNonePolicy) {
 
         val txObject = IsisTransactionAspectSupport.currentTransactionObject().orElse(null);
diff --git a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo.java b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo.java
index 318f02f..7c71cbc 100644
--- a/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo.java
+++ b/extensions/core/command-log/impl/src/main/java/org/apache/isis/extensions/commandlog/impl/jdo/CommandJdo.java
@@ -53,6 +53,7 @@ import org.apache.isis.applib.services.tablecol.TableColumnOrderForCollectionTyp
 import org.apache.isis.applib.types.MemberIdentifierType;
 import org.apache.isis.applib.util.ObjectContracts;
 import org.apache.isis.applib.util.TitleBuffer;
+import org.apache.isis.commons.functional.Result;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.extensions.commandlog.impl.IsisModuleExtCommandLogImpl;
@@ -626,14 +627,11 @@ public class CommandJdo
             }
 
             @Override
-            public void setResult(final Bookmark resultBookmark) {
-                CommandJdo.this.setResult(resultBookmark);
-            }
-
-            @Override
-            public void setException(Throwable throwable) {
-                CommandJdo.this.setException(throwable);
+            public void setResult(final Result<Bookmark> resultBookmark) {
+                CommandJdo.this.setResult(resultBookmark.value().orElse(null));
+                CommandJdo.this.setException(resultBookmark.failure().orElse(null));
             }
+            
         };
     }
 
diff --git a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/jobcallables/IsTickingClockInitialized.java b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/jobcallables/IsTickingClockInitialized.java
index c996ad8..7f8de32 100644
--- a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/jobcallables/IsTickingClockInitialized.java
+++ b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/jobcallables/IsTickingClockInitialized.java
@@ -35,6 +35,7 @@ public class IsTickingClockInitialized implements Callable<Boolean> {
     @Override
     public Boolean call() {
         return transactionService.executeWithinTransaction(
-                () -> tickingClockService.isInitialized());
+                () -> tickingClockService.isInitialized())
+                .orElseFail();
     }
 }
diff --git a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/jobcallables/ReplicateAndRunCommands.java b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/jobcallables/ReplicateAndRunCommands.java
index 11b4f05..d6f5f1e 100644
--- a/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/jobcallables/ReplicateAndRunCommands.java
+++ b/extensions/core/command-replay/secondary/src/main/java/org/apache/isis/extensions/commandreplay/secondary/jobcallables/ReplicateAndRunCommands.java
@@ -110,6 +110,7 @@ public class ReplicateAndRunCommands implements Callable<SecondaryStatus> {
                         .map(dto ->
                                 transactionService.executeWithinTransaction(
                                     () -> commandJdoRepository.saveForReplay(dto))
+                                .orElseFail()
                         ).collect(Collectors.toList());
 
                 if(commandsToReplay.isEmpty()) {
@@ -148,7 +149,8 @@ public class ReplicateAndRunCommands implements Callable<SecondaryStatus> {
             val parent = commandJdo;
             val childCommands =
                     transactionService.executeWithinTransaction(
-                            () -> commandJdoRepository.findByParent(parent));
+                            () -> commandJdoRepository.findByParent(parent))
+                    .orElseFail();
             for (val childCommand : childCommands) {
                 val childReplayState = executeCommandInTranAndAnalyse(childCommand);
                 if(childReplayState.isFailed()) {
@@ -179,7 +181,7 @@ public class ReplicateAndRunCommands implements Callable<SecondaryStatus> {
 
     private boolean isRunning() {
         return controller
-                .map( control -> transactionService.executeWithinTransaction(control::getState))
+                .map( control -> transactionService.executeWithinTransaction(control::getState).orElseFail())
                 .map(state -> state == ReplayCommandExecutionController.State.RUNNING)
             // if no controller implementation provided, then just continue
             .orElse(true);
diff --git a/legacy/jdo/datanucleus/src/main/java/org/apache/isis/legacy/jdo/datanucleus/persistence/PersistenceSession5.java b/legacy/jdo/datanucleus/src/main/java/org/apache/isis/legacy/jdo/datanucleus/persistence/PersistenceSession5.java
index 5037138..3507319 100644
--- a/legacy/jdo/datanucleus/src/main/java/org/apache/isis/legacy/jdo/datanucleus/persistence/PersistenceSession5.java
+++ b/legacy/jdo/datanucleus/src/main/java/org/apache/isis/legacy/jdo/datanucleus/persistence/PersistenceSession5.java
@@ -232,8 +232,10 @@ implements IsisLifecycleListener.PersistenceSessionLifecycleManagement {
 
         final PersistenceQueryProcessor<? extends PersistenceQuery> processor = lookupProcessorFor(persistenceQuery);
 
-        final Can<ManagedObject> instances = transactionService.executeWithinTransaction(
-                ()->processPersistenceQuery(processor, persistenceQuery) );
+        final Can<ManagedObject> instances = transactionService
+                .executeWithinTransaction(
+                        ()->processPersistenceQuery(processor, persistenceQuery) )
+                .orElseFail();
         
         return instances;
         
diff --git a/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/fixturescripts/FixtureScripts.java b/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/fixturescripts/FixtureScripts.java
index d18f3ed..7fbe7c4 100644
--- a/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/fixturescripts/FixtureScripts.java
+++ b/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/fixturescripts/FixtureScripts.java
@@ -389,7 +389,8 @@ public class FixtureScripts {
             transactionService.executeWithinTransaction(()->
                 runBuilderScriptNonTransactional(builderScript)
             )
-        );
+        )
+        .orElseFail();
     }
 
     /**
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
index 8017a09..e01cf38 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
@@ -42,6 +42,7 @@ import org.apache.isis.applib.services.exceprecog.ExceptionRecognizerService;
 import org.apache.isis.applib.services.i18n.TranslationService;
 import org.apache.isis.applib.services.message.MessageService;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
+import org.apache.isis.commons.functional.Result;
 import org.apache.isis.commons.internal.collections._Sets;
 import org.apache.isis.core.metamodel.facets.actions.redirect.RedirectFacet;
 import org.apache.isis.core.metamodel.facets.properties.renderunchanged.UnchangingFacet;
@@ -246,7 +247,7 @@ implements FormExecutor {
             // irrespective, capture error in the Command, and propagate
             if (command != null) {
                 
-                command.updater().setException(ex);
+                command.updater().setResult(Result.failure(ex));
                 
                 //XXX legacy of
                 //command.internal().setException(Throwables.getStackTraceAsString(ex));