You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2020/09/20 15:10:12 UTC

[isis] 01/02: ISIS-2222: improving command docs.

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

danhaywood pushed a commit to branch ISIS-2222
in repository https://gitbox.apache.org/repos/asf/isis.git

commit 8f80c0e1d54967de7c5f5a7b817ef7d6b9510024
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Sun Sep 20 15:49:26 2020 +0100

     ISIS-2222: improving command docs.
---
 .../main/adoc/modules/applib-ant/pages/Action.adoc |  12 +-
 .../modules/applib-ant/pages/Action/command.adoc   | 280 ++-------------------
 .../adoc/modules/applib-ant/pages/Property.adoc    |  13 +-
 .../modules/applib-ant/pages/Property/command.adoc |  38 ++-
 .../events/domainevent/ActionDomainEvent.adoc      |  17 +-
 .../reference-services/commands-and-events.png     | Bin 51656 -> 55126 bytes
 .../reference-services/commands-and-events.pptx    | Bin 42272 -> 43735 bytes
 .../pages/CommandDtoProcessorService.adoc          |   4 +-
 .../applib-svc/pages/CommandExecutorService.adoc   |   4 +-
 .../modules/applib-svc/pages/CommandService.adoc   |  46 +---
 .../applib-svc/pages/CommandServiceListener.adoc   |   8 +
 .../applib-svc/pages/InteractionContext.adoc       |  66 ++---
 .../main/adoc/modules/applib-svc/pages/about.adoc  |  16 +-
 .../partials/_application-layer-api.adoc           |   6 -
 .../applib-svc/partials/_integration-spi.adoc      |  10 +-
 .../modules/applib-svc/partials/module-nav.adoc    |   2 +-
 .../applib/events/domain/ActionDomainEvent.java    |  22 --
 .../applib/services/iactn/InteractionContext.java  |   3 +-
 18 files changed, 99 insertions(+), 448 deletions(-)

diff --git a/api/applib/src/main/adoc/modules/applib-ant/pages/Action.adoc b/api/applib/src/main/adoc/modules/applib-ant/pages/Action.adoc
index 4d2cb68..145ac50 100644
--- a/api/applib/src/main/adoc/modules/applib-ant/pages/Action.adoc
+++ b/api/applib/src/main/adoc/modules/applib-ant/pages/Action.adoc
@@ -20,19 +20,11 @@ associates an action with another property or collection of the action.
 the ordering of multiple actions associated with another property/collection.
 
 <.> xref:refguide:applib-ant:Action.adoc#command[`command()`]
