You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@causeway.apache.org by da...@apache.org on 2026/05/06 09:05:38 UTC

(causeway) branch CAUSEWAY-3998 created (now a06d92a56a5)

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

danhaywood pushed a change to branch CAUSEWAY-3998
in repository https://gitbox.apache.org/repos/asf/causeway.git


      at a06d92a56a5 CAUSEWAY-3998 : adds CommandReplayManager#replayOrRetryNext

This branch includes the following new commits:

     new a06d92a56a5 CAUSEWAY-3998 : adds CommandReplayManager#replayOrRetryNext

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



(causeway) 01/01: CAUSEWAY-3998 : adds CommandReplayManager#replayOrRetryNext

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch CAUSEWAY-3998
in repository https://gitbox.apache.org/repos/asf/causeway.git

commit a06d92a56a55fe5159e7f3b857c7c89d2a653b29
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Wed May 6 10:05:29 2026 +0100

    CAUSEWAY-3998 : adds CommandReplayManager#replayOrRetryNext
---
 .../applib/dom/replay/CommandReplayManager.java    | 65 ++++++++++++++++++----
 1 file changed, 54 insertions(+), 11 deletions(-)

diff --git a/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/replay/CommandReplayManager.java b/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/replay/CommandReplayManager.java
index becf8d46ef6..772907ff31b 100644
--- a/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/replay/CommandReplayManager.java
+++ b/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/replay/CommandReplayManager.java
@@ -23,6 +23,7 @@
 import java.sql.Timestamp;
 import java.util.List;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -49,6 +50,8 @@
 import org.apache.causeway.extensions.commandlog.applib.dom.CommandLogEntryRepository;
 import org.apache.causeway.schema.cmd.v2.CommandDto;
 
+import org.jspecify.annotations.NonNull;
+
 import lombok.Getter;
 
 @DomainObject(introspection = Introspection.ANNOTATION_REQUIRED)
@@ -160,9 +163,9 @@ private static Timestamp addSeconds(Timestamp since, int secondsToAdd) {
             executionPublishing = Publishing.DISABLED
     )
     @ActionLayout(
-            sequence = "0.1",
+            sequence = "1.1",
             associateWith = "pendingOrFailed",
-            cssClass = "btn-primary",
+            cssClass = "btn-secondary",
             describedAs = "Imports commands from yaml format, then persists them with replayState=PENDING."
     )
     public class importCommands {
@@ -187,13 +190,21 @@ public CommandReplayManager act(
             describedAs = "Imported Commands that can be either replayed (replayState=PENDING) or retried (when replayState=FAILED)"
     )
     public List<ReplayableCommand> getPendingOrFailed() {
-        return commandLogEntryRepository().findForegroundSinceTimestampAndWithReplayPendingOrFailed(since).stream()
-            .map(entry->new ReplayableCommand(
-                    entry.getInteractionId(),
-                    replayContext))
+        return streamPendingOrFailed()
             .collect(Collectors.toList());
     }
 
+    private @NonNull Stream<ReplayableCommand> streamPendingOrFailed() {
+        return commandLogEntryRepository().findForegroundSinceTimestampAndWithReplayPendingOrFailed(since).stream()
+                .map(entry -> new ReplayableCommand(
+                        entry.getInteractionId(),
+                        replayContext));
+    }
+
+    private long sizePendingOrFailed() {
+        return streamPendingOrFailed().count();
+    }
+
 
     @Action(
             restrictTo = RestrictTo.PROTOTYPING,
@@ -204,9 +215,9 @@ public List<ReplayableCommand> getPendingOrFailed() {
             executionPublishing = Publishing.DISABLED
     )
     @ActionLayout(
-            associateWith = "pendingOrFailed", sequence = "1.1",
-            cssClassFa = "solid circle-play",
+            associateWith = "pendingOrFailed", sequence = "1.2",
             cssClass = "btn-primary",
+            cssClassFa = "solid circle-play",
             describedAs = "Executes the list of commands in sequence, after having sorted them by their timestamp. "
                     + "If any of the given commands fails, "
                     + "its surrounding transaction is rolled back, but any successful commands so far are marked OK). "
@@ -246,6 +257,36 @@ public List<ReplayableCommand> choicesSelected() {
 
 
 
+    @Action(
+            restrictTo = RestrictTo.PROTOTYPING,
+            choicesFrom = "pendingOrFailed",
+            semantics = SemanticsOf.NON_IDEMPOTENT,
+            commandPublishing = Publishing.DISABLED,
+            domainEvent = replayOrRetrySelected.DomainEvent.class,
+            executionPublishing = Publishing.DISABLED
+    )
+    @ActionLayout(
+            associateWith = "pendingOrFailed", sequence = "1.3",
+            cssClassFa = "solid circle-play",
+            cssClass = "btn-primary",
+            describedAs = "Executes the oldest command.")
+    public class replayOrRetryNext {
+        public class DomainEvent extends ActionDomainEvent<replayOrRetrySelected> { }
+        @MemberSupport public CommandReplayManager act() {
+            var nextIfAny = streamPendingOrFailed().findFirst();
+            // should always be present, due to our guard
+            nextIfAny.ifPresent(ReplayableCommand::tryReplayOrRetry);
+            return CommandReplayManager.this;
+        }
+
+        @MemberSupport
+        public String disableAct() {
+            return sizePendingOrFailed() == 0 ? "No commands in collection" : null;
+        }
+    }
+
+
+
     @Action(
             restrictTo = RestrictTo.PROTOTYPING,
             choicesFrom = "pendingOrFailed",
@@ -255,7 +296,8 @@ public List<ReplayableCommand> choicesSelected() {
             executionPublishing = Publishing.DISABLED
     )
     @ActionLayout(
-            associateWith = "pendingOrFailed", sequence = "1.2",
+            associateWith = "pendingOrFailed", sequence = "1.4",
+            cssClass = "btn-secondary",
             describedAs = "Marks selected Commands to be EXCLUDED from replay"
     )
     public class excludeSelectedFromReplay {
@@ -269,7 +311,7 @@ public CommandReplayManager act(final List<ReplayableCommand> selected) {
 
         @MemberSupport
         public String disableAct() {
-            return getPendingOrFailed().isEmpty() ? "No commands in collection" : null;
+            return sizePendingOrFailed() == 0 ? "No commands in collection" : null;
         }
 
         @MemberSupport
@@ -296,7 +338,8 @@ public List<ReplayableCommand> choicesSelected() {
             executionPublishing = Publishing.DISABLED
     )
     @ActionLayout(
-            associateWith = "pendingOrFailed", sequence = "1.3",
+            associateWith = "pendingOrFailed", sequence = "1.4",
+            cssClass = "btn-danger",
             describedAs = "Deletes selected Commands (cannot be undone)"
     )
     public class deleteSelectedPendingOrFailed {