You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@causeway.apache.org by ah...@apache.org on 2026/04/15 05:40:35 UTC
(causeway) branch 3989-cmd-io updated: CAUSEWAY-3989: Command Replay Manager w/ 2 tables (PENDING/FAILED and OK/EXCLUDE)
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch 3989-cmd-io
in repository https://gitbox.apache.org/repos/asf/causeway.git
The following commit(s) were added to refs/heads/3989-cmd-io by this push:
new 08ddf31157d CAUSEWAY-3989: Command Replay Manager w/ 2 tables (PENDING/FAILED and OK/EXCLUDE)
08ddf31157d is described below
commit 08ddf31157dedea1213a8b0de6b4344832b48271
Author: andi-huber <ah...@apache.org>
AuthorDate: Wed Apr 15 07:40:27 2026 +0200
CAUSEWAY-3989: Command Replay Manager w/ 2 tables (PENDING/FAILED and
OK/EXCLUDE)
first allows replay or retry
second collects those that are done
---
.../applib/dom/CommandLogEntryRepository.java | 9 +++-
.../dom/CommandLogEntryRepositoryAbstract.java | 19 ++++++--
.../applib/dom/replay/CommandReplayManager.java | 56 ++++++++++++++++------
.../dom/replay/CommandReplayManager.layout.xml | 7 ++-
.../applib/dom/replay/ReplayableCommand.java | 18 ++++++-
.../integtest/CommandLog_IntegTestAbstract.java | 4 +-
.../commandlog/jpa/dom/CommandLogEntry.java | 9 ++--
7 files changed, 94 insertions(+), 28 deletions(-)
diff --git a/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/CommandLogEntryRepository.java b/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/CommandLogEntryRepository.java
index 7b8e1f913c9..d067f446e76 100644
--- a/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/CommandLogEntryRepository.java
+++ b/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/CommandLogEntryRepository.java
@@ -158,7 +158,14 @@ List<CommandLogEntry> findByTargetAndFromAndTo(
*/
Optional<CommandLogEntry> findMostRecentCompleted();
- List<CommandLogEntry> findNotYetReplayed();
+ /**
+ * Command Replay feature: Can replay or retry.
+ */
+ List<CommandLogEntry> findReplayPendingOrFailed();
+ /**
+ * Command Replay feature: Cannot replay or retry.
+ */
+ List<CommandLogEntry> findReplaySucceededOrExcluded();
CommandLogEntry saveForReplay(CommandDto dto);
diff --git a/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/CommandLogEntryRepositoryAbstract.java b/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/CommandLogEntryRepositoryAbstract.java
index 3b0d840a2a0..bacaa3bfda6 100644
--- a/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/CommandLogEntryRepositoryAbstract.java
+++ b/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/CommandLogEntryRepositoryAbstract.java
@@ -333,14 +333,25 @@ public Optional<CommandLogEntry> findMostRecentCompleted() {
Query.named(commandLogEntryClass, CommandLogEntry.Nq.FIND_MOST_RECENT_COMPLETED))
);
}
-
@Override
- public List<CommandLogEntry> findNotYetReplayed() {
+ public List<CommandLogEntry> findReplayPendingOrFailed() {
+ return _Casts.uncheckedCast(
+ repositoryService().allMatches(
+ Query.named(commandLogEntryClass, CommandLogEntry.Nq.FIND_BY_REPLAY_STATE)
+ .withParameter("replayState1", ReplayState.PENDING)
+ .withParameter("replayState2", ReplayState.FAILED))
+ );
+ }
+ /**
+ * Command Replay feature: Cannot replay or retry.
+ */
+ @Override
+ public List<CommandLogEntry> findReplaySucceededOrExcluded() {
return _Casts.uncheckedCast(
repositoryService().allMatches(
Query.named(commandLogEntryClass, CommandLogEntry.Nq.FIND_BY_REPLAY_STATE)
- .withParameter("replayState", ReplayState.PENDING)
- .withLimit(10))
+ .withParameter("replayState1", ReplayState.OK)
+ .withParameter("replayState2", ReplayState.EXCLUDED))
);
}
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 efe179ca14c..72303f3a217 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
@@ -39,7 +39,6 @@
import org.apache.causeway.applib.value.NamedWithMimeType.CommonMimeType;
import org.apache.causeway.extensions.commandlog.applib.CausewayModuleExtCommandLogApplib;
import org.apache.causeway.extensions.commandlog.applib.dom.CommandLogEntryRepository;
-import org.apache.causeway.extensions.commandlog.applib.dom.ReplayState;
import org.apache.causeway.schema.cmd.v2.CommandDto;
@DomainObject(introspection = Introspection.ANNOTATION_REQUIRED)
@@ -76,39 +75,66 @@ public CommandReplayManager importCommands(
return this;
}
- // -- NOT YET REPLAYED
+ // -- PENDING OR FAILED
@Collection
- public List<ReplayableCommand> getNotYetReplayed() {
- return commandLogEntryRepository().findNotYetReplayed().stream()
+ public List<ReplayableCommand> getPendingOrFailed() {
+ return commandLogEntryRepository().findReplayPendingOrFailed().stream()
.map(entry->new ReplayableCommand(
replayContext.bookmarkService().bookmarkFor(entry).get().identifier(),
replayContext))
.toList();
}
- @Action(choicesFrom = "notYetReplayed")
- @ActionLayout(associateWith = "notYetReplayed")
- public CommandReplayManager replaySelected(final List<ReplayableCommand> selected) {
+ @Action(choicesFrom = "pendingOrFailed")
+ @ActionLayout(associateWith = "pendingOrFailed",
+ sequence = "1.1",
+ cssClassFa = "solid circle-play",
+ cssClass = "btn-primary")
+ public CommandReplayManager replayOrRetrySelected(final List<ReplayableCommand> selected) {
selected.stream()
- .filter(c->c.getReplayState() == ReplayState.PENDING)
- .forEach(ReplayableCommand::replay);
+ .forEach(ReplayableCommand::replay); // filtered on its own responsibility
return this;
}
- @Action(choicesFrom = "notYetReplayed")
- @ActionLayout(associateWith = "notYetReplayed",
+ @Action(choicesFrom = "pendingOrFailed")
+ @ActionLayout(associateWith = "pendingOrFailed", sequence = "1.2",
describedAs = "Marks selected Commands to be EXCLUDED from replay.")
public CommandReplayManager excludeSelectedFromReplay(final List<ReplayableCommand> selected) {
selected.stream()
- .filter(c->c.getReplayState() == ReplayState.PENDING)
- .forEach(ReplayableCommand::excludeFromReplay);
+ .forEach(ReplayableCommand::excludeFromReplay); // filtered on its own responsibility
return this;
}
- // -- FAILED //TODO
+ @Action(choicesFrom = "pendingOrFailed")
+ @ActionLayout(associateWith = "pendingOrFailed", sequence = "1.3",
+ describedAs = "Deletes selected Commands.")
+ public CommandReplayManager deleteSelected(final List<ReplayableCommand> selected) {
+ selected.stream()
+ .forEach(ReplayableCommand::delete); // filtered on its own responsibility
+ return this;
+ }
+
+ // -- OK OR EXCLUDE
+
+ @Collection
+ public List<ReplayableCommand> getSucceededOrExcluded() {
+ return commandLogEntryRepository().findReplaySucceededOrExcluded().stream()
+ .map(entry->new ReplayableCommand(
+ replayContext.bookmarkService().bookmarkFor(entry).get().identifier(),
+ replayContext))
+ .toList();
+ }
- // -- OK //TODO
+ @Action(choicesFrom = "succeededOrExcluded")
+ @ActionLayout(associateWith = "succeededOrExcluded",
+ named = "Delete Selected",
+ describedAs = "Deletes selected Commands.")
+ public CommandReplayManager deleteSelected2(final List<ReplayableCommand> selected) {
+ selected.stream()
+ .forEach(ReplayableCommand::delete); // filtered on its own responsibility
+ return this;
+ }
// -- VM STATE
diff --git a/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/replay/CommandReplayManager.layout.xml b/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/replay/CommandReplayManager.layout.xml
index 1f09f254ecc..30489ca2158 100644
--- a/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/replay/CommandReplayManager.layout.xml
+++ b/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/replay/CommandReplayManager.layout.xml
@@ -33,7 +33,12 @@
<bs:col span="12">
<bs:row>
<bs:col span="12" size="MD">
- <cpt:collection defaultView="table" paged="15" id="notYetReplayed"/>
+ <cpt:collection defaultView="table" paged="15" id="pendingOrFailed"/>
+ </bs:col>
+ </bs:row>
+ <bs:row>
+ <bs:col span="12" size="MD">
+ <cpt:collection defaultView="table" paged="15" id="succeededOrExcluded"/>
</bs:col>
</bs:row>
</bs:col>
diff --git a/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/replay/ReplayableCommand.java b/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/replay/ReplayableCommand.java
index 63af5ad1955..4550c7e8b6e 100644
--- a/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/replay/ReplayableCommand.java
+++ b/extensions/core/commandlog/applib/src/main/java/org/apache/causeway/extensions/commandlog/applib/dom/replay/ReplayableCommand.java
@@ -203,6 +203,7 @@ public ReplayableCommand replay() {
if(disableReplay()!=null)
return this; // safe guard when called programmatically
commandLogEntry()
+ .filter(ReplayableCommand::canReplayOrRetryOrMarkForExclusion)
.ifPresent(commandLogEntry->{
commandLogEntry.setExecuteIn(ExecuteIn.FOREGROUND);
replayContext.commandExecutorService().executeCommand(commandLogEntry.getCommandDto());
@@ -226,7 +227,7 @@ public ReplayableCommand excludeFromReplay() {
if(disableExcludeFromReplay()!=null)
return this; // safe guard when called programmatically
commandLogEntry()
- .filter(commandLogEntry->commandLogEntry.getReplayState() == ReplayState.PENDING)
+ .filter(ReplayableCommand::canReplayOrRetryOrMarkForExclusion)
.ifPresent(commandLogEntry->commandLogEntry.setReplayState(ReplayState.EXCLUDED));
return this;
}
@@ -238,6 +239,16 @@ public ReplayableCommand excludeFromReplay() {
: "Cannot mark for exclusion, if not PENDING nor FAILED";
}
+ @Action
+ @ActionLayout(
+ //hidden = Where.NOWHERE, // show in tables //TODO NPE bug
+ describedAs = "Marks Command to be EXCLUDED from replay.")
+ public ReplayableCommand delete() {
+ commandLogEntry()
+ .ifPresent(commandLogEntry->commandLogEntry.setReplayState(ReplayState.EXCLUDED));
+ return this;
+ }
+
// -- VM STATE
@Override
@@ -268,4 +279,9 @@ private Bookmark commandLogEntryBookmark() {
commandLogEntryId));
}
+ private static boolean canReplayOrRetryOrMarkForExclusion(final CommandLogEntry commandLogEntry) {
+ return commandLogEntry.getReplayState() == ReplayState.PENDING
+ || commandLogEntry.getReplayState() == ReplayState.FAILED;
+ }
+
}
diff --git a/extensions/core/commandlog/applib/src/test/java/org/apache/causeway/extensions/commandlog/applib/integtest/CommandLog_IntegTestAbstract.java b/extensions/core/commandlog/applib/src/test/java/org/apache/causeway/extensions/commandlog/applib/integtest/CommandLog_IntegTestAbstract.java
index 8909aa77aac..1c94cd85468 100644
--- a/extensions/core/commandlog/applib/src/test/java/org/apache/causeway/extensions/commandlog/applib/integtest/CommandLog_IntegTestAbstract.java
+++ b/extensions/core/commandlog/applib/src/test/java/org/apache/causeway/extensions/commandlog/applib/integtest/CommandLog_IntegTestAbstract.java
@@ -361,7 +361,7 @@ void test_all_the_repository_methods() {
var to = from.plusDays(1);
// when
- List<? extends CommandLogEntry> notYetReplayed = commandLogEntryRepository.findNotYetReplayed();
+ List<? extends CommandLogEntry> notYetReplayed = commandLogEntryRepository.findReplayPendingOrFailed();
// then
Assertions.assertThat(notYetReplayed).isEmpty();
@@ -374,7 +374,7 @@ void test_all_the_repository_methods() {
commandTarget1User1.setReplayState(ReplayState.PENDING);
// when
- List<? extends CommandLogEntry> notYetReplayed2 = commandLogEntryRepository.findNotYetReplayed();
+ List<? extends CommandLogEntry> notYetReplayed2 = commandLogEntryRepository.findReplayPendingOrFailed();
// then
Assertions.assertThat(notYetReplayed2).hasSize(1);
diff --git a/extensions/core/commandlog/persistence-jpa/src/main/java/org/apache/causeway/extensions/commandlog/jpa/dom/CommandLogEntry.java b/extensions/core/commandlog/persistence-jpa/src/main/java/org/apache/causeway/extensions/commandlog/jpa/dom/CommandLogEntry.java
index a760611bc0e..0ac083a3198 100644
--- a/extensions/core/commandlog/persistence-jpa/src/main/java/org/apache/causeway/extensions/commandlog/jpa/dom/CommandLogEntry.java
+++ b/extensions/core/commandlog/persistence-jpa/src/main/java/org/apache/causeway/extensions/commandlog/jpa/dom/CommandLogEntry.java
@@ -198,7 +198,8 @@
name = Nq.FIND_MOST_RECENT_REPLAYED,
query = "SELECT cl "
+ " FROM CommandLogEntry cl "
- + " WHERE (cl.replayState = org.apache.causeway.extensions.commandlog.applib.dom.ReplayState.OK OR cl.replayState = org.apache.causeway.extensions.commandlog.applib.dom.ReplayState.FAILED) "
+ + " WHERE (cl.replayState = org.apache.causeway.extensions.commandlog.applib.dom.ReplayState.OK"
+ + " OR cl.replayState = org.apache.causeway.extensions.commandlog.applib.dom.ReplayState.FAILED) "
+ " ORDER BY cl.timestamp DESC"), // programmatic LIMIT 1
@NamedQuery(
name = Nq.FIND_MOST_RECENT_COMPLETED,
@@ -210,9 +211,9 @@
@NamedQuery(
name = Nq.FIND_BY_REPLAY_STATE,
query = "SELECT cl "
- + " FROM CommandLogEntry cl "
- + " WHERE cl.replayState = :replayState "
- + " ORDER BY cl.timestamp ASC"), // programmatic LIMIT 10
+ + " FROM CommandLogEntry cl "
+ + " WHERE (cl.replayState = :replayState1 OR cl.replayState = :replayState2) "
+ + " ORDER BY cl.timestamp ASC"),
})
@Named(CommandLogEntry.LOGICAL_TYPE_NAME)
@DomainObject(