-whether the action invocation should be reified into a `Command` object using the xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`] service:
-
-<.> `commandExecuteIn()`
-+
-Whether to execute the command immediately, or to persist it (assuming that an appropriate implementation of xref:refguide:applib-svc:CommandService.adoc[`CommandService`] has been configured) such that a background scheduler can execute the command asynchronously
-
-<.> `commandPersistence()`
-+
-Whether the reified `Command` (obtainable from the `InteractionContext` domain service) should actually be persisted (assuming an appropriate implementation of xref:refguide:applib-svc:CommandService.adoc[`CommandService`] has been configured).
+whether the action invocation should be reified into a `Command`, typically so it can be logged using the xref:extensions:command-log:about.adoc[Command Log] extension  (for auditing or for regression testing using xref:extensions:command-replay:about.adoc[Command Replay]).
 
 <.> `commandDtoProcessor()`
 +
-If the `Command` also implements `CommandWithDto` (meaning that it can return a `CommandDto`, in other words be converted into an XML memento), then optionally specifies a processor that can refine this XML.
+If the xref:extensions:command-replay:about.adoc[Command Replay] extension is being used (for regression testing), provides a mechanism to process the `CommandDto` before being replicated from primary to secondary system
 
 <.> xref:refguide:applib-ant:Action.adoc#domainEvent[`domainEvent()`]
 +
diff --git a/api/applib/src/main/adoc/modules/applib-ant/pages/Action/command.adoc b/api/applib/src/main/adoc/modules/applib-ant/pages/Action/command.adoc
index b30b43d..b8db600 100644
--- a/api/applib/src/main/adoc/modules/applib-ant/pages/Action/command.adoc
+++ b/api/applib/src/main/adoc/modules/applib-ant/pages/Action/command.adoc
@@ -4,283 +4,31 @@
 :Notice: 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 ag [...]
 :page-partial:
 
-CAUTION: TODO - v2, this documentation is not out of date.
+Every action invocation (and xref:Property.adoc#command[property edit] for that matter) is normally reified into a concrete `Command` object, basically a wrapper around the XML invocation xref:schema:cmd.adoc[Command] schema that also captures some timing metrics about the execution as well as the outcome.
 
-Every action invocation (and property edit for that matter) is automatically reified into a concrete `Command` object.
-The `@Action(command=..., commandXxx=...)` attributes provide hints for the persistence of that `Command` object, and the subsequent processing of that persisted command.
-The primary use cases for this are to support the deferring the execution of the action such that it can be invoked in the background, and to replay commands in a master/slave configuration.
+The main uses cases are:
 
-Note that for a `Command` to actually be persisted requires an appropriate implementation of `CommandService` SPI.
-The framework does _not_ provide an implementation of this SPI "out-of-the-box".
-However, the xref:extensions:command-log:about.adoc[Command Log] extension _does_ provide such an implementation.
+* as a means to allow asynchronous child commands to be executed, using the xref:refguide:applib-svc:WrapperFactory.adoc[`WrapperFactory`] service;
 
-== Design
-
-The annotation works with (and is influenced by the behaviour of) a number of domain services:
-
-* xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`]
-* xref:refguide:applib-svc:CommandService.adoc[`CommandService`]
-//* xref:refguide:applib-svc:BackgroundService.adoc[`BackgroundService`] and
-//* xref:refguide:applib-svc:BackgroundCommandService.adoc[`BackgroundCommandService`]
-
-
-Each action invocation is automatically reified by the xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`] service into a `Command` object, capturing details of the target object, the action, the parameter arguments, the user, a timestamp and so on.
-
-If an appropriate `CommandService` is configured
-//(for example using (non-ASF) link:https://platform.incode.org/modules/spi/command/spi-command.html[Incode Platform's command] module),
-then the `Command` itself is persisted.
-
-By default, actions are invoked in directly in the thread of the invocation.
-//If there is an implementation of `BackgroundCommandService` (as the (non-ASF) link:https://platform.incode.org[Incode Platform^]'s command module does provide), then this means in turn that the `BackgroundService` can be used by the domain object code to programmatically create background ``Command``s.
-
-//[NOTE]
-//====
-//If background ``Command``s are used, then an external scheduler, using xref:userguide:btb:about.adoc#BackgroundCommandExecution[headless access], must also be configured.
-//====
-
-
-
-== `command` and `commandPersistence`
-
-The `command()` and `commandPersistence() attributes work together to determine whether a command will actually be persisted.
-There inter-relationship is somewhat complex, so is probably best explained by way of examples:
-
-[cols="1a,1a,1a,1a,1a,2a",options="header"]
-|===
-
-| `command()`
-|`isis.services.
-  command.actions` config property
-| action's declared `semantics()`
-| `command
-Persistence()`
-| action dirties objects?
-| is command persisted?
-
-| `ENABLED`
-| (any)
-| (any)
-| `PERSISTED`
-| (either)
-| yes
-
-| `ENABLED`
-| (any)
-| (any)
-| `IF_HINTED`
-| no
-| no
-
-| `ENABLED`
-| (any)
-| (any)
-| `IF_HINTED`
-| yes
-| yes
-
-| `ENABLED`
-| (any)
-| (any)
-| `NOT_PERSISTED`
-| (any)
-| no
-
-| `AS_CONFIGURED`
-| `all`
-| (any)
-| `PERSISTED`
-| no
-| yes
-
-| `AS_CONFIGURED`
-| `all`
-| (any)
-| `IF_HINTED`
-| no
-| no
-
-| `AS_CONFIGURED`
-| `all`
-| (any)
-| `IF_HINTED`
-| yes
-| yes
-
-| `AS_CONFIGURED`
-| `all`
-| (any)
-| `NOT_PERSISTED`
-| (any)
-| no
-
-| `AS_CONFIGURED`
-| `ignoreSafe` or `ignoreQueryOnly`
-| `SAFE`
-| `PERSISTED`
-| no
-| no (!)
-
-| `AS_CONFIGURED`
-| `ignoreSafe` or `ignoreQueryOnly`
-| `SAFE`
-| `IF_HINTED` or `NOT_PERSISTED`
-| no
-| no
-
-| `AS_CONFIGURED`
-| `ignoreSafe` or `ignoreQueryOnly`
-| `SAFE`
-| `PERSISTED` or `IF_HINTED`
-| yes
-| yes
-
-| `AS_CONFIGURED`
-| `ignoreSafe` or `ignoreQueryOnly`
-| `SAFE`
-| `NOT_PERSISTED`
-| yes
-| yes (!)
-
-| `AS_CONFIGURED`
-| `ignoreSafe` or `ignoreQueryOnly`
-| `IDEMPOTENT` or `NON_IDEMPOTENT`
-| `PERSISTED`
-| (any)
-| yes
-
-| `AS_CONFIGURED`
-| `ignoreSafe` or `ignoreQueryOnly`
-| `IDEMPOTENT` or `NON_IDEMPOTENT`
-| `IF_HINTED`
-| no
-| no
-
-| `AS_CONFIGURED`
-| `ignoreSafe` or `ignoreQueryOnly`
-| `IDEMPOTENT` or `NON_IDEMPOTENT`
-| `IF_HINTED`
-| yes
-| yes
-
-| `AS_CONFIGURED`
-| `ignoreSafe` or `ignoreQueryOnly`
-| `IDEMPOTENT` or `NON_IDEMPOTENT`
-| `NOT_PERSISTED`
-| (any)
-| no
-
-| `AS_CONFIGURED`
-| `none`
-| (any)
-| `PERSISTED`
-| no
-| no (!)
-
-| `AS_CONFIGURED`
-| `none`
-| (any)
-| `PERSISTED`
-| yes
-| yes
-
-| `AS_CONFIGURED`
-| `none`
-| (any)
-| `IF_HINTED`
-| no
-| no
-
-| `AS_CONFIGURED`
-| `none`
-| (any)
-| `IF_HINTED`
-| yes
-| yes
-
-| `AS_CONFIGURED`
-| `none`
-| (any)
-| `NOT_PERSISTED`
-| no
-| no
-
-| `AS_CONFIGURED`
-| `none`
-| (any)
-| `NOT_PERSISTED`
-| yes
-| yes (!)
-
-| `DISABLED`
-| (any)
-| (any)
-| `PERSISTED`
-| no
-| no (!)
-
-| `DISABLED`
-| (any)
-| (any)
-| `PERSISTED`
-| yes
-| yes
-
-| `DISABLED`
-| (any)
-| (any)
-| `IF_HINTED`
-| no
-| no
-
-| `DISABLED`
-| (any)
-| (any)
-| `IF_HINTED`
-| yes
-| yes
-
-| `DISABLED`
-| (any)
-| (any)
-| `NOT_PERSISTED`
-| no
-| no
-
-| `DISABLED`
-| (any)
-| (any)
-| `NOT_PERSISTED`
-| yes
-| yes (!)
-
-|===
-
-For example:
-
-[source,java]
-----
-public class Order {
-    @Action(
-        command=CommandReification.ENABLED,
-        commandPersistence=CommandPersistence.PERSISTED
-    )
-    public Invoice generateInvoice( /* ... */ ) { /* ... */ }
-}
-----
+* as a means to audit (persist) commands, by implementing the xref:refguide:applib-svc:CommandServiceListener.adoc[`CommandServiceListener`] SPI.
++
+The xref:extensions:command-log:about.adoc[Command Log] extension _does_ provide such an implementation.
++
+TIP: Another option to achieve this is to use the xref:refguide:applib-svc:PublisherService.adoc[`PublisherService`] SPI.
 
