blob: 6588205ebbf72ed2829ce5cce77e59bc4ef9a2de [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Command Log :: causeway</title>
<link rel="canonical" href="https://causeway.apache.org/userguide/latest/commandlog/about.html">
<meta name="generator" content="Antora 3.1.1">
<link rel="stylesheet" href="../../../_/css/site.css">
<link rel="stylesheet" href="../../../_/css/site-custom.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,700,700i|Raleway:300,400,500,700,800|Montserrat:300,400,700" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.css"/>
<link rel="home" href="https://causeway.apache.org" title="causeway">
</head>
<body class="article">
<header class="header">
<nav class="navbar">
<div class="navbar-brand">
<a class="navbar-item" href="https://causeway.apache.org">
<span class="icon">
<img src="../../../_/img/causeway-logo-no-words-65x48.png"></img>
</span>
<span class="navbar-title">causeway</span>
</a>
<button class="navbar-burger" data-target="topbar-nav">
<span></span>
<span></span>
<span></span>
</button>
</div>
<div id="topbar-nav" class="navbar-menu">
<a class="navbar-end">
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" href="#">Quick Start</a>
<div class="navbar-dropdown">
<span class="navbar-item navbar-heading">Starter Apps</span>
<a class="navbar-item" href="../../../docs/latest/starters/helloworld.html">Hello World</a>
<a class="navbar-item" href="../../../docs/latest/starters/simpleapp.html">Simple App</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Learning &amp; Tutorials</span>
<a class="navbar-item" href="../../../docs/latest/reference/about.html">Reference App</a>
<a class="navbar-item" href="https://danhaywood.gitlab.io/isis-petclinic-tutorial-docs/petclinic/1.16.2/intro.html">Petclinic</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Resources</span>
<a class="navbar-item" href="../../../docs/latest/resources/cheatsheet.html">Cheatsheet</a>
<a class="navbar-item" href="../../../docs/latest/resources/icons.html">Icons</a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" href="#">Guides</a>
<div class="navbar-dropdown">
<span class="navbar-item navbar-heading">Core</span>
<a class="navbar-item" href="../../../userguide/latest/about.html">User Guide</a>
<a class="navbar-item" href="../../../refguide/latest/about.html">Reference Guide</a>
<a class="navbar-item" href="../../../testing/latest/about.html">Testing Guide</a>
<a class="navbar-item" href="../../../security/latest/about.html">Security Guide</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">For use in apps</span>
<a class="navbar-item" href="../../../valuetypes/latest/about.html">Value Types</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Development</span>
<a class="navbar-item" href="../../../setupguide/latest/about.html">Setup Guide</a>
<a class="navbar-item" href="../../../conguide/latest/about.html">Contributors' Guide</a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" href="#">Components</a>
<div class="navbar-dropdown">
<span class="navbar-item navbar-heading">Security</span>
<a class="navbar-item" href="../../../security/latest/bypass/about.html">Bypass</a>
<a class="navbar-item" href="../../../security/latest/simple/about.html">Simple</a>
<a class="navbar-item" href="../../../security/latest/shiro/about.html">Shiro</a>
<a class="navbar-item" href="../../../security/latest/spring/about.html">Spring</a>
<a class="navbar-item" href="../../../security/latest/keycloak/about.html">Keycloak</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Viewers</span>
<a class="navbar-item" href="../../../vw/latest/about.html">Web UI (Wicket)</a>
<a class="navbar-item" href="../../../gqlv/latest/about.html">GraphQL API</a>
<a class="navbar-item" href="../../../vro/latest/about.html">REST API (Restful Objects)</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Persistence</span>
<a class="navbar-item" href="../../../pjpa/latest/about.html">JPA (EclipseLink)</a>
<a class="navbar-item" href="../../../pjdo/latest/about.html">JDO (DataNucleus)</a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" href="#">Extensions</a>
<div class="navbar-dropdown">
<span class="navbar-item navbar-heading">Core</span>
<a class="navbar-item" href="../../../userguide/latest/commandlog/about.html">Command Log</a>
<a class="navbar-item" href="../../../userguide/latest/docgen/about.html">Doc Gen</a>
<a class="navbar-item" href="../../../userguide/latest/executionlog/about.html">Execution Log</a>
<a class="navbar-item" href="../../../userguide/latest/executionoutbox/about.html">Execution Outbox</a>
<a class="navbar-item" href="../../../userguide/latest/executionrepublisher/about.html">Execution Republisher</a>
<a class="navbar-item" href="../../../userguide/latest/excel/about.html">Excel</a>
<a class="navbar-item" href="../../../userguide/latest/flyway/about.html">Flyway</a>
<a class="navbar-item" href="../../../userguide/latest/layoutloaders/about.html">Layout Loaders</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Security</span>
<a class="navbar-item" href="../../../security/latest/secman/about.html">Secman</a>
<a class="navbar-item" href="../../../security/latest/audittrail/about.html">Audit Trail</a>
<a class="navbar-item" href="../../../security/latest/spring-oauth2/about.html">Spring OAuth2 Integration</a>
<a class="navbar-item" href="../../../security/latest/shiro-realm-ldap/about.html">LDAP Realm for Shiro</a>
<a class="navbar-item" href="../../../security/latest/sessionlog/about.html">Session Log</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Web UI (Wicket)</span>
<a class="navbar-item" href="../../../vw/latest/fullcalendar/about.html">Full Calendar</a>
<a class="navbar-item" href="../../../vw/latest/pdfjs/about.html">pdf.js</a>
<a class="navbar-item" href="../../../vw/latest/sse/about.html">Server Side Events</a>
<a class="navbar-item" href="../../../vw/latest/tabular/about.html">Tabular Download</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">REST API (Restful Objects)</span>
<a class="navbar-item" href="../../../vro/latest/cors/about.html">CORS</a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" href="#">Support</a>
<div class="navbar-dropdown">
<span class="navbar-item navbar-heading">Contact</span>
<a class="navbar-item" href="../../../docs/latest/support/slack-channel.html">Slack</a>
<a class="navbar-item" href="../../../docs/latest/support/mailing-list.html">Mailing Lists</a>
<a class="navbar-item" href="https://issues.apache.org/jira/browse/CAUSEWAY">JIRA</a>
<a class="navbar-item" href="https://stackoverflow.com/questions/tagged/causeway">Stack Overflow</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Releases</span>
<a class="navbar-item" href="../../../docs/latest/downloads/how-to.html">Downloads</a>
<a class="navbar-item" href="../../../relnotes/latest/about.html">Release Notes</a>
<hr class="navbar-divider"/>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" href="#">Framework</a>
<div class="navbar-dropdown">
<span class="navbar-item navbar-heading">Process</span>
<a class="navbar-item" href="../../../comguide/latest/about.html">Committers' Guide</a>
<a class="navbar-item" href="../../../tooling/latest/about.html">Tooling</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Automated Analysis</span>
<a class="navbar-item" href="https://sonarcloud.io/dashboard?id=apache_causeway">SonarCloud.io</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Interim Builds</span>
<a class="navbar-item" href="../../../comguide/latest/nightly-builds.html">Nightly builds</a>
<a class="navbar-item" href="../../../comguide/latest/weekly-builds.html">Weekly builds</a>
<a class="navbar-item" href="https://apache-causeway-committers.github.io/causeway-nightly">Website Preview (not ASF hosted)</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Development</span>
<a class="navbar-item" href="../../../core/latest/about.html">Internal Design Docs</a>
<a class="navbar-item" href="../../../regressiontests/latest/about.html">Regression Tests</a>
<a class="navbar-item" href="../../../incubator/latest/about.html">Incubator</a>
<hr class="navbar-divider"/>
<span class="navbar-item navbar-heading">Thanks</span>
<a class="navbar-item" href="../../../more-thanks/latest/more-thanks.html">Acknowledgements</a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" href="#">ASF</a>
<div class="navbar-dropdown">
<a class="navbar-item" href="http://www.apache.org/">Apache Homepage</a>
<a class="navbar-item" href="https://www.apache.org/events/current-event">Events</a>
<a class="navbar-item" href="https://www.apache.org/licenses/">License</a>
<a class="navbar-item" href="https://www.apache.org/security/">Security</a>
<a class="navbar-item" href="https://privacy.apache.org/policies/privacy-policy-public.html">Privacy</a>
<a class="navbar-item" href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a>
<a class="navbar-item" href="https://www.apache.org/foundation/thanks.html">Thanks</a>
<hr class="navbar-divider"/>
<a class="navbar-item" href="https://whimsy.apache.org/board/minutes/Causeway.html">PMC board minutes</a>
</div>
</div>
<a class="navbar-item" href="../../../docs/latest/about.html">
<span class="icon">
<img src="../../../_/img/home.png"></img>
</span>
</a>
</div>
</div>
</nav>
</header>
<div class="body ">
<div class="nav-container" data-component="userguide" data-version="2.0.0">
<aside class="nav">
<div class="panels">
<div class="nav-panel-search hide-for-print">
<input id="algolia-search-input" placeholder="Search"></span>
</div>
<div class="nav-panel-pagination">
<a class="page-previous disabled" rel="prev" href="" title=""><span></span></a>
<a class="page-next disabled" rel="next"
href="" title=""><span></span></a>
<!--
page.parent doesn't seem to be set...
<a class="page-parent disabled" rel="prev" href="" title=""><span></span></a>
-->
</div>
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<h3 class="title"><a href="../about.html">User Guide</a></h3>
<ul class="nav-list">
<li class="nav-item" data-depth="0">
<ul class="nav-list">
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../latest/overview.html">10,000ft overview</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../latest/domain-entities.html">Domain Entities</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../latest/domain-services.html">Domain Services</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../latest/properties-collections-actions.html">Properties, Collections &amp; Actions</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../latest/ui-layout-and-hints.html">UI Layout &amp; Hints</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../latest/business-rules.html">Business Rules</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../latest/drop-downs-and-defaults.html">Drop downs &amp; Defaults</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../latest/view-models.html">View Models</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../latest/mixins.html">Mixins</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../latest/events.html">Events</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../latest/modules.html">Modules</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../latest/value-types.html">Value types</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../latest/meta-annotations.html">Meta-annotations</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../latest/background-context-and-theory.html">Background, Context &amp; Theory</a>
</li>
<li class="nav-item" data-depth="1">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../latest/btb/about.html">Beyond the Basics</a>
<ul class="nav-list">
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../latest/btb/headless-access.html">Headless Access</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../latest/btb/programming-model.html">Programming Model</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../latest/btb/hints-and-tips.html">Hints-n-Tips</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../latest/btb/i18n.html">Internationalization (i18n)</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="1">
<button class="nav-item-toggle"></button>
<span class="nav-text">Extensions</span>
<ul class="nav-list">
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../latest/commandlog/about.html">Command Log</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../latest/docgen/about.html">DocGen</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../latest/executionlog/about.html">Execution Log</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../latest/executionoutbox/about.html">Execution Outbox</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../latest/executionrepublisher/about.html">Execution Republisher</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../latest/excel/about.html">Excel Library</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../latest/flyway/about.html">Flyway</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../latest/layoutloaders/about.html">Layout Loaders</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
</div>
<div class="nav-panel-explore" data-panel="explore">
<div class="context">
<span class="title">User Guide</span>
<span class="version">2.0.0</span>
</div>
<ul class="components">
<li class="component">
<span class="title"> </span>
<ul class="versions">
<li class="version">
<a href="../../../docs/latest/about.html">3.0.0</a>
</li>
<li class="version">
<a href="../../../docs/2.0.0/about.html">2.0.0</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Committers' Guide</span>
<ul class="versions">
<li class="version">
<a href="../../../comguide/latest/about.html">3.0.0</a>
</li>
<li class="version">
<a href="../../../comguide/2.0.0/about.html">2.0.0</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Contributors' Guide</span>
<ul class="versions">
<li class="version">
<a href="../../../conguide/latest/about.html">3.0.0</a>
</li>
<li class="version">
<a href="../../../conguide/2.0.0/about.html">2.0.0</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Design Docs</span>
<ul class="versions">
<li class="version">
<a href="../../../core/latest/about.html">3.0.0</a>
</li>
<li class="version">
<a href="../../../core/2.0.0/about.html">2.0.0</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Extensions</span>
<ul class="versions">
<li class="version">
<a href="../../../extensions/latest/about.html">3.0.0</a>
</li>
<li class="version">
<a href="../../../extensions/2.0.0/about.html">2.0.0</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">GraphQL Viewer</span>
<ul class="versions">
<li class="version">
<a href="../../../gqlv/latest/about.html">3.0.0</a>
</li>
<li class="version">
<a href="../../../gqlv/2.0.0/about.html">2.0.0</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Incubator Catalog</span>
<ul class="versions">
<li class="version">
<a href="../../../incubator/latest/about.html">3.0.0</a>
</li>
<li class="version">
<a href="../../../incubator/2.0.0/about.html">2.0.0</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">JDO/DataNucleus</span>
<ul class="versions">
<li class="version">
<a href="../../../pjdo/latest/about.html">3.0.0</a>
</li>
<li class="version">
<a href="../../../pjdo/2.0.0/about.html">2.0.0</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">JPA</span>
<ul class="versions">
<li class="version">
<a href="../../../pjpa/latest/about.html">3.0.0</a>
</li>
<li class="version">
<a href="../../../pjpa/2.0.0/about.html">2.0.0</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Reference Guide</span>
<ul class="versions">
<li class="version">
<a href="../../../refguide/latest/about.html">3.0.0</a>
</li>
<li class="version">
<a href="../../../refguide/2.0.0/about.html">2.0.0</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">regressiontests</span>
<ul class="versions">
<li class="version">
<a href="../../../regressiontests/latest/index.html">3.0.0</a>
</li>
<li class="version">
<a href="../../../regressiontests/2.0.0/index.html">2.0.0</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Release Notes</span>
<ul class="versions">
<li class="version">
<a href="../../../relnotes/latest/about.html">3.0.0</a>
</li>
<li class="version">
<a href="../../../relnotes/2.0.0/about.html">2.0.0</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">REST API (Restful Objects Viewer)</span>
<ul class="versions">
<li class="version">
<a href="../../../vro/latest/about.html">3.0.0</a>
</li>
<li class="version">
<a href="../../../vro/2.0.0/about.html">2.0.0</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Security Guide</span>
<ul class="versions">
<li class="version">
<a href="../../../security/latest/about.html">3.0.0</a>
</li>
<li class="version">
<a href="../../../security/2.0.0/about.html">2.0.0</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Setup Guide</span>
<ul class="versions">
<li class="version">
<a href="../../../setupguide/latest/about.html">3.0.0</a>
</li>
<li class="version">
<a href="../../../setupguide/2.0.0/about.html">2.0.0</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Testing Guide</span>
<ul class="versions">
<li class="version">
<a href="../../../testing/latest/about.html">3.0.0</a>
</li>
<li class="version">
<a href="../../../testing/2.0.0/about.html">2.0.0</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Tooling</span>
<ul class="versions">
<li class="version">
<a href="../../../tooling/latest/about.html">3.0.0</a>
</li>
<li class="version">
<a href="../../../tooling/2.0.0/about.html">2.0.0</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Tutorials</span>
<ul class="versions">
<li class="version">
<a href="../../../tutorials/latest/about.html">3.0.0</a>
</li>
<li class="version">
<a href="../../../tutorials/2.0.0/about.html">2.0.0</a>
</li>
</ul>
</li>
<li class="component is-current">
<span class="title">User Guide</span>
<ul class="versions">
<li class="version">
<a href="../../latest/about.html">3.0.0</a>
</li>
<li class="version is-current">
<a href="../about.html">2.0.0</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Value Types Catalog</span>
<ul class="versions">
<li class="version">
<a href="../../../valuetypes/latest/about.html">3.0.0</a>
</li>
<li class="version">
<a href="../../../valuetypes/2.0.0/about.html">2.0.0</a>
</li>
</ul>
</li>
<li class="component">
<span class="title">Web UI (Wicket Viewer)</span>
<ul class="versions">
<li class="version">
<a href="../../../vw/latest/about.html">3.0.0</a>
</li>
<li class="version">
<a href="../../../vw/2.0.0/about.html">2.0.0</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</aside>
</div>
<main role="main">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<a href="../../../docs/latest/about.html" class="home-link"></a>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li><a href="../about.html">User Guide</a></li>
<li><a href="about.html">Command Log</a></li>
</ul>
</nav>
<div class="page-versions">
<button class="version-menu-toggle" title="Show other versions of page">2.0.0</button>
<div class="version-menu">
<a class="version" href="../../latest/commandlog/about.html">3.0.0</a>
<a class="version is-current" href="about.html">2.0.0</a>
</div>
</div>
<div class="edit-this-page"><a href="https://github.com/apache/causeway/edit/2.0.0/extensions/core/commandlog/adoc/modules/commandlog/pages/about.adoc">Edit</a></div>
</div>
<article class="doc">
<a name="section-top"></a>
<h1 class="page">Command Log</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>The <em>Command Log</em> module provides an implementation of <a href="../../../refguide/latest/applib/index/services/publishing/spi/CommandSubscriber.html" class="xref page">CommandSubscriber</a> SPI that persists <a href="../../../refguide/latest/applib/index/services/command/Command.html" class="xref page">Command</a>s using either the <a href="../../../pjpa/latest/about.html" class="xref page">JPA/EclipseLink</a> or <a href="../../../pjdo/latest/about.html" class="xref page">JDO/DataNucleus</a> object store.</p>
</div>
<div class="paragraph">
<p>One use case is to combine with the <a href="../../../security/latest/audittrail/about.html" class="xref page">Audit Trail</a> extension.
The <em>Command Log</em> module logs the action invocations or property edits that the end-user makes, while the <em>audit trail</em> logs the resultant changes in state to domain objects.
The two logs are correlated using the <a href="../../../refguide/latest/applib/index/services/iactn/Interaction.html#getInteractionId_" class="xref page">interactionId</a> of the owning <a href="../../../refguide/latest/applib/index/services/iactn/Interaction.html" class="xref page">interaction</a>.</p>
</div>
<div class="paragraph">
<p>Another use case is to support (persisted) background commands, whereby actions are not invoked immediately but instead persisted and invoked by a background thread; this is described in the <a href="#background-commands">background commands</a> section below.</p>
</div>
<div class="paragraph">
<p>Sometimes the <a href="../executionlog/about.html" class="xref page">Execution Log</a> extension is also configured with or instead of this extension; see the <a href="#notes">notes</a> below to compare and contrast.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="setup"><a class="anchor" href="#setup"></a>Setup</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="dependency-management"><a class="anchor" href="#dependency-management"></a>Dependency Management</h3>
<div class="paragraph">
<p>Add an entry for the <em>Command Log</em> module&#8217;s own BOM:</p>
</div>
<div class="listingblock">
<div class="title">pom.xml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;dependencyManagement&gt;
&lt;dependencies&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.apache.causeway.extensions&lt;/groupId&gt;
&lt;artifactId&gt;causeway-extensions-commandlog&lt;/artifactId&gt;
&lt;scope&gt;import&lt;/scope&gt;
&lt;type&gt;pom&lt;/type&gt;
&lt;version&gt;2.0.0&lt;/version&gt;
&lt;/dependency&gt;
&lt;/dependencies&gt;
&lt;/dependencyManagement&gt;</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="dependencies"><a class="anchor" href="#dependencies"></a>Dependencies / Imports</h3>
<div class="paragraph">
<p>In the webapp module of your application, add the following dependency:</p>
</div>
<div class="listingblock">
<div class="title">pom.xml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;dependencies&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.apache.causeway.extensions&lt;/groupId&gt;
&lt;artifactId&gt;causeway-extensions-commandlog-persistence-XXX&lt;/artifactId&gt; <i class="conum" data-value="1"></i><b>(1)</b>
&lt;/dependency&gt;
&lt;/dependencies&gt;</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>either:
<div class="ulist">
<ul>
<li>
<p><code>causeway-extensions-commandlog-persistence-jpa</code> (<a href="../../../pjpa/latest/about.html" class="xref page">JPA/Eclipselink</a>), or</p>
</li>
<li>
<p><code>causeway-extensions-commandlog-persistence-jdo</code> (<a href="../../../pjdo/latest/about.html" class="xref page">JDO/DataNucleus</a>).</p>
</li>
</ul>
</div></td>
</tr>
</table>
</div>
<div class="paragraph">
<p>In your application&#8217;s <a href="../../latest/modules.html#appmanifest" class="xref page">App Manifest</a>, import the CommandLog modules.
The exact modules to use will depend upon the persistence mechanism in use:</p>
</div>
<div class="listingblock">
<div class="title">AppManifest.java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Configuration
@Import({
...
CausewayModuleExtCommandLogPersistenceXxx.class, <i class="conum" data-value="1"></i><b>(1)</b>
...
})
public class AppManifest {
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>either
<div class="ulist">
<ul>
<li>
<p><code>CausewayModuleExtCommandLogPersistenceJpa</code> (<a href="../../../pjpa/latest/about.html" class="xref page">JPA/Eclipselink</a>),or</p>
</li>
<li>
<p><code>CausewayModuleExtCommandLogPersistenceJdo</code>, (<a href="../../../pjdo/latest/about.html" class="xref page">JDO/DataNucleus</a>)</p>
</li>
</ul>
</div></td>
</tr>
</table>
</div>
<div class="paragraph">
<p>If using <a href="../../../security/latest/secman/about.html" class="xref page">SecMan</a>, you will also need to import the <a href="../../../testing/latest/fixtures/about.html" class="xref page">Fixture</a> module; SecMan uses fixture scripts to seed its entities.</p>
</div>
</div>
<div class="sect2">
<h3 id="configure-properties"><a class="anchor" href="#configure-properties"></a>Configuration Properties</h3>
<div class="paragraph">
<p>Add the database schema used by the <em>Command Log</em> entities to the configuration file:</p>
</div>
<div class="listingblock">
<div class="title">application.yml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-yaml hljs" data-lang="yaml">causeway:
persistence:
schema:
auto-create-schemas: causewayExtCommandLog</code></pre>
</div>
</div>
<div class="paragraph">
<p>Optionally, modify the configuration properties for the <em>Command Log</em> module itself:</p>
</div>
<div class="listingblock">
<div class="title">application.yml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-yaml hljs" data-lang="yaml">causeway:
extensions:
command-log:
publish-policy: "always" <i class="conum" data-value="1"></i><b>(1)</b></code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>the alternative is <code>"only-if-system-changed"</code>, which suppresses the persisting of `CommandLogEntry`s for commands where no other system state was changed (for example a finder action with safe semantics).
<div class="paragraph">
<p>See <a href="../../../refguide/latest/config/sections/causeway.extensions.html#causeway.extensions.command-log.publish-policy" class="xref page">causeway.extensions.command-log.publish-policy</a> configuration property for more details.</p>
</div></td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="menubar-layout-xml"><a class="anchor" href="#menubar-layout-xml"></a>menubar.layout.xml</h3>
<div class="paragraph">
<p>Once configured, the extension provides a number of menu actions.
You can use <code>menubars.layout.xml</code> to arrange these as you see fit.
To get you started, the following fragment adds all of the actions to an "Activity" secondary menu:</p>
</div>
<div class="listingblock">
<div class="title">menubars.layout.xml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;mb:secondary&gt;
...
&lt;mb:menu&gt;
&lt;mb:named&gt;Activity&lt;/mb:named&gt;
...
&lt;mb:section&gt;
&lt;mb:named&gt;Commands&lt;/mb:named&gt;
&lt;mb:serviceAction id="activeCommands" objectType="causeway.ext.commandLog.CommandLogMenu"/&gt;
&lt;mb:serviceAction id="findMostRecent" objectType="causeway.ext.commandLog.CommandLogMenu"/&gt;
&lt;mb:serviceAction id="findCommands" objectType="causeway.ext.commandLog.CommandLogMenu"/&gt;
&lt;mb:serviceAction id="findAll" objectType="causeway.ext.commandLog.CommandLogMenu"/&gt;
&lt;/mb:section&gt;
...
&lt;/mb:menu&gt;
&lt;/mb:secondary&gt;</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="secman-security-roles"><a class="anchor" href="#secman-security-roles"></a>SecMan Security Roles</h3>
<div class="paragraph">
<p>If <a href="../../../security/latest/secman/about.html" class="xref page">SecMan</a> extension is configured, then permissions must be granted to access the menu actions.</p>
</div>
<div class="paragraph">
<p>This can be done by granting the role set up by the <a href="../../../refguide/latest/extensions/index/secman/applib/role/seed/CausewayExtCommandLogRoleAndPermissions.html" class="xref page">CausewayExtCommandLogRoleAndPermissions</a> seed fixture script (see its <code>ROLE_NAME</code> constant).</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="user-interface"><a class="anchor" href="#user-interface"></a>User Interface</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The extension provides a number of menu actions and contributions.</p>
</div>
<div class="paragraph">
<p>The menu actions are as listed in <a href="#menubar-layout-xml">menubar.layout.xml</a>, above.
They allow the administrator to query the persisted commands.
Typically access to these actions would be restricted, see <a href="#secman-security-roles">security roles</a> above.</p>
</div>
<div class="paragraph">
<p>The extension also provides these mixins:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="../../../refguide/latest/extensions/index/commandlog/applib/contributions/Object_recentCommands.html" class="xref page">Object_recentCommands</a></p>
<div class="paragraph">
<p>This contributes a <code>recentCommands</code> collection to each and every domain object.</p>
</div>
<div class="paragraph">
<p>This can be explicit positioned through the domain class' own <a href="../../latest/ui-layout-and-hints.html#object-layout" class="xref page">layout file</a>, but this is generally not necessary: it will slot into the tab group in the layout file indicated for unreferenced collections using <code>&lt;tabGroup unreferencedCollections="true"&gt;</code>.</p>
</div>
</li>
<li>
<p><a href="../../../refguide/latest/extensions/index/commandlog/applib/contributions/HasUsername_recentCommandsByUser.html" class="xref page">HasUsername_recentCommandsByUser</a></p>
<div class="paragraph">
<p>This contributes the <code>recentCommandsByUser</code> collection to any domain object that implements the <a href="../../../refguide/latest/applib/index/mixins/security/HasUsername.html" class="xref page">HasUsername</a> interface.</p>
</div>
<div class="paragraph">
<p>Most notably, this is <a href="../../../security/latest/secman/about.html" class="xref page">SecMan</a> extension&#8217;s <a href="../../../refguide/latest/extensions/index/secman/applib/user/dom/ApplicationUser.html" class="xref page">ApplicationUser</a> entity that represents a logged-on user.
It is also supported by xref:security:sessionlog:about.adoc</p>
</div>
</li>
<li>
<p><a href="../../../refguide/latest/extensions/index/commandlog/applib/contributions/HasInteractionId_commandLogEntry.html" class="xref page">HasInteractionId_commandLogEntry</a></p>
<div class="paragraph">
<p>This contributes the <code>commandLogEntry</code> property to any object implementing <a href="../../../refguide/latest/applib/index/mixins/system/HasInteractionId.html" class="xref page">HasInteractionId</a> interface.
Typically these are the entities persisted by the <a href="../executionlog/about.html" class="xref page">Execution Log</a> or <a href="../../../security/latest/audittrail/about.html" class="xref page">Audit Trail</a> extensions, making it easy to traverse between these logs.</p>
</div>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="background-commands"><a class="anchor" href="#background-commands"></a>Background Commands</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Sometimes we might want to execute an action not immediately in the current users&#8217;s thread of control, but instead to perform it in the background; for example any long-running process.</p>
</div>
<div class="paragraph">
<p>One way to accomplish this is to use <a href="../../../refguide/latest/applib/index/services/wrapper/WrapperFactory.html#asyncWrap_T_AsyncControl" class="xref page">WrapperFactory#asyncWrap(&#8230;&#8203;)</a>, where the command is executed by another thread obtained from a thread pool (<code>ForkJoinPool.commonPool()</code>).
This works well, but has the slight risk that it is not transactionally safe - the async thread executes in its own interaction/transaction, and so might fail even though the initiating command succeeds; or vice versa.</p>
</div>
<div class="paragraph">
<p>An alternative approach is to use the <a href="../../../refguide/latest/extensions/index/commandlog/applib/dom/BackgroundService.html" class="xref page">BackgroundService</a>.
This persists the command as an <code>CommandLogEntry</code> instance, indicating that it is to be executed in the background.
Then, a separate thread - eg scheduling using Quartz - can pick up the queued <code>CommandLogEntry</code> and execute it.</p>
</div>
<div class="sect2">
<h3 id="submitting-actions"><a class="anchor" href="#submitting-actions"></a>Submitting Actions</h3>
<div class="paragraph">
<p>For example, suppose we have a long-running action to export all the invoices we have received from a supplier, perhaps to be sent to some other system.
Assuming that the <code>exportInvoices()</code> action is a regular action on the <code>Supplier</code> domain class, we would use:</p>
</div>
<div class="listingblock">
<div class="title">example usage of <code>BackgroundService</code> to invoke a regular action</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Action
public void exportInvoices(Supplier supplier) {
backgroundService.execute(supplier).exportInvoices();
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>If instead this functionality is implemented as a mixin, we would use something like:</p>
</div>
<div class="listingblock">
<div class="title">example usage of <code>BackgroundService</code> to invoke a mixin action:</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Action
public void exportInvoices(Supplier supplier) {
backgroundService.executeMixin(Supplier_exportInvoices.class, supplier).act();
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The action being invoked must be part of the Causeway metamodel, in other words it cannot be marked uses
<a href="../../../refguide/latest/applib/index/annotation/Programmatic.html" class="xref page">@Programmatic</a> or <a href="../../../refguide/latest/applib/index/annotation/Domain_Exclude.html" class="xref page">@Domain.Exclude</a>.</p>
</div>
<div class="paragraph">
<p>By default all the usual hide/disable/validate rules will be checked, but there are also methods to allow these rules to be skipped.</p>
</div>
<div class="paragraph">
<p>Behind the scenes this service uses <a href="../../../refguide/latest/applib/index/services/wrapper/WrapperFactory.html#asyncWrap_T_AsyncControl" class="xref page">WrapperFactory#asyncWrap(&#8230;&#8203;)</a> using <a href="../../../refguide/latest/applib/index/services/wrapper/control/AsyncControl.html#with_ExecutorService" class="xref page">AsyncControl#with(ExecutorService)</a> to pass an implementation of <code>ExecutorService</code> that persists the command as a <code>CommandLogEntry</code> instance.</p>
</div>
<div class="paragraph">
<p>If you require more fine-grained control, you can always just use the <a href="../../../refguide/latest/applib/index/services/wrapper/WrapperFactory.html" class="xref page">WrapperFactory</a> async method yourself.
The <code>ExecutorService</code> to use is <a href="../../../refguide/latest/extensions/index/commandlog/applib/dom/BackgroundService_PersistCommandExecutorService.html" class="xref page">BackgroundService.PersistCommandExecutorService</a>.
This is a Spring <code>@Service</code> and so can be obtained through injection.</p>
</div>
</div>
<div class="sect2">
<h3 id="executing-actions-using-the-quartz-scheduler"><a class="anchor" href="#executing-actions-using-the-quartz-scheduler"></a>Executing Actions using the Quartz scheduler</h3>
<div class="paragraph">
<p>Once a command has been persisted as a <code>CommandLogEntry</code>, we require some other process to actually execute the command.
The <em>Command Log</em> module includes the <code>RunBackgroundCommandsJob</code>, a <a href="https://www.quartz-scheduler.org/">Quartz</a> job that does exactly this.
Each time it is called it will query for any background commands that have not been started, and will execute each (using the <a href="../../../refguide/latest/applib/index/services/command/CommandExecutorService.html" class="xref page">CommandExecutorService</a>).</p>
</div>
<div class="paragraph">
<p>The job is marked as non re-entrant, so it doesn&#8217;t matter how often it is called; we recommend a 10 second delay usually works fine.</p>
</div>
<div class="paragraph">
<p>To configure Quartz, add the following to your <code>AppManifest</code>:</p>
</div>
<div class="listingblock">
<div class="title">AppManifest.java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public class AppManifest {
@Bean(name = "RunBackgroundCommandsJob") <i class="conum" data-value="1"></i><b>(1)</b>
public JobDetailFactoryBean jobDetail() {
val jobDetailFactory = new JobDetailFactoryBean();
jobDetailFactory.setJobClass(RunBackgroundCommandsJob.class);
jobDetailFactory.setDurability(true);
return jobDetailFactory;
}
@Bean
public SimpleTriggerFactoryBean trigger(
final @Qualifier("RunBackgroundCommandsJob") JobDetail job) { <i class="conum" data-value="1"></i><b>(1)</b>
val trigger = new SimpleTriggerFactoryBean();
trigger.setJobDetail(job);
trigger.setStartDelay(60_000); <i class="conum" data-value="2"></i><b>(2)</b>
trigger.setRepeatInterval(10_000); <i class="conum" data-value="3"></i><b>(3)</b>
trigger.setRepeatCount(REPEAT_INDEFINITELY);
return trigger;
}
// ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>name and qualify the job (so will not interfere with any other Quartz jobs you may have defined)</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>60 secs to wait for the app to be ready</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>check every 10 seconds</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="disabling-quartz"><a class="anchor" href="#disabling-quartz"></a>Disabling Quartz</h4>
<div class="paragraph">
<p>The <em>Command Log</em> module automatically references the <a href="https://www.quartz-scheduler.org/">Quartz</a> library.
If you don&#8217;t want to use this functionality and want to exclude quartz, then add an explicit dependency on the <em>Command Log</em> applib but exclude the quartz dependency within it:</p>
</div>
<div class="listingblock">
<div class="title">pom.xml</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;dependencies&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.apache.causeway.extensions&lt;/groupId&gt;
&lt;artifactId&gt;causeway-extensions-commandlog-applib&lt;/artifactId&gt;
&lt;exclusions&gt;
&lt;exclusion&gt;
&lt;groupId&gt;org.quartz-scheduler&lt;/groupId&gt; <i class="conum" data-value="1"></i><b>(1)</b>
&lt;artifactId&gt;quartz&lt;/artifactId&gt;
&lt;/exclusion&gt;
&lt;/exclusions&gt;
&lt;/dependency&gt;
&lt;/dependencies&gt;</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>exclude reference to quartz</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="notes"><a class="anchor" href="#notes"></a>Notes</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Conceptually a <strong>command</strong> represents the <em>intention</em> to execute an action or to edit a property ("before" the change), while an <strong>interaction execution</strong> represents the actual execution itself ("after" the change).</p>
</div>
<div class="paragraph">
<p>The <a href="../../../refguide/latest/applib/index/services/publishing/spi/CommandSubscriber.html" class="xref page">CommandSubscriber</a> SPI and <a href="../../../refguide/latest/applib/index/services/publishing/spi/ExecutionSubscriber.html" class="xref page">ExecutionSubscriber</a> SPI allow either to be subscribed to.
From an auditing perspective, their behaviour is quite similar:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>even though a command represents the <em>intention</em> to invoke an action, its <a href="../../../refguide/latest/applib/index/services/publishing/spi/CommandSubscriber.html" class="xref page">CommandSubscriber</a> SPI is only called once the action/property edit has been completed.</p>
</li>
<li>
<p>the <a href="../../../refguide/latest/applib/index/services/publishing/spi/ExecutionSubscriber.html" class="xref page">ExecutionSubscriber</a> is called as soon as the action has completed.
In most interactions there will only be a single action called within the interaction, hence these two subscribers will be called at almost the same time with very similar payloads.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>However, there can be some subtle differences:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>the <a href="../../../refguide/latest/applib/index/services/wrapper/WrapperFactory.html" class="xref page">WrapperFactory</a> service allows actions to be invoked "as if" through the user interface.
Therefore one action can execute another can execute another, creating a nested call graph of executions.</p>
<div class="paragraph">
<p>The <a href="../../../refguide/latest/applib/index/services/publishing/spi/ExecutionSubscriber.html" class="xref page">ExecutionSubscriber</a> is called after each and every execution as it completes, so will be called several times.</p>
</div>
</li>
<li>
<p>In contrast, the <a href="../../../refguide/latest/applib/index/services/publishing/spi/CommandSubscriber.html" class="xref page">CommandSubscriber</a> is called only once, for the top-level (outermost) action.</p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect1">
<h2 id="see-also"><a class="anchor" href="#see-also"></a>See also</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p><a href="../../../refguide/latest/applib/index/services/iactn/Interaction.html" class="xref page">interaction</a></p>
</li>
<li>
<p><a href="../../../refguide/latest/applib/index/services/iactnlayer/InteractionService.html" class="xref page">InteractionService</a>.</p>
</li>
<li>
<p><a href="../../../refguide/latest/applib/index/services/wrapper/WrapperFactory.html" class="xref page">WrapperFactory</a> service</p>
</li>
<li>
<p><a href="../../../refguide/latest/extensions/index/commandlog/applib/dom/BackgroundService.html" class="xref page">BackgroundService</a> service</p>
</li>
<li>
<p><a href="../../../refguide/latest/applib/index/services/publishing/spi/CommandSubscriber.html" class="xref page">CommandSubscriber</a> SPI</p>
</li>
<li>
<p><a href="../../../refguide/latest/applib/index/services/publishing/spi/ExecutionSubscriber.html" class="xref page">ExecutionSubscriber</a> SPI</p>
</li>
<li>
<p><a href="../executionlog/about.html" class="xref page">Execution Log</a> extension</p>
</li>
</ul>
</div>
</div>
</div>
</article>
<aside class="article-aside toc hide-for-print" role="navigation">
<p class="toc-title">On this page</p>
<div id="article-toc"></div>
</aside>
</main>
</div>
<footer class="footer">
<div class="content">
<div class="copyright">
<p>
Copyright © 2010~2023 The Apache Software Foundation, licensed under the Apache License, v2.0.
<br/>
Apache, the Apache feather logo, Apache Causeway, and the Apache Causeway project logo are all trademarks of The Apache Software Foundation.
</p>
</div>
<div class="revision">
<p>Revision: website.20240325-2342</p>
</div>
</div>
</footer>
<script src="../../../_/js/site.js"></script>
<script async src="../../../_/js/vendor/highlight.js"></script>
<script src="../../../_/js/vendor/jquery-3.4.1.min.js"></script>
<script src="../../../_/js/vendor/jquery-ui-1.12.1.custom.widget-only.min.js"></script>
<script src="../../../_/js/vendor/jquery.tocify.min.js"></script>
<script>
$(function() {
$("#article-toc").tocify( {
showEffect: "slideDown",
hashGenerator: "pretty",
hideEffect: "slideUp",
selectors: "h2, h3",
scrollTo: 120,
smoothScroll: true,
theme: "jqueryui",
highlightOnScroll: true
} );
});
</script>
<script src="https://cdn.jsdelivr.net/npm/docsearch.js@2/dist/cdn/docsearch.min.js"></script>
<script>
function focusSearchInput () { document.querySelector('#algolia-search-input').focus() }
var search = docsearch({
appId: '5ISP5TFAEN',
apiKey: '0fc51c28b4ad46e7318e96d4e97fab7c',
indexName: 'causeway-apache-org',
inputSelector: '#algolia-search-input',
autocompleteOptions: { hint: false, keyboardShortcuts: ['s'] },
debug: false,
}).autocomplete
search.on('autocomplete:closed', function () { search.autocomplete.setVal() })
focusSearchInput()
window.addEventListener('load', focusSearchInput);
</script>
<!--
docsearch options:
https://docsearch.algolia.com/docs/behavior/
-->
<!--
https://www.algolia.com/doc/api-reference/api-parameters/
algoliaOptions: { hitsPerPage: 6 },
-->
</body>
</html>