Execution Outbox
The Execution Outbox module provides an implementation of ExecutionSubscriber that persists Executions into an "outbox" (using either the JPA/EclipseLink or JDO/DataNucleus object store). The purpose of the "outbox" is to act as a temporary store of executions to be propogated to other "downstream" systems.
The module also provides a REST API, a rest client and DTOs to represent the payloads between these two services. The client polls the outbox through the REST API (for example every 15 seconds), and uses it to download any new executions. Once processed (eg published to a message bus), the client then uses the same REST API to delete the executions. The usage REST client is described below.
Setup
Dependency Management
Add a section for Execution Outbox's own BOM:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.causeway.extensions</groupId>
<artifactId>causeway-extensions-executionoutbox</artifactId>
<scope>import</scope>
<type>pom</type>
<version>2.1.0</version>
</dependency>
</dependencies>
</dependencyManagement>
Dependencies / Imports
In the webapp module of your application, add the following dependency:
<dependencies>
<dependency>
<groupId>org.apache.causeway.extensions</groupId>
<artifactId>causeway-extensions-executionoutbox-persistence-XXX</artifactId> (1)
</dependency>
</dependencies>
1 | either:
|
In your application’s App Manifest, import the ExecutionOutbox modules. The exact modules to use will depend upon the persistence mechanism in use:
@Configuration
@Import({
...
CausewayModuleExtExecutionOutboxPersistenceXxx.class, (1)
...
})
public class AppManifest {
}
1 | either:
|
Configuration Properties
Add the database schema used by the Execution Outbox entities to the configuration file:
causeway:
persistence:
schema:
auto-create-schemas: causewayExtExecutionOutbox
Optionally, modify the configuration properties for the Execution Outbox module itself:
causeway:
extensions:
execution-outbox:
rest-api:
max-pending: 100
Programmatic usage (queueing up commands)
With the extension configured, any action (or property edit) that has execution publishing enabled will result in an ExecutionOutboxEntry being persisted. The REST Client (described below) can then be set up to poll for and subsequent remove these entries.
Often the action in question should be a no-op; all that is required is create an ExecutionOutboxEntry
with the appropriate state.
This state will include a bookmark of the target object (on which the action was invoked) along with a serialization of the parameters.
There are two options when publishing an action:
-
make the event as "thin" as possible, ie inform the downstream systems that a significant event has occurred, but no more.
With this approach the downstream systems will probably make a RESTful API call to any additional information to perform their work
-
alternatively, provide supplemental information in the event, which may obviate the requirement for a REST call.
This can be done by defining action that has
String
parameters that take XML or JSON; these can therefore publish as much information as is necessary to the downstream systems.
For example:
-
define a no-op action taking XML parameters.
This should have publishing enabled, but we don’t want it visible in the UI so it should also be hidden:
@Action( semantics = SemanticsOf.IDEMPOTENT, publishing = Publishing.ENABLED, hidden = Where.EVERYWHERE ) public void addSupplier( final String addRequestXml, final String getRequestXml) { // no-op }
-
define a convenience method:
@Programmatic public T toOutbox() { return (T)wrapperFactory.wrapSkipRules(this); }
-
queue up commands, eg:
val addRequestXml = ...; val getRequestXml = ...; toOutbox().addSupplier(addRequestXml, getRequestXml);
User Interface
The extension provides a number of menu actions,that allow the administrator to query the persisted commands. These should be added to menu bar, and access to these restricted.
The sections below describe how.
menubar.layout.xml
Once configured, the extension provides a number of menu actions.
You can use menubars.layout.xml
to arrange these as you see fit.
To get you started, the following fragment adds all of the actions to an "Activity" secondary menu:
<mb:secondary>
...
<mb:menu>
<mb:named>Activity</mb:named>
...
<mb:section>
<mb:named>Execution Outbox</mb:named>
<mb:serviceAction id="findOldest" objectType="causeway.ext.executionOutbox.ExecutionOutboxMenu"/>
<mb:serviceAction id="findAll" objectType="causeway.ext.executionOutbox.ExecutionOutboxMenu"/>
</mb:section>
...
</mb:menu>
</mb:secondary>
SecMan Security Roles
If SecMan extension is configured, then permissions must be granted to access the menu actions.
This can be done by granting the role set up by the CausewayExtExecutionOutboxRoleAndPermissions seed fixture script (see its ROLE_NAME
constant).
Outbox REST Client
Once an execution has been persisted into the outbox, it will stay there until it has been processed and removed by another process. Typically that other process will be a microservice that forwards on the message to an event bus.
This is shown below.
The module provides a REST service, along with a rest client, OutboxClient.
The OutboxClient
is used by the message processor shown in the above diagram.
Prerequisites
To setup the message processor:
-
in
dependencyManagement
section, add an entry for Execution Outbox's own BOM:pom.xml<dependencyManagement> <dependencies> <dependency> <groupId>org.apache.causeway.extensions</groupId> <artifactId>causeway-extensions-executionoutbox</artifactId> <scope>import</scope> <type>pom</type> <version>2.1.0</version> </dependency> </dependencies> </dependencyManagement>
-
In the
dependencies
section, add the following dependency:pom.xml<dependencies> <dependency> <groupId>org.apache.causeway.extensions</groupId> <artifactId>causeway-extensions-executionoutbox-restclient</artifactId> </dependency> </dependencies>
Usage
To instantiate the OutboxClient
, specify the URL, user and password.
The URL will be something like: http://localhost:8080/restful/
, where the last part is the default path obtainable from the resteasy.jaxrs.defaultPath
configuration property of the Causeway app.
The OutboxClient
API consists of three methods:
-
to retrieve any pending interactions:
List<InteractionDto> pending = outboxClient.pending();
-
to delete a single interaction:
val first = pending.get(0); val interactionId = first.getInteractionId(); val sequence = first.getExecution().getSequence(); outboxClient.delete(interactionId, sequence);
-
to delete many interactions:
outboxClient.deleteMany(pending);
The maximum number of interactions that will be returned is configurable, see above.
See also
-
Execution Log extension