-As can be seen, whether a command is actually persisted does not always follow the value of the `commandPersistence` attribute.
-This is because the `command` attribute actually determines whether any command metadata for the action is captured within the framework's internal metamodel.
-If `command` is `DISABLED` or does not otherwise apply due to the action's declared semantics, then the framework decides to persist a command based solely on whether the action dirtied any objects (as if `commandPersistence()` was set to `IF_HINTED`).
+* to replay commands onto a secondary system, for regression testing.
++
+This is implemented by the xref:extensions:command-replay:about.adoc[Command Replay] extension, working in conjunction with the xref:extensions:command-log:about.adoc[Command Log] extension.
 
-== `commandExecuteIn`
 
-For persisted commands, the `commandExecuteIn` attribute determines whether the `Command` should be executed in the foreground (the default) or executed in the background.
 
-WARNING: TODO: v2 - background execution has temporarily been removed, will be reinstated for v2.0.
+== `command`
 
+The `command()` attribute can be used to explicitly enable or disable command reification for the action.
 
 
 
+[#commanddtoprocessor]
 == `commandDtoProcessor`
 
 The `commandDtoProcessor` attribute allows an implementation of `CommandDtoProcessor` to be specified.
diff --git a/api/applib/src/main/adoc/modules/applib-ant/pages/Property.adoc b/api/applib/src/main/adoc/modules/applib-ant/pages/Property.adoc
index 4171f0e..7c5a83b 100644
--- a/api/applib/src/main/adoc/modules/applib-ant/pages/Property.adoc
+++ b/api/applib/src/main/adoc/modules/applib-ant/pages/Property.adoc
@@ -15,20 +15,11 @@ include::refguide:applib-ant:example$annotation/Property.java[tags="refguide"]
 ----
 <.> xref:refguide:applib-ant:Property.adoc#command[`command()`]
 +
-Whether the property edit should be reified into a `o.a.i.applib.` +
-`services.command.Command` object through the xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`] service.
-
-<.> `commandPersistence()`
-+
-Whether the reified `Command` (as provided by the `CommandContext` domain service) should actually be persisted (assuming an appropriate implementation of xref:refguide:applib-svc:CommandService.adoc[`CommandService`] has been configured).
-
-<.> `commandExecuteIn()`
-+
-Whether to execute the command immediately, or to persist it (assuming that an appropriate implementation of xref:refguide:applib-svc:CommandService.adoc[`CommandService`] has been configured) such that a background scheduler can execute the command asynchronously
+Whether the property edit should be reified into a `Command`, typically so it can be logged using the xref:extensions:command-log:about.adoc[Command Log] extension  (for auditing or for regression testing using xref:extensions:command-replay:about.adoc[Command Replay]).
 
 <.> `commandDtoProcessor()`
 +
-If the `Command` also implements `CommandWithDto` (meaning that it can return a `CommandDto`, in other words be converted into an XML memento), then optionally specifies the implementation of a `CommandDtoProcessor` that can refine this XML.
+If the xref:extensions:command-replay:about.adoc[Command Replay] extension is being used (for regression testing), provides a mechanism to process the `CommandDto` before being replicated from primary to secondary system
 
 <.> xref:refguide:applib-ant:Property.adoc#domainEvent[`domainEvent()`]
 +
diff --git a/api/applib/src/main/adoc/modules/applib-ant/pages/Property/command.adoc b/api/applib/src/main/adoc/modules/applib-ant/pages/Property/command.adoc
index 40f23a3..a3da1ef 100644
--- a/api/applib/src/main/adoc/modules/applib-ant/pages/Property/command.adoc
+++ b/api/applib/src/main/adoc/modules/applib-ant/pages/Property/command.adoc
@@ -4,26 +4,27 @@
 :Notice: 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 ag [...]
 :page-partial:
 
-CAUTION: TODO - v2 to update, has been simplified.
+Every property edit (and xref:Action.adoc#command[action invocation] for tht matter) is normally reified into a concrete `Command` object, basically a wrapper around the XML invocation xref:schema:cmd.adoc[Command] schema that also captures some timing metrics about the execution as well as the outcome.
 
-Every property edit (and action invocation for that matter) is automatically reified into a concrete `Command` object.
-The `@Property(command=..., commandXxx=...)` attributes provide hints for the persistence of that `Command` object, and the subsequent processing of that persisted command.
-The primary use cases for this are to support the deferring the execution of the action such that it can be invoked in the background, and to replay commands in a master/slave configuration.
+The main uses cases are:
 
+* as a means to allow asynchronous child commands to be executed, using the xref:refguide:applib-svc:WrapperFactory.adoc[`WrapperFactory`] service;
 
-== Design
-
-The annotation works with (and is influenced by the behaviour of) a number of domain services:
+* as a means to audit (persist) commands, by implementing the xref:refguide:applib-svc:CommandServiceListener.adoc[`CommandServiceListener`] SPI.
++
+The xref:extensions:command-log:about.adoc[Command Log] extension _does_ provide such an implementation.
++
+TIP: Another option to achieve this is to use the xref:refguide:applib-svc:PublisherService.adoc[`PublisherService`] SPI.
 
-* xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`]
-* xref:refguide:applib-svc:CommandService.adoc[`CommandService`]
+* to replay commands onto a secondary system, for regression testing.
++
+This is implemented by the xref:extensions:command-replay:about.adoc[Command Replay] extension, working in conjunction with the xref:extensions:command-log:about.adoc[Command Log] extension.
 
 
-Each property edit is automatically reified by the xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`] service into a `Command` object, capturing details of the target object, the property, the proposed new value for the property, the user, a timestamp and so on.
 
-If an appropriate `CommandService` is configured (for example using xref:extensions:command-log:about.adoc[Command Log] extension module), then the `Command` itself is persisted.
+== `command`
 
-By default, actions are invoked in directly in the thread of the invocation.
+The `command()` attribute can be used to explicitly enable or disable command reification for the property edit.
 
 
 
@@ -35,15 +36,13 @@ This interface has the following API:
 [source,java]
 ----
 public interface CommandDtoProcessor {
-    CommandDto process(             // <1>
-            Command command,        // <2>
-            CommandDto dto);        // <3>
+    CommandDto process(             // <.>
+            CommandDto dto);        // <.>
 }
 ----
-<1> The returned `CommandDto`.
-This will typically be the `CommandDto` passed in, but supplemented in some way.
-<2> The `Command` being processed
-<3> The `CommandDto` (XML) obtained already from the `Command` (by virtue of it also implementing `CommandWithDto`, see discussion below).
+<.> The returned `CommandDto`.
+This will typically be the `CommandDto` passed in, but may be supplemented in some way.
+<.> The `CommandDto` obtained already from the `Command`.
 
 This interface is used by the framework-provided implementations of `ContentMappingService` for the REST API, allowing ``Command``s implementations that also implement `CommandWithDto` to be further customised as they are serialized out.
 The primary use case for this capability is in support of master/slave replication.
@@ -62,7 +61,6 @@ A `CommandDtoProcessor` can be provided to re-attach blob information if require
 * replaying ``Command``s requires this missing parameter information to be reinstated.
 The `CommandDtoProcessor` therefore offers a hook to dynamically re-attach the missing `Blob` or `Clob` argument.
 
-
 As a special case, returning `null` means that the command's DTO is effectively excluded when retrieving the list of commands.
 If replicating from master to slave, this effectively allows certain commands to be ignored.
 The `CommandDtoProcessor.Null` class provides a convenience implementation for this requirement.
diff --git a/api/applib/src/main/adoc/modules/applib-classes/pages/events/domainevent/ActionDomainEvent.adoc b/api/applib/src/main/adoc/modules/applib-classes/pages/events/domainevent/ActionDomainEvent.adoc
index 53f9f77..ab3c168 100644
--- a/api/applib/src/main/adoc/modules/applib-classes/pages/events/domainevent/ActionDomainEvent.adoc
+++ b/api/applib/src/main/adoc/modules/applib-classes/pages/events/domainevent/ActionDomainEvent.adoc
@@ -12,7 +12,6 @@ The class has a number of responsibilities (in addition to those it inherits):
 * capture the target object being interacted with
 * capture the arguments for each of the action's parameters
 * provide selected metadata about the action parameters from the metamodel (names, types)
-* link back to the xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`] service's `Command` object
 
 The class itself is instantiated automatically by the framework whenever interacting with a rendered object's action.
 
@@ -30,9 +29,6 @@ public abstract class ActionDomainEvent<S> extends AbstractDomainEvent<S> {
     public static class Noop extends ActionDomainEvent<Object> { }      // <.>
     public static class Doop extends ActionDomainEvent<Object> { }      // <.>
 
-    @Deprecated
-    public Command getCommand();                                        // <.>
-
     public SemanticsOf getSemantics();
 
     public List<String> getParameterNames();
@@ -43,12 +39,11 @@ public abstract class ActionDomainEvent<S> extends AbstractDomainEvent<S> {
     public void setReturnValue();                                       // <.>
 }
 ----
-<1> The `Default` nested static class is the default for the xref:refguide:applib-ant:Action.adoc#domainEvent[`@Action#domainEvent()`]
+<.> The `Default` nested static class is the default for the xref:refguide:applib-ant:Action.adoc#domainEvent[`@Action#domainEvent()`]
 annotation attribute.
 Whether this raises an event or not depends upon the `isis.reflector.facet.actionAnnotation.domainEvent.postForDefault` configuration property.
-<2> The `Noop` class is provided as a convenience to indicate that an event should _not_ be posted (irrespective of the configuration property setting).
-<3> Similarly, the `Doop` class is provided as a convenience to indicate that an event _should_ be raised (irrespective of the configuration property setting).
-<4> Deprecated, use xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`] or (better)  xref:refguide:applib-svc:InteractionContext.adoc[`InteractionContext`]instead.
-<5> The arguments being used to invoke the action; populated during validate phase and subsequent phases.
-<6> The value returned by the action; populated only in the executed phase.
-<7> Allows the subscriber to effectively change the value returned by the action; may only be called in the executed phase.
+<.> The `Noop` class is provided as a convenience to indicate that an event should _not_ be posted (irrespective of the configuration property setting).
+<.> Similarly, the `Doop` class is provided as a convenience to indicate that an event _should_ be raised (irrespective of the configuration property setting).
+<.> The arguments being used to invoke the action; populated during validate phase and subsequent phases.
+<.> The value returned by the action; populated only in the executed phase.
+<.> Allows the subscriber to effectively change the value returned by the action; may only be called in the executed phase.
diff --git a/api/applib/src/main/adoc/modules/applib-svc/images/reference-services/commands-and-events.png b/api/applib/src/main/adoc/modules/applib-svc/images/reference-services/commands-and-events.png
index efa501c..667be69 100644
Binary files a/api/applib/src/main/adoc/modules/applib-svc/images/reference-services/commands-and-events.png and b/api/applib/src/main/adoc/modules/applib-svc/images/reference-services/commands-and-events.png differ
diff --git a/api/applib/src/main/adoc/modules/applib-svc/images/reference-services/commands-and-events.pptx b/api/applib/src/main/adoc/modules/applib-svc/images/reference-services/commands-and-events.pptx
index 1a6f665..45d0a17 100644
Binary files a/api/applib/src/main/adoc/modules/applib-svc/images/reference-services/commands-and-events.pptx and b/api/applib/src/main/adoc/modules/applib-svc/images/reference-services/commands-and-events.pptx differ
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/CommandDtoProcessorService.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/CommandDtoProcessorService.adoc
index 0371d41..6bbeccd 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/CommandDtoProcessorService.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/CommandDtoProcessorService.adoc
@@ -23,7 +23,7 @@ The API defined by `CommandDtoProcessorService` is:
 
 [source,java]
 ----
-include::refguide:applib-svc:example$services/conmap/command/spi/CommandDtoProcessorService.java[tags="refguide"]
+include::refguide:applib-svc:example$services/commanddto/processor/spi/CommandDtoProcessorService.java[tags="refguide"]
 ----
 
 
@@ -40,7 +40,7 @@ The main use case is to allow certain actions to be ignored.
 
 [source,java]
 ----
-include::refguide:applib-svc:example$services/command/CommandDtoProcessor.java[tags="refguide"]
+include::refguide:applib-svc:example$services/commanddto/processor/CommandDtoProcessor.java[tags="refguide"]
 ----
 <.> Returning `null` means that the command's DTO is effectively ignored.
 
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/CommandExecutorService.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/CommandExecutorService.adoc
index 7215962..5ccb295 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/CommandExecutorService.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/CommandExecutorService.adoc
@@ -35,8 +35,8 @@ public interface CommandExecutorService {
 Behind the scenes this uses the xref:refguide:applib-svc:SudoService.adoc[`SudoService`].
 <.> provided `Command` must implement `CommandDto`.
 
-When the `Command` is executed, it will also be returned by xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`].
-Any associated objects that implement `HasUniqueId` (audit entries and the like) will therefore have the correct transactionId and will correctly be associated with the `Command` being executed.
+When the `Command` is executed, it can also be accessed from the `Interaction` obtained by  xref:refguide:applib-svc:InteractionContext.adoc[`InteractionContext`].
+Any associated objects that implement `HasUniqueId` (audit entries and the like) will therefore have the correct uniqueId and will correctly be associated with the `Command` being executed.
 
 == Implementation
 
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/CommandService.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/CommandService.adoc
index 2f97605..686609f 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/CommandService.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/CommandService.adoc
@@ -4,49 +4,5 @@
 :page-partial:
 
 
-CAUTION: TODO - v2 - to update, has been simplified.
-
-The `CommandService` service supports the xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`] service such that xref:refguide:applib-svc:CommandContext.adoc#command[`Command`] objects (that reify the invocation of an action/edit of a property on a domain object) can be persisted.
-
-``Command``s
-//also
-support the ability to replicate from a master to a slave instance of an application.
-One use case for this is for regression testing, allowing a production usages to be replayed against a new release candidate, eg after upgrading that application to a new version of Apache Isis itself (or some other dependency).
-
-There are a number of related use cases:
-
-* they enable profiling of the running application (which actions are invoked then most often, what is their response time)
-
-
-* if xref:refguide:applib-svc:PublisherService.adoc[`PublisherService`] is configured, they provide better traceability as the `Command` is also correlated with any published events, again through the unique `transactionId` GUID
-* if xref:refguide:applib-svc:AuditerService.adoc[`AuditerService`](s) are configured, they provide better audit information, since the `Command` (the 'cause' of an action) can be correlated to the audit records (the "effect" of the action) through the `transactionId` GUID
-
-== SPI
-
-The `CommandService` service defines the following very simple API:
-
-[source,java]
-----
-include::refguide:applib-svc:example$services/command/CommandService.java[tags="refguide"]
-----
-
-<.> Instantiate the appropriate instance of the xref:refguide:applib-svc:CommandContext.adoc#command[`Command`] (as defined by the
-xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`] service).
-Its members will be populated automatically by the framework.
-<.> Set the hint that the `Command` should be persisted if possible (when completed, see below).
-<.> "Complete" the command, typically meaning that the command should be persisted it if its `Command#getPersistence()` flag and persistence hint (`Command#isPersistHint()`) indicate that it should be.  +
-+ The framework will automatically have set the `completedAt` property of the `Command`.
-
-== Implementation
-
-The xref:extensions:command-log:about.adoc[Command Log] extension provides an implementation of this service that persists commands to a database table.
-
-== Related Services
-
-As discussed above, this service supports the xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`], providing the ability for `Command` objects to be persisted.
-
-The services provided by this module combines very well with the xref:refguide:applib-svc:AuditerService.adoc[`AuditerService`].
-The `CommandService` captures the __cause__ of an interaction (an action was invoked, a property was edited), while the `AuditerService` captures the __effect__ of that interaction in terms of changed state.
-You may also want to configure the xref:refguide:applib-svc:PublisherService.adoc[`PublisherService`], which also captures the effect of the interaction but as an event.
-All three of these services collaborate implicitly by way of the xref:applib-classes:roles-mixins-contributees/contributee.adoc#HasUniqueId[`HasUniqueId`] interface.
+The `CommandService` service is an internal service whose responsibility is simply to notify all known xref:CommandServiceListener.adoc[`CommandServiceListener`] when the `Command` has completed.
 
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/CommandServiceListener.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/CommandServiceListener.adoc
new file mode 100644
index 0000000..9831bcc
--- /dev/null
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/CommandServiceListener.adoc
@@ -0,0 +1,8 @@
+= `CommandServiceListener`
+
+:Notice: 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 ag [...]
+:page-partial:
+
+
+CAUTION: TODO - v2 - to update, has been simplified.
+
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/InteractionContext.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/InteractionContext.adoc
index c901741..2964a9b 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/InteractionContext.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/InteractionContext.adoc
@@ -3,8 +3,6 @@
 :Notice: 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 ag [...]
 :page-partial:
 
-WARNING: TODO: this content has not yet been reviewed/updated for v2.0
-
 
 The `InteractionContext` is a request-scoped domain service that is used to obtain the current
 `Interaction`.
@@ -29,6 +27,8 @@ The public API of the service consists of several related classes:
 
 * `InteractionContext` domain service itself:
 * `Interaction` class, obtainable from the `InteractionContext`
++
+The `Interaction` can be used to obtain the `Command` object representing the top-level invocation action/property edit.
 * `Execution` class, obtainable from the `Interaction`.
 
 The `Execution` class itself is abstract; there are two subclasses, `ActionInvocation` and `PropertyEdit`.
@@ -56,7 +56,6 @@ include::refguide:applib-svc:example$services/iactn/Interaction.java[tags="refgu
 <.> The unique identifier of this interaction.
 <.> Returns a (list of) execution}s in the order that they were pushed.
 Generally there will be just one entry in this list, but additional entries may arise from the use of mixins/contributions when re-rendering a modified object.
-This will be the same value as held in `Command` (obtainable from xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`]).
 <.> The current execution.
 <.> The member `Execution` (action invocation or property edit) that preceded the current one.
 <.> Generates numbers in a named sequence.
@@ -75,50 +74,42 @@ It has the following public API:
 [source,java]
 ----
 public abstract class Execution {
-    public Interaction getInteraction();            // <1>
-    public InteractionType getInteractionType();    // <2>
-    public String getMemberIdentifier();            // <3>
-    public Object getTarget();                      // <4>
+    public Interaction getInteraction();            // <.>
+    public InteractionType getInteractionType();    // <.>
+    public String getMemberIdentifier();            // <.>
+    public Object getTarget();                      // <.>
 
-    public String getTargetClass();                 // <5>
+    public String getTargetClass();                 // <.>
     public String getTargetMember();
 
-    public Execution getParent();                   // <6>
+    public Execution getParent();                   // <.>
     public List<Execution> getChildren();
 
-    public AbstractDomainEvent getEvent();          // <7>
+    public AbstractDomainEvent getEvent();          // <.>
 
-    public Timestamp getStartedAt();                // <8>
+    public Timestamp getStartedAt();                // <.>
     public Timestamp getCompletedAt();
 
-    public Object getReturned();                    // <9>
+    public Object getReturned();                    // <.>
     public Exception getThrew();
 
-    public T getDto();                              // <10>
+    public T getDto();                              // <.>
 }
 ----
-<1> The owning `Interaction`.
-<2> Whether this is an action invocation or a property edit.
-<3> A string uniquely identifying the action or property (similar to Javadoc syntax).
-<4> The object on which the action is being invoked or property edited.
+
+<.> The owning `Interaction`.
+<.> Whether this is an action invocation or a property edit.
+<.> A string uniquely identifying the action or property (similar to Javadoc syntax).
+<.> The object on which the action is being invoked or property edited.
 In the case of a mixin this will be the mixin object itself (rather than the mixed-in object).
-<5> A human-friendly description of the class of the target object, and of the name of the action invoked/property edited on the target object.
-<6> The parent action/property that invoked this action/property edit (if any), and any actions/property edits made in turn via the xref:refguide:applib-svc:WrapperFactory.adoc[`WrapperFactory`].
-<7> The domain event fired via the xref:refguide:applib-svc:EventBusService.adoc[`EventBusService`] representing the execution of this action invocation/property edit.
-<8> The date/time at which this execution started/completed.
-<9> The object returned by the action invocation/property edit, or the exception thrown.
+<.> A human-friendly description of the class of the target object, and of the name of the action invoked/property edited on the target object.
+<.> The parent action/property that invoked this action/property edit (if any), and any actions/property edits made in turn via the xref:refguide:applib-svc:WrapperFactory.adoc[`WrapperFactory`].
+<.> The domain event fired via the xref:refguide:applib-svc:EventBusService.adoc[`EventBusService`] representing the execution of this action invocation/property edit.
+<.> The date/time at which this execution started/completed.
+<.> The object returned by the action invocation/property edit, or the exception thrown.
 For `void` methods and for actions returning collections, the value will be `null`.
-<10> A DTO (instance of the xref:refguide:schema:ixn.adoc["ixn" schema]) being a serializable representation of this action invocation/property edit.
-
-[NOTE]
-====
+<.> A DTO (instance of the xref:refguide:schema:ixn.adoc["ixn" schema]) being a serializable representation of this action invocation/property edit.
 
-Unlike the similar xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`] domain service (discussed xref:refguide:applib-svc:InteractionContext.adoc#Related-Classes[below]) there is no domain service to different implementations of `Interaction` to be used.
-That said, the framework simply instantiates the `Interaction` using the
-xref:refguide:applib-svc:FactoryService.adoc[`FactoryService`].
-If a different implementation of `Interaction` was required, then a custom implementation of
-xref:refguide:applib-svc:FactoryService.adoc[`FactoryService`] could always be supplied.
-====
 
 There are two concrete subclasses of `Execution`.
 
@@ -155,14 +146,3 @@ The services are used within the framework however, primarily to support the
 xref:refguide:applib-svc:PublisherService.adoc[`PublisherService`] SPI, and to emit domain events over the
 xref:refguide:applib-svc:EventBusService.adoc[`EventBusService`].
 
-//== Related Classes
-//
-// TODO: CommandContext removed, instead just InteractionContext
-//
-//This service is very similar in nature to xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`], in that the `Interaction` object accessed through it is very similar to the `Command` object obtained from the `CommandContext`.
-//The principle distinction is that while `Command` represents the __intention__ to invoke an action or edit a property, the `Interaction` (and contained ``Execution``s) represents the actual execution.
-
-//Most of the time a `Command` will be followed directly by its corresponding `Interaction`.
-//However, if the `Command` is annotated to run in the background (using xref:refguide:applib-ant:Action.adoc#command[`@Action#commandExecuteIn()`], or is explicitly created through the xref:refguide:applib-svc:BackgroundService.adoc[`BackgroundService`], then the actual interaction/execution is deferred until some other mechanism invokes the command (eg as described xref:userguide:btb:about.adoc#BackgroundCommandExecution[here]).
-
-
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/about.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/about.adoc
index c226739..0c8e6b4 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/about.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/about.adoc
@@ -151,16 +151,12 @@ image::reference-services/commands-and-events.png[width="960px",link="{imagesdir
 
 To explain:
 
-* the (request-scoped) xref:refguide:applib-svc:CommandContext.adoc[`CommandContext`] captures the user's intention to invoke an action or edit a property; this is held by the `Command` object.
-
-* if a xref:refguide:applib-svc:CommandService.adoc[`CommandService`] has been configured, then this will be used to create the `Command` object implementation, generally so that it can then also be persisted.
-+
-If the action or property is annotated to be invoked in the background (using xref:refguide:applib-ant:Action.adoc#command[`@Action#command...()`] or xref:refguide:applib-ant:Property.adoc#command[`@Property#command...()`]) then no further work is done.
-But, if the action/property is to be executed in the foreground, then the interaction continues.
-
 * the (request-scoped) xref:refguide:applib-svc:InteractionContext.adoc[`InteractionContext`] domain service acts as a factory for the ``Interaction`` object, which keeps track of the call-graph of executions (``Interaction.Execution``) of either action invocations or property edits.
++
 In the majority of cases there is likely to be just a single top-level node of this graph, but for applications that use the xref:refguide:applib-svc:WrapperFactory.adoc[`WrapperFactory`] extensively each successive call results in a new child execution.
 
+* the `Interaction` also holds a reference to the `Command`, which represents the top-level intention to invoke the action / edit the property.
+
 * before and after each action invocation/property edit, a xref:applib-classes:events/domainevent.adoc[domain event] is may be broadcast to all subscribers.
 Whether this occurs depends on whether the action/property has been annotated (using xref:refguide:applib-ant:Action.adoc#domainEvent[`@Action#domainEvent()`] or xref:refguide:applib-ant:Property.adoc#domainEvent[`@Property#domainEvent()`]).
 +
@@ -185,6 +181,12 @@ Note that it's possible for there to be more than one transaction per top-level
 
 * Also at the end of each transaction, details of all changed properties are passed to any registered xref:refguide:applib-svc:AuditerService.adoc[`AuditerService`](s) by way of the (internal) xref:core:runtime-services:AuditerDispatchService.adoc[`AuditerDispatchService`] domain service.
 
+* At the end of the entire interaction footnote:[although rare, there can be multiple transactions in a single interaction], details of the top-level `Command` are sent to each xref:refguide:applib-svc:CommandServiceListener.adoc[`CommandServiceListener`].
+This captures whether the command succeeded or failed.
++
+The xref:extensions:command-log:about.adoc[Command Log] extension uses this to persist a log of commands, for auditing or to support regression testing with the xref:extensions:command-replay:about.adoc[Command Replay] extension.
+
+
 Implementations of xref:refguide:applib-svc:CommandService.adoc[`CommandService`] can use the `Command#getMemento()` method to obtain a XML equivalent of that `Command`, reified using the xref:refguide:schema:cmd.adoc[`cmd.xsd`] schema.
 This can be converted back into a `CommandDto` using the `CommandDtoUtils` utility class (part of the applib).
 
diff --git a/api/applib/src/main/adoc/modules/applib-svc/partials/_application-layer-api.adoc b/api/applib/src/main/adoc/modules/applib-svc/partials/_application-layer-api.adoc
index 3aa57a1..32e34e8 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/partials/_application-layer-api.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/partials/_application-layer-api.adoc
@@ -23,12 +23,6 @@ Domain service APIs for the application layer allow the domain objects to contro
 //NOTE: TODO: v2: this has been replaced by `WrapperFactory#async(...)`
 
 
-|xref:refguide:applib-svc:CommandContext.adoc[CommandContext]
-|Request-scoped access to capture the users's __intention__ to invoke an action or to edit a property.
-|
-* API is also the implementation (concrete class).
-
-
 |xref:refguide:applib-svc:CommandExecutorService.adoc[CommandExecutorService]
 |Executes the specified `Command`.
 |
diff --git a/api/applib/src/main/adoc/modules/applib-svc/partials/_integration-spi.adoc b/api/applib/src/main/adoc/modules/applib-svc/partials/_integration-spi.adoc
index 2d80a33..ad87561 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/partials/_integration-spi.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/partials/_integration-spi.adoc
@@ -26,7 +26,15 @@ TIP: see also the xref:mappings:ROOT:about.adoc[Bounded Context Mappings] catalo
 
 |xref:refguide:applib-svc:CommandExecutorService.adoc.adoc[CommandExecutorService]
 |Internal service used to execute commands.
-One use case is to replay commands on master/slave; another is in support of background commands.
+One use case is to replay commands from a primary onto a secondary (see xref:extensions:command-replay:about.adoc[Command Replay] ; another is in support of async commands (using
+xref:refguide:applib-svc:WrapperFactory.adoc[`WrapperFactory`] ).
+|
+* xref:core:runtime-services:about.adoc[Core Runtime Services]
+
+
+|xref:refguide:applib-svc:CommandServiceListener.adoc.adoc[CommandServiceListener]
+|SPI to allow commands to be processed on completion.
+The xref:extensions:command-log:about.adoc[Command Log] extension implements the SPI in order to persists commands for audit or replay.
 |
 * xref:core:runtime-services:about.adoc[Core Runtime Services]
 
diff --git a/api/applib/src/main/adoc/modules/applib-svc/partials/module-nav.adoc b/api/applib/src/main/adoc/modules/applib-svc/partials/module-nav.adoc
index f95b4fc..8cc26e4 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/partials/module-nav.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/partials/module-nav.adoc
@@ -9,10 +9,10 @@
 ** xref:refguide:applib-svc:BookmarkService.adoc[BookmarkService]
 ** xref:refguide:applib-svc:BookmarkUiService.adoc[BookmarkUiService]
 ** xref:refguide:applib-svc:ClockService.adoc[ClockService]
-** xref:refguide:applib-svc:CommandContext.adoc[CommandContext]
 ** xref:refguide:applib-svc:CommandDtoProcessorService.adoc[CommandDtoProcessorService]
 ** xref:refguide:applib-svc:CommandExecutorService.adoc[CommandExecutorService]
 ** xref:refguide:applib-svc:CommandService.adoc[CommandService]
+** xref:refguide:applib-svc:CommandServiceListener.adoc[CommandServiceListener]
 ** xref:refguide:applib-svc:ConfigurationMenu.adoc[ConfigurationMenu]
 ** xref:refguide:applib-svc:ConfigurationViewService.adoc[ConfigurationViewService]
 ** xref:refguide:applib-svc:ContentMappingService.adoc[ContentMappingService]
diff --git a/api/applib/src/main/java/org/apache/isis/applib/events/domain/ActionDomainEvent.java b/api/applib/src/main/java/org/apache/isis/applib/events/domain/ActionDomainEvent.java
index f891fe1..0fe46cb 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/events/domain/ActionDomainEvent.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/events/domain/ActionDomainEvent.java
@@ -67,28 +67,6 @@ public abstract class ActionDomainEvent<S> extends AbstractDomainEvent<S> {
     public ActionDomainEvent() {
     }
 
-    //    // -- command
-    //    private Command command;
-    //
-    //    /**
-    //     * @deprecated - use {@link CommandContext#getCommand()} to obtain the current {@link Command}.
-    //     */
-    //    @Deprecated
-    //    public Command getCommand() {
-    //        return command;
-    //    }
-    //
-    //    /**
-    //     * Not API - set by the framework.
-    //     *
-    //     * @deprecated - the corresponding {@link #getCommand()} should not be called, instead use {@link CommandContext#getCommand()} to obtain the current {@link Command}.
-    //     */
-    //    @Deprecated
-    //    public void setCommand(Command command) {
-    //        this.command = command;
-    //    }
-
-
     // tag::refguide[]
     @Getter
     private SemanticsOf semantics;
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/iactn/InteractionContext.java b/api/applib/src/main/java/org/apache/isis/applib/services/iactn/InteractionContext.java
index de41f1e..b6579ea 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/iactn/InteractionContext.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/iactn/InteractionContext.java
@@ -77,7 +77,6 @@ public class InteractionContext implements TransactionScopeListener, DisposableB
         this.interaction = interaction;
     }
 
-    // tag::refguide[]
 
     @Override
     public void onTransactionEnded() {
@@ -92,5 +91,7 @@ public class InteractionContext implements TransactionScopeListener, DisposableB
         setInteraction(null);
     }
 
+    // tag::refguide[]
+    // ...
 }
 // end::refguide[]