content/versions/1.12.2/guides/rgsvc.html (11,899 lines of code) (raw):
<!doctype html>
<html class="no-js" lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Domain Services</title>
<!--
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 agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<!-- No caching headers -->
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="expires" content="-1" />
<!-- TODO: need to (re)instate CDN in the future (not using for now just so can develop off-line -->
<link href="../css/foundation/5.5.1/foundation.css" rel="stylesheet" />
<script src="../js/foundation/5.5.1/vendor/modernizr.js"></script>
<link href="../css/asciidoctor/colony.css" rel="stylesheet">
<link href="../css/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet">
<link href="../css/github-fork-ribbon-css/0.1.1/gh-fork-ribbon.css" rel="stylesheet" />
<!--[if lt IE 9]>
<link href="../css/github-fork-ribbon-css/0.1.1/gh-fork-ribbon.ie.css" rel="stylesheet" />
<![endif]-->
<style type="text/css">
pre code {
background-color: inherit;
border-style: none;
}
pre code > span:first-child {
margin-left: -5px;
}
<style>
<!--
<style type="text/css">
/* Stylesheet for CodeRay to match GitHub theme | MIT License | http://foundation.zurb.com */
/*pre.CodeRay {background-color:#f7f7f8;}*/
.CodeRay .line-numbers{border-right:1px solid #d8d8d8;padding:0 0.5em 0 .25em}
.CodeRay span.line-numbers{display:inline-block;margin-right:.5em;color:rgba(0,0,0,.3)}
.CodeRay .line-numbers strong{color:rgba(0,0,0,.4)}
table.CodeRay{border-collapse:separate;border-spacing:0;margin-bottom:0;border:0;background:none}
table.CodeRay td{vertical-align: top;line-height:1.45}
table.CodeRay td.line-numbers{text-align:right}
table.CodeRay td.line-numbers>pre{padding:0;color:rgba(0,0,0,.3)}
table.CodeRay td.code{padding:0 0 0 .5em}
table.CodeRay td.code>pre{padding:0}
.CodeRay .debug{color:#fff !important;background:#000080 !important}
.CodeRay .annotation{color:#007}
.CodeRay .attribute-name{color:#000080}
.CodeRay .attribute-value{color:#700}
.CodeRay .binary{color:#509}
.CodeRay .comment{color:#998;font-style:italic}
.CodeRay .char{color:#04d}
.CodeRay .char .content{color:#04d}
.CodeRay .char .delimiter{color:#039}
.CodeRay .class{color:#458;font-weight:bold}
.CodeRay .complex{color:#a08}
.CodeRay .constant,.CodeRay .predefined-constant{color:#008080}
.CodeRay .color{color:#099}
.CodeRay .class-variable{color:#369}
.CodeRay .decorator{color:#b0b}
.CodeRay .definition{color:#099}
.CodeRay .delimiter{color:#000}
.CodeRay .doc{color:#970}
.CodeRay .doctype{color:#34b}
.CodeRay .doc-string{color:#d42}
.CodeRay .escape{color:#666}
.CodeRay .entity{color:#800}
.CodeRay .error{color:#808}
.CodeRay .exception{color:inherit}
.CodeRay .filename{color:#099}
.CodeRay .function{color:#900;font-weight:bold}
.CodeRay .global-variable{color:#008080}
.CodeRay .hex{color:#058}
.CodeRay .integer,.CodeRay .float{color:#099}
.CodeRay .include{color:#555}
.CodeRay .inline{color:#000}
.CodeRay .inline .inline{background:#ccc}
.CodeRay .inline .inline .inline{background:#bbb}
.CodeRay .inline .inline-delimiter{color:#d14}
.CodeRay .inline-delimiter{color:#d14}
.CodeRay .important{color:#555;font-weight:bold}
.CodeRay .interpreted{color:#b2b}
.CodeRay .instance-variable{color:#008080}
.CodeRay .label{color:#970}
.CodeRay .local-variable{color:#963}
.CodeRay .octal{color:#40e}
.CodeRay .predefined{color:#369}
.CodeRay .preprocessor{color:#579}
.CodeRay .pseudo-class{color:#555}
.CodeRay .directive{font-weight:bold}
.CodeRay .type{font-weight:bold}
.CodeRay .predefined-type{color:inherit}
.CodeRay .reserved,.CodeRay .keyword {color:#000;font-weight:bold}
.CodeRay .key{color:#808}
.CodeRay .key .delimiter{color:#606}
.CodeRay .key .char{color:#80f}
.CodeRay .value{color:#088}
.CodeRay .regexp .delimiter{color:#808}
.CodeRay .regexp .content{color:#808}
.CodeRay .regexp .modifier{color:#808}
.CodeRay .regexp .char{color:#d14}
.CodeRay .regexp .function{color:#404;font-weight:bold}
.CodeRay .string{color:#d20}
.CodeRay .string .string .string{background:#ffd0d0}
.CodeRay .string .content{color:#d14}
.CodeRay .string .char{color:#d14}
.CodeRay .string .delimiter{color:#d14}
.CodeRay .shell{color:#d14}
.CodeRay .shell .delimiter{color:#d14}
.CodeRay .symbol{color:#990073}
.CodeRay .symbol .content{color:#a60}
.CodeRay .symbol .delimiter{color:#630}
.CodeRay .tag{color:#008080}
.CodeRay .tag-special{color:#d70}
.CodeRay .variable{color:#036}
.CodeRay .insert{background:#afa}
.CodeRay .delete{background:#faa}
.CodeRay .change{color:#aaf;background:#007}
.CodeRay .head{color:#f8f;background:#505}
.CodeRay .insert .insert{color:#080}
.CodeRay .delete .delete{color:#800}
.CodeRay .change .change{color:#66f}
.CodeRay .head .head{color:#f4f}
pre.CodeRay code {
background-color: inherit;
border-style: none;
}
pre.CodeRay code > span:first-child {
margin-left: -5px;
}
.literalblock pre,
.listingblock pre:not(.highlight),
.listingblock pre[class="highlight"],
.listingblock pre[class^="highlight "],
.listingblock pre.CodeRay,
.listingblock pre.prettyprint {
background: rgb(253, 250, 246);
}
.sidebarblock .literalblock pre,
.sidebarblock .listingblock pre:not(.highlight),
.sidebarblock .listingblock pre[class="highlight"],
.sidebarblock .listingblock pre[class^="highlight "],
.sidebarblock .listingblock pre.CodeRay,
.sidebarblock .listingblock pre.prettyprint {
background: rgb(253, 250, 246);
}
<style>
-->
<style>
.github-fork-ribbon-wrapper.right {
position: fixed;
}
.github-fork-ribbon {
background: #090;
}
.github-fork-ribbon a:hover {
background:#0D0;
color:#fff;
font-size: 1.1em;
}
</style>
<style>
@media only screen and (min-width: 40.063em) {
.top-bar {
.contain-to-grid .top-bar {
max-width: 80rem;
}
}
}
.row {
max-width: 80rem;
}
</style>
<style>
.extended-quote,
.extended-quote-first {
margin-left: 40px;
margin-right: 40px;
font-style: italic;
}
.extended-quote-attribution {
text-align: right;
margin-right: 100px;
color: #10B061;
}
.extended-quote-first:before {
content: "\201c";
float: left;
font-size: 2.75em;
font-weight: bold;
line-height: 0.6em;
margin-left: -0.6em;
color: #003b6b;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
</style>
<style>
body {
position: relative;
}
*:not(pre) a > code {
color: #210DDC;
}
*:not(pre) > code {
background-color: inherit;
border: none;
font-weight: normal;
}
body div#toc li,
body div#toc2 li {
list-style-type: none;
}
div#doc-content {
margin-top: 30px;
}
div.documentation-page table.frame-all {
border-left: none;
border-right: none;
}
body div#toc li.active-region:before,
body div#toc2 li.active-region:before {
content: "\00BB \0020";
margin-left: -12px;
}
body div#toc li a.active,
body div#toc2 li a.active {
color: red;
}
body div#toc.toc,
body div#toc.toc2 {
position: fixed;
left: auto;
padding-top: 60px;
z-index: auto;
background-color: white;
border-left-color: #eee;
border-left-style: solid;
border-right: none;
min-height: 2000px;
}
</style>
<style>
@media only screen and (min-width: 768px) {
#toc.toc2 ul ul { margin-left: -10px; }
}
body div#toc .tocify-subheader ul {
margin-bottom: 0px;
}
body div#toc .tocify-subheader li {
font-size: 14px;
}
.tocify li.tocify-item, .tocify ul.tocify-item {
line-height: 24px;
}
body div#toc li.tocify-item.active:before,
body div#toc2 li.tocify-item.active:before {
content: "\00BB \0020";
margin-left: -12px;
}
body div#toc li.tocify-item.active a,
body div#toc2 li.tocify-item.active a {
color: red;
}
</style>
<style>
footer {
margin-top: 1000px;
}
</style>
<style>
/* overriding colony.css stylesheet */
.literalblock pre, .literalblock pre[class], .listingblock pre, .listingblock pre[class] {
/*padding: 1.25em 1.5625em 1.125em 1.5625em;*/
padding: 0.3em 0.6em 0.25em 0.6em;
}
@media only screen and (min-width: 1280px)
#toc.toc2 {
/*width: 20em;*/
width: 25em;
}
#doc-content a {
color: #210DDC;
}
.top-bar h1 {
border-bottom: inherit;
}
h2 {
margin-top: 80px;
}
h3 {
margin-top: 40px;
}
h4,h5 {
margin-top: 30px;
}
.admonitionblock.tip > table td.content {
color: #10B061;
}
.admonitionblock.note > table td.content {
color: #B509AB;
}
.admonitionblock.important > table td.content {
color: #D5810A;
}
.admonitionblock .title {
font-size: larger;
font-style: italic;
}
.imageblock img {
margin-bottom: 10px;
}
</style>
<style>
/* from http://ben.balter.com/2014/03/13/pages-anchor-links/ */
.header-link {
position: absolute;
left: -0.5em;
opacity: 0;
/*
-webkit-transition: opacity 0.2s ease-in-out 0.1s;
-moz-transition: opacity 0.2s ease-in-out 0.1s;
-ms-transition: opacity 0.2s ease-in-out 0.1s;
*/
}
h2:hover .header-link,
h3:hover .header-link,
h4:hover .header-link,
h5:hover .header-link,
h6:hover .header-link {
opacity: 1;
}
</style>
<style>
.top-bar
{
-webkit-transition-duration: .5s;
transition-duration: .5s;
-webkit-transition-timing-function: cubic-bezier( 0.215, 0.610, 0.355, 1.000 );
transition-timing-function: cubic-bezier( 0.215, 0.610, 0.355, 1.000 );
-webkit-transition-property: -webkit-transform;
transition-property: transform;
}
/*
http://osvaldas.info/auto-hide-sticky-header
MIT license
*/
.header--hidden
{
-webkit-transform: translateY( -100% );
-ms-transform: translateY( -100% );
transform: translateY( -100% );
transition-duration: .5s;
transition-timing-function: cubic-bezier( 0.215, 0.610, 0.355, 1.000 );
-webkit-transition-property: -webkit-transform;
transition-property: transform;
}
</style>
<style>
#doc-content a.guide {
color: white;
}
</style>
<style>
.tocify {
margin-top: 80px;
}
</style>
</script>
</head>
<body>
<<div class="github-fork-ribbon-wrapper right" style="position: fixed;">
<div class="github-fork-ribbon">
<a href="https://github.com/apache/isis#fork-destination-box">Fork me on GitHub</a>
</div>
</div>
<div class="row">
<div class="fixed contain-to-grid header">
<nav class="top-bar" data-topbar role="navigation" style="max-width: 80rem">
<ul class="title-area">
<li class="name">
<h1>
<a href="/index.html">Apache Isis™</a>
</h1>
</li>
<!-- Remove the class "menu-icon" to get rid of menu icon. Take out "Menu" to just have icon alone -->
<li class="toggle-topbar menu-icon"><a href="#"><span>Menu</span></a></li>
</ul>
<section class="top-bar-section">
<ul class="right">
<li class="has-form">
<FORM class="searchbox navbar-form navbar-right" id="searchbox_012614087480249044419:dn-q5gtwxya" action="http://www.google.com/cse">
<div class="row collapse">
<input type="hidden" name="cx" value="012614087480249044419:dn-q5gtwxya">
<INPUT type="hidden" name="cof" value="FORID:0">
<INPUT class="form-control" name="q" type="text" placeholder="Search">
</div>
</FORM>
</li>
</ul>
<!-- Left Nav Section -->
<ul class="left">
<li><a href="/documentation.html">Documentation</a></li>
<li><a href="/downloads.html">Downloads</a></li>
<li><a href="/help.html">Help</a></li>
<li><a href="/asf.html">@ASF</a></li>
</ul>
</section>
</nav>
</div>
</div>
<div class="row">
<div id="doc-content-left" class="large-9 medium-9 columns">
<div id="doc-content">
<div class="sect1">
<h2 id="_rgsvc">1. Domain Services</h2>
<div class="sectionbody">
<div class="paragraph">
<p>This guide documents Apache Isis' domain services, both those that act as an API (implemented by the framework for
your domain objects to call), and those domain services that act as an SPI (implemented by your domain application and
which are called by the framework).</p>
</div>
<div class="sect2">
<h3 id="_other_guides">1.1. Other Guides</h3>
<div class="paragraph">
<p>Apache Isis documentation is broken out into a number of user, reference and "supporting procedures" guides.</p>
</div>
<div class="paragraph">
<p>The user guides available are:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="ugfun.html">Fundamentals</a></p>
</li>
<li>
<p><a href="ugvw.html">Wicket viewer</a></p>
</li>
<li>
<p><a href="ugvro.html">Restful Objects viewer</a></p>
</li>
<li>
<p><a href="ugsec.html">Security</a></p>
</li>
<li>
<p><a href="ugtst.html">Testing</a></p>
</li>
<li>
<p><a href="ugbtb.html">Beyond the Basics</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The reference guides are:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="rgant.html">Annotations</a></p>
</li>
<li>
<p><a href="#">Domain Services</a> (this guide)</p>
</li>
<li>
<p><a href="rgcfg.html">Configuration Properties</a></p>
</li>
<li>
<p><a href="rgcms.html">Classes, Methods and Schema</a></p>
</li>
<li>
<p><a href="rgmvn.html">Apache Isis Maven plugin</a></p>
</li>
<li>
<p><a href="rgfis.html">Framework Internal Services</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The remaining guides are:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="dg.html">Developers' Guide</a> (how to set up a development environment
for Apache Isis and contribute back to the project)</p>
</li>
<li>
<p><a href="cgcom.html">Committers' Guide</a> (release procedures and related practices)</p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_rgsvc_intro">2. Introduction</h2>
<div class="sectionbody">
<div class="sect2">
<h3 id="_rgsvc_intro_types-of-domain-services">2.1. Types of Domain Service</h3>
<div class="paragraph">
<p>The domain services also group into various broad categories. Many support functionality of the various layers of the
system (presentation layer, application layer, core domain, persistence layer); others exist to allow the domain objects
to integrate with other bounded contexts, or provide various metadata (eg for development-time tooling). The diagram
below shows these categories:</p>
</div>
<div class="imageblock">
<div class="content">
<a class="image" href="images/reference-services/categories.png"><img src="images/reference-services/categories.png" alt="categories" width="600px"></a>
</div>
</div>
<div class="paragraph">
<p>A small number of domain services can be considered both API and SPI; a good example is the <a href="#_rgsvc_api_EmailService"><code>EmailService</code></a> that is of direct use for domain objects wishing to send out emails,
but is also used by the framework to support the <a href="ugvw.html#_ugvw_features_user-registration">user registration</a>
functionality supported by the <a href="ugvw.html">Wicket viewer</a>. The same is true of the <a href="#_rgsvc_api_EventBusService"><code>EventBusService</code></a>; this can be used by domain objects to broadcast arbitrary events,
but is also used by the framework to automatically emit events for
<a href="rgant.html#_rgant-Action_domainEvent"><code>@Action#domainEvent()</code></a> etc.</p>
</div>
<div class="paragraph">
<p>For these hybrid services we have categorized the service as an "API" service. This chapter therefore contains only
the strictly SPI services.</p>
</div>
<div class="paragraph">
<p>This rest of this guide is broken out into several chapters, one for each of the various types/categories of domain
service.</p>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_intro_public-api">2.2. Public API vs Internal Services</h3>
<div class="paragraph">
<p>The vast majority of Apache Isis' domain services are defined in Apache Isis' applib (<code>o.a.i.core:isis-core-applib</code>
module) as stable, public classes. Importantly, this also minimizes the coupling between your code and Apache Isis,
allowing you to easily mock out these services in your unit tests.</p>
</div>
<div class="paragraph">
<p>The framework also defines a number of "internal" services. These are not part of the framework’s formal API, in that
they use classes that are outside of the applib. These internal framework services should be thought of as part of the
internal design of the framework, and are liable to change from release to release. The internal framework services
are documented in the <a href="rgfis.html">Framework Internal Services</a> guide.</p>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_intro_using-the-services">2.3. Using the services</h3>
<div class="paragraph">
<p>Apache Isis includes an extensive number of domain services for your domain objects to use; simply define the service
as an annotated field and Apache Isis will inject the service into your object.</p>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">Customer</span> {
<span class="directive">public</span> <span class="type">void</span> sendEmail( <span class="predefined-type">String</span> subject, <span class="predefined-type">String</span> body) {
<span class="predefined-type">List</span><<span class="predefined-type">String</span>> cc = <span class="predefined-type">Collections</span>.emptyList;
<span class="predefined-type">List</span><<span class="predefined-type">String</span>> bcc = <span class="predefined-type">Collections</span>.emptyList;
emailService.send(getEmailAddress(), cc, bcc, subject, body);
}
<span class="directive">public</span> <span class="type">boolean</span> hideSendEmail() {
<span class="keyword">return</span> !emailService.isConfigured();
}
<span class="annotation">@Inject</span> <i class="conum" data-value="1"></i><b>(1)</b>
EmailService emailService;
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Service automatically injected by the framework.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>For objects that are already persisted, the service is automatically injected just after the object is rehydrated by
JDO/DataNucleus.</p>
</div>
<div class="paragraph">
<p>For transient objects (instantiated programmatically), the <a href="#_rgsvc_api_FactoryService"><code>FactoryService</code></a>'s
<code>instantiate()</code> method (or the deprecated <a href="#_rgsvc_api_DomainObjectContainer"><code>DomainObjectContainer</code></a>'s
<code>newTransientInstance()</code> method) will automatically inject the services.</p>
</div>
<div class="paragraph">
<p>Alternatively the object can be instantiated simply using <code>new</code>, then services injected using
<a href="#_rgsvc_api_ServiceRegistry"><code>ServiceRegistry</code></a>'s <code>injectServicesInto(…​)</code> method (or the deprecated
<a href="#_rgsvc_api_DomainObjectContainer"><code>DomainObjectContainer</code></a>'s <code>injectServicesInto(…​)</code> method).</p>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_intro_overriding-the-services">2.4. Overriding the services</h3>
<div class="paragraph">
<p>The framework provides default implementations for many of the domain services. This is convenient, but sometimes you
will want to replace the default implementation with your own service implementation.</p>
</div>
<div class="paragraph">
<p>The trick is to use the <a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a>
attribute, specifying a low number (typically <code>"1"</code>).</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>For a small number of domain services, all implementations are used (following the chain-of-responsibility pattern),
not just the first one. The services in question are:
<a href="#_rgsvc_spi_ContentMappingService"><code>ContentMappingService</code></a>,
<a href="#_rgsvc_spi_GridSystemService"><code>GridSystemService</code></a>, and
<a href="#_rgsvc_spi_RoutingService"><code>RoutingService</code></a>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>For example, suppose you wanted to provide your own implementation of
<a href="#_rgsvc_api_LocaleProvider"><code>LocaleProvider</code></a>. Here’s how:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>(
nature = NatureOfService.DOMAIN
)
<span class="annotation">@DomainServiceLayout</span>(
menuOrder = <span class="string"><span class="delimiter">"</span><span class="content">1</span><span class="delimiter">"</span></span> <i class="conum" data-value="1"></i><b>(1)</b>
)
<span class="directive">public</span> <span class="type">class</span> <span class="class">MyLocaleProvider</span> <span class="directive">implements</span> LocaleProvider {
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="predefined-type">Locale</span> getLocale() {
<span class="keyword">return</span> ...
}
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>takes precedence over the default implementation.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>It’s also quite common to want to decorate the existing implementation (ie have your own implementation delegate to the
default); this is also possible and quite easy (if using <code>1.10.0</code> or later). The idea is to have the framework
inject all implementations of the service, and then to delegate to the first one that isn’t "this" one:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>(nature=NatureOfService.DOMAIN)
<span class="annotation">@DomainServiceLayout</span>(
menuOrder = <span class="string"><span class="delimiter">"</span><span class="content">1</span><span class="delimiter">"</span></span> <i class="conum" data-value="1"></i><b>(1)</b>
)
<span class="directive">public</span> <span class="type">class</span> <span class="class">MyLocaleProvider</span> <span class="directive">implements</span> LocaleProvider {
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="predefined-type">Locale</span> getLocale() {
<span class="keyword">return</span> getDelegateLocaleProvider().getLocale(); <i class="conum" data-value="2"></i><b>(2)</b>
}
<span class="directive">private</span> LocaleProvider getDelegateLocaleProvider() {
<span class="keyword">return</span> Iterables.tryFind(localeProviders, input -> input != <span class="local-variable">this</span>).orNull(); <i class="conum" data-value="3"></i><b>(3)</b>
}
<span class="annotation">@Inject</span>
<span class="predefined-type">List</span><LocaleProvider> localeProviders; <i class="conum" data-value="4"></i><b>(4)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>takes precedence over the default implementation when injected elsewhere.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>this implementation merely delegates to the default implementation</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>find the first implementation that isn’t <em>this</em> implementation (else infinite loop!)</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>injects all implementations, including this implemenation</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The above code could be improved by caching the delegateLocaleProvider once located (rather than searching each time).</p>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_intro_commands-and-events">2.5. Command and Events (<code>1.13.0-SNAPSHOT</code>)</h3>
<div class="paragraph">
<p>A good number of the domain services manage the execution of action invocations/property edits, along with the state
of domain objects that are modified as a result of these. These services capture information which can then be used
for various purposes, most notably for auditing or for publishing events, or for deferring execution such that the
execution be performed in the background at some later date.</p>
</div>
<div class="paragraph">
<p>The diagram below shows how these services fit together. The outline boxes are services while the coloured boxes
represent data structures - defined in the applib and therefore accessible to domain applications - which hold various
information about the executions.</p>
</div>
<div class="imageblock">
<div class="content">
<a class="image" href="images/reference-services/commands-and-events.png"><img src="images/reference-services/commands-and-events.png" alt="commands and events" width="960px"></a>
</div>
</div>
<div class="paragraph">
<p>To explain:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>the (request-scoped) <a href="#_rgsvc_api_CommandContext"><code>CommandContext</code></a> captures the user’s intention to
invoke an action or edit a property; this is held by the <code>Command</code> object.</p>
</li>
<li>
<p>if a <a href="#_rgsvc_spi_CommandService"><code>CommandService</code></a> has been configured, then this will be used to
create the <code>Command</code> object implementation, generally so that it can then also be persisted.<br></p>
<div class="paragraph">
<p>If the action or property is annotated to be invoked in the background (using
<a href="rgant.html#_rgant-Action_command"><code>@Action#command…​()</code></a> or
<a href="rgant.html#_rgant-Property_command"><code>@Property#command…​()</code></a>) then no further work is done. But,
if the action/property is to be executed in the foreground, then the interaction continues.</p>
</div>
</li>
<li>
<p>the (request-scoped) <a href="#_rgsvc_api_InteractionContext"><code>InteractionContext</code></a> domain service acts as a
factory for the <code>Interaction</code> object, which keeps track of the call-graph of executions (<code>Interaction.Execution</code>)
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 <a href="#_rgsvc_api_WrapperFactory"><code>WrapperFactory</code></a>
extensively each successive call results in a new child execution.</p>
</li>
<li>
<p>before and after each action invocation/property edit, a <a href="rgcms.html#_rgcms_classes_domainevent">domain event</a> is
may be broadcast to all subscribers. Whether this occurs depends on whether the action/property has been annotated
(using <a href="rgant.html#_rgant-Action_domainEvent"><code>@Action#domainEvent()</code></a> or
<a href="rgant.html#_rgant-Property_domainEvent"><code>@Property#domainEvent()</code></a>).<br></p>
<div class="paragraph">
<p>(Note that susbcribers will also receive events for vetoing the action/property; this is not shown on the diagram).</p>
</div>
</li>
<li>
<p>As each execution progresses, and objects that are modified are "enlisted" into the (internal)
<a href="rgfis.html#_rgfis_spi_ChangedObjectsServiceInternal"><code>ChangedObjectsServiceInternal</code></a> domain service. Metrics as
to which objects are merely loaded into memory are also captured using the
<a href="#_rgsvc_api_MetricsService"><code>MetricsService</code></a> (not shown on the diagram).</p>
</li>
<li>
<p>At the end of each execution, details of that execution are published through the (internal)
<a href="rgfis.html#_rgfis_spi_PublisherServiceInternal"><code>PublisherServiceInternal</code></a> domain service. This is only done for
actions/properties annotated appropriate (with <a href="rgant.html#_rgant-Action_publishing"><code>@Action#publishing()</code></a> or
<a href="rgant.html#_rgant-Property_publishing"><code>@Property#publishing()</code></a>). <br></p>
<div class="paragraph">
<p>The internal service delegates in turn to any registered
<a href="#_rgsvc_spi_PublishingService"><code>PublishingService</code></a> (deprecated) and also to any
registered <a href="#_rgsvc_spi_PublisherService"><code>PublisherService</code></a>s (there may be more than one).</p>
</div>
</li>
<li>
<p>At the end of each transaction, details of all changed objects are published, again through the (internal)
<a href="rgfis.html#_rgfis_spi_PublisherServiceInternal"><code>PublisherServiceInternal</code></a> to any registered <code>PublishingService</code>
or <code>PublisherService</code> implementations. Only domain objects specified to be published with
<a href="rgant.html#_rgant-DomainObject_publishing"><code>@DomainObject#publishing()</code></a> are published.<br></p>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Note that it’s possible for there to be more than one transaction per top-level interaction, by virtue of the
<a href="#_rgsvc_api_TransactionService"><code>TransactionService</code></a>.</p>
</div>
</td>
</tr>
</table>
</div>
</li>
<li>
<p>Also at the end of each transaction, details of all changed properties are passed to any registered
<a href="#_rgsvc_spi_AuditingService"><code>AuditingService</code></a> or
<a href="#_rgsvc_spi_AuditerService"><code>AuditerService</code></a> (<code>1.13.0-SNAPSHOT</code>) by way of the (internal)
<a href="rgfis.html#_rgfis_spi_AuditingServiceInternal"><code>AuditingServiceInternal</code></a> domain service.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Implementations of <a href="#_rgsvc_spi_CommandService"><code>CommandService</code></a> can use the <code>Command#getMemento()</code>
method to obtain a XML equivalent of that <code>Command</code>, reified using the <a href="rgcms.html#_rgcms_schema-cmd"><code>cmd.xsd</code></a>
schema. This can be converted back into a <code>CommandDto</code> using the <code>CommandDtoUtils</code> utility class (part of the applib).</p>
</div>
<div class="paragraph">
<p>Similarly, implementations of <a href="#_rgsvc_spi_PublisherService"><code>PublisherService</code></a> can use the
<code>InteractionDtoUtils</code> utility class to obtain a <code>InteractionDto</code> representing the interaction, either just for a single
execution or for the entire call-graph. This can be converted into XML in a similar fashion.</p>
</div>
<div class="paragraph">
<p>Likewise, the <code>PublishedObjects</code> class passed to the <code>PublisherService</code> at the end of the interaction provides the
<code>PublishedObjects#getDto()</code> method which returns a <code>ChangesDto</code> instance. This can be converted into XML using the
<code>ChangesDtoUtils</code> utility class.</p>
</div>
<div class="paragraph">
<p>One final point: multiple <a href="#_rgsvc_spi_PublisherService"><code>PublisherService</code></a> implementations are supported
because different implementations may have different responsibilities. For example, the (non-ASF)
<a href="http://github.com/isisaddons/isis-module-publishmq">Isis addons' publishmq</a> module is responsible for publishing
messages onto an ActiveMQ event bus, for inter-system communication. However, the SPI can also be used for profiling;
each execution within the call-graph contains metrics of the number of objects loaded or modified as a result of that
execution, and thus could be used for application profiling. The framework provides a default
<code>PublisherServiceLogging</code> implementation that logs this using SLF4J.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_rgsvc_presentation-layer-spi">3. Presentation Layer SPI</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Domain service SPIs for the presentation layer influence how the Apache Isis viewers behave.</p>
</div>
<div class="paragraph">
<p>The table below summarizes the presentation layer SPIs defined by Apache Isis. It also lists their corresponding implementation, either a default implementation provided by Apache Isis itself, or provided by one of the in (non-ASF) <a href="http://www.isisaddons.org">Isis Addons</a> modules.</p>
</div>
<table class="tableblock frame-all grid-all spread">
<caption class="title">Table 1. Presentation Layer SPI</caption>
<colgroup>
<col style="width: 25%;">
<col style="width: 50%;">
<col style="width: 12.5%;">
<col style="width: 12.5%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">SPI</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Implementation</th>
<th class="tableblock halign-left valign-top">Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_ContentMappingService"><code>o.a.i.applb.</code><br>
<code>services.conmap</code><br>
<code>ContentMappingService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>(Attempt to) map the returned data into the representation required by the client’s HTTP <code>Accept</code> header.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Replaces (and simplifies) the earlier <code>ContentMappingService</code> that defined an SPI using classes internal to the
framework.<br>
+
No default implementation.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_EmailNotificationService"><code>o.a.i.applib.</code><br>
<code>services.userreg</code><br>
<code>EmailNotificationService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Notify a user during <a href="#_rgsvc_spi_UserRegistrationService">self-registration</a> of users.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>EmailNotificationService-</code><br>
<code>Default</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-runtime</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">depends on:<br>
a configured <code>EmailService</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_ErrorReportingService"><code>o.a.i.applib.</code><br>
<code>services.error</code><br>
<code>ErrorReportingService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Record details of an error occurring in the system (eg in an external incident recording system such as JIRA), and return a more friendly (jargon-free) message to display to the end user, with optional reference (eg <code>XXX-1234</code>).</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">(none)</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_ExceptionRecognizer"><code>o.a.i.applib.</code><br>
<code>services.exceprecog</code><br>
<code>ExceptionRecognizer2</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Convert certain exceptions (eg foreign or unique key violation in the database) into a format that can be rendered to the end-user.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>ExceptionRecognizer-</code><br>
<code>CompositeFor-</code><br>
<code>JdoObjectStore</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-applib</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Extensible using composite pattern if required</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_GridSystemService"><code>o.a.i.applib.</code><br>
<code>services.grid</code><br>
<code>GridSystemService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Validates and normalizes the grid layout for a domain class (with respect to a particular grid
system such as Bootstrap3), also providing a default grid (for those domain classes where there is no grid layout).</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>GridSystemServiceBS3</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-metamodel</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_GridLoaderService"><code>o.a.i.applib.</code><br>
<code>services.grid</code><br>
<code>GridLoaderService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Responsible for loading a grid layout for a domain class, eg from a <code>layout.xml</code> file.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>GridLoaderServiceDefault</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-metamodel</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_GridService"><code>o.a.i.applib.</code><br>
<code>services.grid</code><br>
<code>GridService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>A facade on top of both <a href="#_rgsvc_spi_GridLoaderService"><code>GridLoaderService</code></a> and
<a href="#_rgsvc_spi_GridSystemService"><code>GridSystemService</code></a>, thus being able to return normalized
grids for any domain class.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>GridServiceDefault</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-metamodel</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_HintStore"><code>o.a.i.applib.</code><br>
<code>services.hint</code><br>
<code>HintStore</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Stores UI hints on a per-object basis. For example, the viewer remembers which tabs are selected, and for collections which view is selected (eg table or hidden), which page of a table to render, or whether "show all" (rows) is toggled.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>HintStoreUsingWicketSession</code><br>
<code>o.a.i.viewer</code><br>
<code>isis-viewer-wicket-impl</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_LocaleProvider"><code>o.a.i.applib.</code><br>
<code>services.i18n</code><br>
<code>LocaleProvider</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Request-scoped service to return the locale of the current user, in support of i18n (ie so that the app’s UI, messages and exceptions can be translated to the required locale by the <a href="#_rgsvc_spi_TranslationService"><code>TranslationService</code></a>.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>LocaleProviderWicket</code><br>
<code>o.a.i.viewer</code><br>
<code>isis-viewer-wicket-impl</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_RoutingService"><code>o.a.i.applib.</code><br>
<code>services.routing</code><br>
<code>RoutingService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Return an alternative object than that returned by an action.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>RoutingServiceDefault</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-applib</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The default implementation will return the home page (per <a href="#_rgsvc_api_HomePageProviderService"><code>HomePageProviderService</code></a>) if a void or null is returned.<br>
Used by the <a href="ugvw.html">Wicket viewer</a> only.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_TranslationService"><code>o.a.i.applib.</code><br>
<code>services.i18n</code><br>
<code>TranslationService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Translate an app’s UI, messages and exceptions for the current user (as per the locale provided by <a href="#_rgsvc_spi_LocaleProvider"><code>LocalProvider</code></a>.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>TranslationServicePo</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-runtime</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">related services: <code>TranslationServicePoMenu</code><br>
depends on:<br>
<code>TranslationsResolver</code>, <code>LocaleProvider</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_TranslationsResolver"><code>o.a.i.applib.</code><br>
<code>services.i18n</code><br>
<code>TranslationsResolver</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Obtain translations for a particuar phrase and locale, in support of i18n (ie so that the app’s UI, messages and exceptions can be translated to the required locale by the <a href="#_rgsvc_spi_TranslationService"><code>TranslationService</code></a></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>TranslationsResolverWicket</code><br>
<code>o.a.i.viewer</code><br>
<code>isis-viewer-wicket-impl</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_UrlEncodingService"><code>o.a.i.applib.</code><br>
<code>services.urlencoding</code><br>
<code>UrlEncodingService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Converts strings into a form safe for use within a URL. Used to convert view models mementos into usable URL form.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>UrlEncodingService</code><br>
<code>UsingBaseEncoding</code><br>
<code>o.a.i.applib</code><br>
<code>isis-core-applib</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_UserProfileService"><code>o.a.i.applib.</code><br>
<code>services.userprof</code><br>
<code>UserProfileService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Obtain an alternative (usually enriched/customized) name for the current user, to render in the UI.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Key:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>o.a.i</code> is an abbreviation for <code>org.apache.isis</code></p>
</li>
<li>
<p><code>o.ia.m</code> is an abbreviation for <code>org.isisaddons.module</code></p>
</li>
<li>
<p><code>o.a.i.c.m.s</code> is an abbreviation for <code>org.apache.isis.core.metamodel.services</code></p>
</li>
<li>
<p><code>o.a.i.c.r.s</code> is an abbreviation for <code>org.apache.isis.core.runtime.services</code></p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_ContentMappingService">3.1. <code>ContentMappingService</code></h3>
<div class="paragraph">
<p>The <code>ContentMappingService</code> supports the (default implementation of the)
<a href="rgfis.html#_rgfis_spi_ContentNegotiationService"><code>ContentNegotiationService</code></a> allowing the
<a href="ugvro.html">RestfulObjects viewer</a> to allow domain objects to be transformed into some other format as specified
by the HTTP <code>Accept</code> header.</p>
</div>
<div class="paragraph">
<p>See <a href="rgfis.html#_rgfis_spi_ContentNegotiationService"><code>ContentNegotiationService</code></a> for further discussion.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Unlike most other domain services, the framework (that is, <code>ContentNegotiationService</code>) will check <em>all</em> available
implementations of <code>ContentMappingService</code> to convert the domain object to the requested media type, rather than merely
the first implementation found; in other words it uses the chain-of-responsibility pattern. Services are checked
in the ordering defined by <a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a>).
The mapped object used will be the first non-<code>null</code> result returned by an implementation.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_spi">3.1.1. SPI</h4>
<div class="paragraph">
<p>The SPI defined by this service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">ContentMappingService</span> {
<span class="predefined-type">Object</span> map(<span class="predefined-type">Object</span> object, <i class="conum" data-value="1"></i><b>(1)</b>
<span class="predefined-type">List</span><MediaType> acceptableMediaTypes); <i class="conum" data-value="2"></i><b>(2)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>typically the input is a domain object (whose structure might change over time), and the output is a DTO (whose structure is guaranteed to be preserved over time)</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>as per the caller’s HTTP <code>Accept</code> header</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>In versions prior to <code>v1.12.0</code>, this interface resided in a different package, internal to the
<a href="#ugvro.adoc">Restful Objects</a> viewer, and defined a slightly different signature that used an internal enum:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">ContentMappingService</span> {
<span class="predefined-type">Object</span> map(<span class="predefined-type">Object</span> object,
<span class="predefined-type">List</span><MediaType> acceptableMediaTypes,
RepresentationType representationType); <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>enum representing the requested representation; only ever take a value of <code>DOMAIN_OBJECT</code> or <code>ACTION_RESULT</code>.</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_implementations">3.1.2. Implementations</h4>
<div class="paragraph">
<p>No default implementations are provided by Apache Isis framework itself.</p>
</div>
<div class="paragraph">
<p>However, the (non-ASF) <a href="http://github.com/isisaddons/isis-app-todoapp">Isis addons' todoapp</a> includes a sample implementation to convert its <code>ToDoItem</code> entity into a (JAXB annotated) <code>ToDoItemDto</code>. The source code is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>(nature = NatureOfService.DOMAIN)
<span class="directive">public</span> <span class="type">class</span> <span class="class">ContentMappingServiceForToDoItem</span> <span class="directive">implements</span> ContentMappingService {
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="predefined-type">Object</span> map(
<span class="directive">final</span> <span class="predefined-type">Object</span> object,
<span class="directive">final</span> <span class="predefined-type">List</span><MediaType> acceptableMediaTypes) {
<span class="keyword">if</span>(object <span class="keyword">instanceof</span> ToDoItem) {
<span class="keyword">for</span> (MediaType acceptableMediaType : acceptableMediaTypes) {
<span class="directive">final</span> <span class="predefined-type">Map</span><<span class="predefined-type">String</span>, <span class="predefined-type">String</span>> parameters = acceptableMediaType.getParameters();
<span class="directive">final</span> <span class="predefined-type">String</span> className = parameters.get(<span class="string"><span class="delimiter">"</span><span class="content">x-ro-domain-type</span><span class="delimiter">"</span></span>);
<span class="keyword">if</span>(className.eqausl(ToDoItemV1_1.class.getName())) {
<span class="keyword">return</span> newToDoItemV1_1((ToDoItem) object);
}
}
}
<span class="keyword">return</span> <span class="predefined-constant">null</span>;
}
<span class="directive">private</span> ToDoItemV1_1 newToDoItemV1_1(<span class="directive">final</span> ToDoItem toDoItem) {
<span class="directive">final</span> ToDoItemV1_1 dto = <span class="keyword">new</span> ToDoItemV1_1();
dto.setToDoItem(toDoItem);
dto.setDescription(toDoItem.getDescription());
...
return dto;
}
...
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_related_services">3.1.3. Related Services</h4>
<div class="paragraph">
<p>This service is a companion to the default implementation of the <a href="rgfis.html#_rgfis_spi_ContentNegotiationService"><code>ContentNegotiationService</code></a>.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_EmailNotificationService">3.2. <code>EmailNotificationService</code></h3>
<div class="paragraph">
<p>The <code>EmailNotificationService</code> supports the <a href="ugvw.html#_ugvw_features_user-registration">user registration</a> (self sign-up) features of the <a href="ugvw.html">Wicket viewer</a> whereby a user can sign-up to access an application by providing a valid email address.</p>
</div>
<div class="paragraph">
<p>The Wicket viewer will check whether an implementation of this service (and also the <a href="#_rgsvc_spi_UserRegistrationService"><code>UserRegistrationService</code></a>) is available, and if so will (unless configured not to) expose a sign-up page where the user enters their email address. A verification email is sent using this service; the email includes a link back to the running application. The user then completes the registration process (choosing a user name, password and so on) and the Wicket viewer creates an account for them (using the aforementioned <code>UserRegistrationService</code>).</p>
</div>
<div class="paragraph">
<p>The role of this service in all of this is to format and send out emails for the initial registration, or for password resets.</p>
</div>
<div class="paragraph">
<p>The default implementation of this service uses the <a href="#_rgsvc_api_EmailService"><code>EmailService</code></a>, which must be configured in order for user registration to be enabled.</p>
</div>
<div class="sect3">
<h4 id="_spi_2">3.2.1. SPI</h4>
<div class="paragraph">
<p>The SPI defined by this service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">EmailNotificationService</span> <span class="directive">extends</span> <span class="predefined-type">Serializable</span> {
<span class="annotation">@Programmatic</span>
<span class="type">boolean</span> send(EmailRegistrationEvent ev); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="annotation">@Programmatic</span>
<span class="type">boolean</span> send(PasswordResetEvent ev); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="annotation">@Programmatic</span>
<span class="type">boolean</span> isConfigured(); <i class="conum" data-value="3"></i><b>(3)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>sends an email to verify an email address as part of the initial user registration</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>sends an email to reset a password for an already-registered user</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>determines whether the implementation was configured and initialized correctly</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>If <code>isConfigured()</code> returns false then it is <em>not</em> valid to call <code>send(…​)</code> (and doing so will result in an <code>IllegalStateException</code> being thrown.</p>
</div>
</div>
<div class="sect3">
<h4 id="_implementation">3.2.2. Implementation</h4>
<div class="paragraph">
<p>The framework provides a default implementation, <code>o.a.i.core.runtime.services.userreg.EmailNotificationServiceDefault</code>
that constructs the emails to send.</p>
</div>
<div class="sect4">
<h5 id="_alternative_implementations">Alternative Implementations</h5>
<div class="paragraph">
<p>The text of these email templates is hard-coded as resources, in other words baked into the core jar files. If you need to use different text then you can of course always write and register your own implementation to be used instead of Isis' default.</p>
</div>
<div class="paragraph">
<p>If you have configured an alternative email service implementation, it should process the message body as HTML.</p>
</div>
<div class="paragraph">
<p>If you wish to write an alternative implementation of this service, note that (unlike most Apache Isis domain services) the implementation is also instantiated and injected by Google Guice. This is because <code>EmailNotificationService</code> is used as part of the <a href="ugvw.html#_ugvw_features_user-registration">user registration</a> functionality and is used by Wicket pages that are accessed outside of the usual Apache Isis runtime.</p>
</div>
<div class="paragraph">
<p>This implies a couple of additional constraints:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>first, implementation class should also be annotated with <code>@com.google.inject.Singleton</code></p>
</li>
<li>
<p>second, there may not be any Apache Isis session running. (If necessary, one can be created on the fly using <code>IsisContext.doInSession(…​)</code>)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>To ensure that your alternative implementation takes the place of the default implementation, register it explicitly in <code>isis.properties</code>.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service">3.2.3. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' default
implementation of <code>EmailNotificationService</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_2">3.2.4. Related Services</h4>
<div class="paragraph">
<p>As noted elsewhere, the default implementation of this service uses <a href="#_rgsvc_api_EmailService"><code>EmailService</code></a>. This service has no specific configuration properties but does require that the <code>EmailService</code> has been configured.</p>
</div>
<div class="paragraph">
<p>Conversely, this service is used by (Isis' default implementation of) <a href="#_rgsvc_spi_UserRegistrationService"><code>UserRegistrationService</code></a>.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_ErrorReportingService">3.3. <code>ErrorReportingService</code></h3>
<div class="paragraph">
<p>The <code>ErrorReportingService</code> service is an optional SPI that providies the ability to record any errors/exceptions that
might occur in the application into an external incident recording system (such as JIRA). The service also allows
a user-friendly (jargon-free) error message to be returned and rendered to the end-user, along with an optional
incident reference (eg a JIRA issue <code>XXX-1234</code>).</p>
</div>
<div class="sect3">
<h4 id="_spi_3">3.3.1. SPI</h4>
<div class="paragraph">
<p>The SPI defined by this service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">ErrorReportingService</span> {
Ticket reportError(ErrorDetails errorDetails);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>where <code>ErrorDetails</code> provided to the service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">ErrorDetails</span> {
<span class="directive">public</span> <span class="predefined-type">String</span> getMainMessage() { ... } <i class="conum" data-value="1"></i><b>(1)</b>
<span class="directive">public</span> <span class="type">boolean</span> isRecognized() { ... } <i class="conum" data-value="2"></i><b>(2)</b>
<span class="directive">public</span> <span class="type">boolean</span> isAuthorizationCause() { ... } <i class="conum" data-value="3"></i><b>(3)</b>
<span class="directive">public</span> <span class="predefined-type">List</span><<span class="predefined-type">String</span>> getStackTraceDetailList() { <i class="conum" data-value="4"></i><b>(4)</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 main message to be displayed to the end-user. The service is responsible for translating this into the language of the end-user (it can use <a href="#_rgsvc_spi_LocaleProvider"><code>LocaleProvider</code></a> if required).</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>whether this message has already been recognized by an <a href="#_rgsvc_spi_ExceptionRecognizer"><code>ExceptionRecognizer</code></a> service. Generally this converts potentially non-recoverable (fatal) exceptions into recoverable exceptions (warnings) as well providing an alternative mechanism for generating user-friendly error messages.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>whether the cause of the exception was due to a lack of privileges. In such cases the UI restricts the information shown to the end-user, to avoid leaking potentially sensitive information</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>the stack trace of the exception, including the trace of any exceptions in the causal chain. These technical details are hidden from the user and only shown for non-recoverable exceptions.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>and <code>Ticket</code> (returned by the service) has the constructor:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">Ticket</span> <span class="directive">implements</span> <span class="predefined-type">Serializable</span> {
<span class="directive">public</span> Ticket(
<span class="directive">final</span> <span class="predefined-type">String</span> reference, <i class="conum" data-value="1"></i><b>(1)</b>
<span class="directive">final</span> <span class="predefined-type">String</span> userMessage, <i class="conum" data-value="2"></i><b>(2)</b>
<span class="directive">final</span> <span class="predefined-type">String</span> details) { ... } <i class="conum" data-value="3"></i><b>(3)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>is a unique identifier that the end-user can use to track any follow-up from this error. For example, an
implementation might automatically log an issue in a bug tracking system such as JIRA, in which case the reference would
probably be the JIRA issue number <tt>XXX-1234</tt>.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>a short, jargon-free message to display to the end-user.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>is optional additional details to show. For example, these might include text on how to recover from the error, or
workarounds, or just further details on contacting the help desk if the issue is severe and requires immediate
attention.</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_2">3.3.2. Implementation</h4>
<div class="paragraph">
<p>The (non-ASF) <a href="http://github.com/isisaddons/isis-app-kitchensink">Isis addons' kitchensink</a> app provides an example
implementation:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>( nature = NatureOfService.DOMAIN )
<span class="directive">public</span> <span class="type">class</span> <span class="class">KitchensinkErrorReportingService</span> <span class="directive">implements</span> ErrorReportingService {
<span class="directive">private</span> <span class="type">int</span> ticketNumber = <span class="integer">1</span>;
<span class="annotation">@Override</span>
<span class="directive">public</span> Ticket reportError(<span class="directive">final</span> ErrorDetails errorDetails) {
<span class="keyword">return</span> <span class="keyword">new</span> Ticket(
nextTicketReference(),
<span class="string"><span class="delimiter">"</span><span class="content">The Kitchen sink app is sorry to report that: </span><span class="delimiter">"</span></span> + errorDetails.getMainMessage(),
<span class="string"><span class="delimiter">"</span><span class="content">These are additional details for the end-user to read.</span><span class="char">\n</span><span class="delimiter">"</span></span>
+ <span class="string"><span class="delimiter">"</span><span class="content">This content should be able to span many lines.</span><span class="char">\n</span><span class="delimiter">"</span></span>
+ <span class="string"><span class="delimiter">"</span><span class="content">More detail.</span><span class="char">\n</span><span class="delimiter">"</span></span>
+ <span class="string"><span class="delimiter">"</span><span class="content">Some suggested work-arounds.</span><span class="char">\n</span><span class="delimiter">"</span></span>
+ <span class="string"><span class="delimiter">"</span><span class="content">Details of how to contact help desk.</span><span class="char">\n</span><span class="delimiter">"</span></span>
+ <span class="string"><span class="delimiter">"</span><span class="content">And so on</span><span class="delimiter">"</span></span>);
}
<span class="predefined-type">String</span> nextTicketReference() {
<span class="keyword">return</span> <span class="string"><span class="delimiter">"</span><span class="delimiter">"</span></span> + ticketNumber++;
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>which is rendered as:</p>
</div>
<div class="imageblock">
<div class="content">
<a class="image" href="images/reference-services-spi/ErrorReportingService/kitchensink-example.png"><img src="images/reference-services-spi/ErrorReportingService/kitchensink-example.png" alt="kitchensink example" width="860px"></a>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services">3.3.3. Registering the Services</h4>
<div class="paragraph">
<p>There is no default implementation of this service. To register your own implementation (and assuming that an
<code>AppManifest</code> is being used to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>), then just
ensure that the implementation is on the classpath and the module containing the implementation is returned in
<code>AppManifest#getModules()</code>.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_ExceptionRecognizer">3.4. <code>ExceptionRecognizer</code></h3>
<div class="paragraph">
<p>The <code>ExceptionRecognizer</code> service provides the mechanism for both the domain programmer and also for components to be able to recognize and handle certain exceptions that may be thrown by the system. Rather than display an obscure error to the end-user, the application can instead display a user-friendly message.</p>
</div>
<div class="paragraph">
<p>For example, the JDO/DataNucleus Objectstore provides a set of recognizers to recognize and handle SQL constraint exceptions such as uniqueness violations. These can then be rendered back to the user as expected errors, rather than fatal stacktraces.</p>
</div>
<div class="paragraph">
<p>It is also possible to provide additional implementations, registered in <code>isis.properties</code>. Unlike other services, where any service registered in <code>isis.properties</code> replaces any default implementations, in the case of this service all implementations registered are "consulted" to see if they recognize an exception (the chain-of-responsibility pattern).</p>
</div>
<div class="sect3">
<h4 id="_spi_4">3.4.1. SPI</h4>
<div class="paragraph">
<p>The SPI defined by this service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">ExceptionRecognizer2</span> ... {
<span class="directive">public</span> <span class="type">enum</span> Category { <i class="conum" data-value="1"></i><b>(1)</b>
...
}
<span class="directive">public</span> <span class="directive">static</span> <span class="type">class</span> <span class="class">Recognition</span> { <i class="conum" data-value="2"></i><b>(2)</b>
<span class="directive">private</span> Category category;
<span class="directive">private</span> <span class="predefined-type">String</span> reason;
...
}
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> Recognition recognize2(<span class="predefined-type">Throwable</span> ex); <i class="conum" data-value="3"></i><b>(3)</b>
<span class="annotation">@Deprecated</span>
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <span class="predefined-type">String</span> recognize(<span class="predefined-type">Throwable</span> ex); <i class="conum" data-value="4"></i><b>(4)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>an enumeration of varies categories of exceptions that are recognised</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>represents the fact that an exception has been recognized as has been converted into a user-friendy message, and has been categorized</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>the main API, to attempt to recognize an exception</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>deprecated API which converted exceptions into strings (reasons), ie without any categorization. This is no longer called.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The categories are:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">ExceptionRecognizer2</span> ... {
<span class="directive">public</span> <span class="type">enum</span> Category {
CONSTRAINT_VIOLATION, <i class="conum" data-value="1"></i><b>(1)</b>
NOT_FOUND, <i class="conum" data-value="2"></i><b>(2)</b>
CONCURRENCY, <i class="conum" data-value="3"></i><b>(3)</b>
CLIENT_ERROR, <i class="conum" data-value="4"></i><b>(4)</b>
SERVER_ERROR, <i class="conum" data-value="5"></i><b>(5)</b>
OTHER <i class="conum" data-value="6"></i><b>(6)</b>
}
...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>a violation of some declarative constraint (eg uniqueness or referential integrity) was detected.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>the object to be acted upon cannot be found (404)</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>a concurrency exception, in other words some other user has changed this object.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>recognized, but for some other reason…​ 40x error</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>50x error</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>recognized, but uncategorized (typically: a recognizer of the original <code>ExceptionRecognizer</code> API).</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>In essence, if an exception is recognized then it is also categorized. This lets the viewer act accordingly. For example, if an exception is raised from the loading of an individual object, then this is passed by the registered <code>ExceptionRecognizer</code>s. If any of these recognize the exception as representing a not-found exception, then an Apache Isis <code>ObjectNotFoundException</code> is raised. Both the viewers interprets this correctly (the <a href="ugvw.html">Wicket viewer</a> as a suitable error page, the <a href="ugvro.html">Restful Objects viewer</a> as a 404 status return code).</p>
</div>
<div class="paragraph">
<p>If the implementation recognizes the exception then it returns a user-friendly message to be rendered (by the viewer) back to the user; otherwise it returns <code>null</code>. There is no need for the implementation to check for exception causes; the casual chain is unwrapped by Apache Isis core and each exception in the chain will also be passed through to the recognizer (from most specific to least). The recognizer implementation can therefore be as fine-grained or as coarse-grained as it wishes.</p>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_3">3.4.2. Implementation</h4>
<div class="paragraph">
<p>The framework provides two default implementations:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>o.a.i.core.metamodel.services.container.DomainObjectContainerDefault</code> provided by Apache Isis core is itself an <code>ExceptionRecognizer</code>, and will handle <code>ConcurrencyException</code>s. It will also handle any application exceptions raised by the system (subclasses of <code>o.a.i.applib.RecoverableException</code>).</p>
</li>
<li>
<p><code>o.a.i.objectstore.jdo.applib.service.exceprecog.ExceptionRecognizerCompositeForJdoObjectStore</code> bundles up a number of more fine-grained implementations:</p>
<div class="ulist">
<ul>
<li>
<p><code>ExceptionRecognizerForSQLIntegrityConstraintViolationUniqueOrIndexException</code></p>
</li>
<li>
<p><code>ExceptionRecognizerForJDOObjectNotFoundException</code></p>
</li>
<li>
<p><code>ExceptionRecognizerForJDODataStoreException</code></p>
</li>
</ul>
</div>
</li>
</ul>
</div>
<div class="paragraph">
<p>If you want to recognize and handle additional exceptions (for example to capture error messages specific to the JDBC driver you might be using), then create a fine-grained implementation of <code>ExceptionRecognizer2</code> for the particular error message (there are some convenience implementations of the interface that you can subclass from if required) and register in <code>isis.properties</code>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_2">3.4.3. Registering the Services</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then the default
implementations provided by the framework (<code>DomainObjectContainerDefault</code> and
<code>ExceptionRecognizerCompositeForJdoObjectStore</code>) will be registered.</p>
</div>
<div class="paragraph">
<p>In addition, you can register any further exception recognizers in <code>isis.properties</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="ini">isis.services=...,\
com.mycompany.myapp.MyExceptionRecognizer,\
...</code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Prior to 1.9.0, the <code>ExceptionRecognizerCompositeForJdoObjectStore</code> also required manual registration.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>If the JDO exception recognizers are not required (rather unlikely), then they can be disabled en-masse using the <a href="rgcfg.html#_rgcfg_configuring-core">configuration property</a> <code>isis.services.ExceptionRecognizerCompositeForJdoObjectStore.disable</code>.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_GridSystemService">3.5. <code>GridSystemService</code></h3>
<div class="paragraph">
<p>The <code>GridSystemService</code> encapsulates a single layout grid system which can be used to customize the layout
of domain objects. In particular this means being able to return a "normalized" form (validating and associating
domain object members into the various regions of the grid) and in providing a default grid if there is no other
metadata available.</p>
</div>
<div class="paragraph">
<p>The framework provides a single such grid implementation, namely for Bootstrap3.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Unlike most other domain services, the framework will check <em>all</em> available implementations of <code>GridSystemService</code> to
obtain available grid systems, rather than merely the first implementation found; in other words it uses the
chain-of-responsibility pattern. Services are called in the order defined by
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a>).</p>
</div>
<div class="paragraph">
<p>Note though that each concrete implementation must also provide corresponding Wicket viewer components capable of
interpreting the grid layout.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_spi_5">3.5.1. SPI</h4>
<div class="paragraph">
<p>The SPI defined by this service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">GridSystemService</span><G <span class="directive">extends</span> Grid> {
<span class="predefined-type">Class</span><? <span class="directive">extends</span> Grid> gridImplementation(); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="predefined-type">String</span> tns(); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="predefined-type">String</span> schemaLocation(); <i class="conum" data-value="3"></i><b>(3)</b>
Grid defaultGrid(<span class="predefined-type">Class</span><?> domainClass); <i class="conum" data-value="4"></i><b>(4)</b>
<span class="type">void</span> normalize(G grid, <span class="predefined-type">Class</span><?> domainClass); <i class="conum" data-value="5"></i><b>(5)</b>
<span class="type">void</span> complete(G grid, <span class="predefined-type">Class</span><?> domainClass); <i class="conum" data-value="6"></i><b>(6)</b>
<span class="type">void</span> minimal(G grid, <span class="predefined-type">Class</span><?> domainClass); <i class="conum" data-value="7"></i><b>(7)</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 concrete subclass of <code>Grid</code> supported by this implementation. As noted in the introduction, there can be multiple implementations of this service, but there can only be one implementation per concrete subclass. As is normal practice,
the service with the lowest <a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> takes precedence.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>the target namespace for this grid system. This is used when generating the XML. The Bootstrap3 grid system provided by the framework returns the value <code><a href="http://isis.apache.org/applib/layout/grid/bootstrap3" class="bare">http://isis.apache.org/applib/layout/grid/bootstrap3</a></code>.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>the schema location for the XSD. The Bootstrap3 grid system provided by the framework returns the value <code><a href="http://isis.apache.org/applib/layout/grid/bootstrap3/bootstrap3.xsd" class="bare">http://isis.apache.org/applib/layout/grid/bootstrap3/bootstrap3.xsd</a></code>.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>a default grid, eg two columns in ratio 4:8. Used when no existing grid layout exists for a domain class.</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>Validates and normalizes a grid, modifying the grid so that all of the domain object’s members (properties, collections, actions) are bound to regions of the grid. This is done using existing metadata, most notably that of the <a href="rgant.html#_rgant-MemberOrder"><code>@MemberOrder</code></a> annotation. Such a grid, if persisted as the layout XML file for the domain class, allows the
<code>@MemberOrder</code> annotation to be removed from the source code of the domain class (but other annotations must be retained).</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>Takes a normalized grid and enriches it with additional metadata (taken from Apache Isis' internal metadata) that can be represented in the layout XML. Such a grid, if persisted as the layout XML file for the domain class, allows all layout annotations (<a href="rgant.html#_rgant-ActionLayout"><code>@ActionLayout</code></a>, <a href="rgant.html#_rgant-PropertyLayout"><code>@PropertyLayout</code></a> and <a href="rgant.html#_rgant-CollectionLayout"><code>@CollectionLayout</code></a>) to be removed from the source code of the domain class.</td>
</tr>
<tr>
<td><i class="conum" data-value="7"></i><b>7</b></td>
<td>Takes a normalized grid and strips out removes all members, leaving only the grid structure. Such a grid, if persisted as the layout XML file for the domain class, requires that the <a href="rgant.html#_rgant-MemberOrder"><code>@MemberOrder</code></a> annotation is retained in the source code of said class in order to bind members to the regions of the grid.</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_4">3.5.2. Implementation</h4>
<div class="paragraph">
<p>The framework provides <code>GridSystemServiceBS3</code>, an implementation that encodes the bootstrap3 grid system. (The framework
also provides <a href="#ugvw.adoc">Wicket viewer</a> components that are capable of interpreting and rendering this metadata).</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_3">3.5.3. Registering the Services</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>), then the
Bootstrap3 default implementation of <code>GridSystemService</code> is automatically registered and injected, and no further
configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_3">3.5.4. Related Services</h4>
<div class="paragraph">
<p>This service is used by <a href="#_rgsvc_spi_GridService"><code>GridService</code></a>.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_GridLoaderService">3.6. <code>GridLoaderService</code></h3>
<div class="paragraph">
<p>The <code>GridLoaderService</code> provides the ability to load the XML layout (grid) for a domain class.</p>
</div>
<div class="sect3">
<h4 id="_spi_6">3.6.1. SPI</h4>
<div class="paragraph">
<p>The SPI defined by this service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">GridLoaderService</span> {
<span class="type">boolean</span> supportsReloading(); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="type">void</span> remove(<span class="predefined-type">Class</span><?> domainClass); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="type">boolean</span> existsFor(<span class="predefined-type">Class</span><?> domainClass); <i class="conum" data-value="3"></i><b>(3)</b>
Grid load(<span class="directive">final</span> <span class="predefined-type">Class</span><?> domainClass); <i class="conum" data-value="4"></i><b>(4)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>whether dynamic reloading of layouts is enabled. The default implementation enables reloading for prototyping, disables in production</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>support metamodel invalidation/rebuilding of spec, eg as called by this <a href="rgcms.html#_rgcms_classes_mixins_Object_rebuildMetamodel">Object mixin</a> action.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>whether any persisted layout metadata (eg a <code>.layout.xml</code> file) exists for this domain class.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>returns a new instance of a <a href="rgcms.html#_rgcms_classes_layout_component"><code>Grid</code></a> for the specified domain class, eg as loaded from a <code>layout.xml</code> file. If none exists, will return null (and the calling <a href="#_rgsvc_spi_GridService"><code>GridService</code></a> will use <a href="#_rgsvc_spi_GridSystemService"><code>GridSystemService</code></a> to obtain a default grid for the domain class).</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_5">3.6.2. Implementation</h4>
<div class="paragraph">
<p>The framework provides a default implementation of this service, namely <code>GridLoaderServiceDefault</code>. This implementation
loads the grid from its serialized representation as a <code>.layout.xml</code> file, loaded from the classpath.</p>
</div>
<div class="paragraph">
<p>For example, the layout for a domain class <code>com.mycompany.myapp.Customer</code> would be loaded from <code>com/mycompany/myapp/Customer.layout.xml</code>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_4">3.6.3. Registering the Services</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>), then the
default implementation of <code>GridLoaderService</code> is automatically registered and injected, and no further
configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_4">3.6.4. Related Services</h4>
<div class="paragraph">
<p>This service is used by <a href="#_rgsvc_spi_GridService"><code>GridService</code></a>.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_GridService">3.7. <code>GridService</code></h3>
<div class="paragraph">
<p>The <code>GridService</code> provides the ability to load the XML layout (grid) for a domain class. To do this it delegates:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>to <a href="#_rgsvc_spi_GridLoaderService"><code>GridLoaderService</code></a> to load a pre-existing layout for the domain class, if possible</p>
</li>
<li>
<p>to <a href="#_rgsvc_spi_GridSystemService"><code>GridSystemService</code></a> to normalize the grid with respect to Apache
Isis' internal metamodel, in other words to ensure that all of the domain objects' properties, collections and actions are associated with regions of the grid.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Once a grid has been loaded for a domain class, this is cached internally by Apache Isis' internal meta model (in the
<code>GridFacet</code> facet). If running in prototype mode, any subsequent changes to the XML will be detected and the grid rebuilt. This allows for dynamic reloading of layouts, providing a far faster feedback (eg if tweaking the UI while working with end-users). Dynamic reloading is disabled in production mode.</p>
</div>
<div class="sect3">
<h4 id="_spi_7">3.7.1. SPI</h4>
<div class="paragraph">
<p>The SPI defined by this service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">GridService</span> {
<span class="type">boolean</span> supportsReloading(); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="type">void</span> remove(<span class="predefined-type">Class</span><?> domainClass); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="type">boolean</span> existsFor(<span class="predefined-type">Class</span><?> domainClass); <i class="conum" data-value="3"></i><b>(3)</b>
Grid load(<span class="directive">final</span> <span class="predefined-type">Class</span><?> domainClass); <i class="conum" data-value="4"></i><b>(4)</b>
Grid defaultGridFor(<span class="predefined-type">Class</span><?> domainClass); <i class="conum" data-value="5"></i><b>(5)</b>
Grid normalize(<span class="directive">final</span> Grid grid); <i class="conum" data-value="6"></i><b>(6)</b>
Grid complete(Grid grid); <i class="conum" data-value="7"></i><b>(7)</b>
Grid minimal(Grid grid); <i class="conum" data-value="8"></i><b>(8)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>whether dynamic reloading of layouts is enabled. The default implementation enables reloading for prototyping, disables in production</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>support metamodel invalidation/rebuilding of spec, eg as called by this <a href="rgcms.html#_rgcms_classes_mixins_Object_rebuildMetamodel">Object mixin</a> action.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>whether any persisted layout metadata (eg a <code>.layout.xml</code> file) exists for this domain class. Just delegates to corresponding method in <a href="#_rgsvc_spi_GridLoaderService"><code>GridLoaderService</code></a>.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>returns a new instance of a <a href="rgcms.html#_rgcms_classes_layout_component"><code>Grid</code></a> for the specified domain class, eg as loaded from a <code>layout.xml</code> file. If none exists, will return null (and the calling <a href="#_rgsvc_spi_GridService"><code>GridService</code></a> will use <a href="#_rgsvc_spi_GridSystemService"><code>GridSystemService</code></a> to obtain a default grid for the domain class).</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>returns a default grid, eg two columns in ratio 4:8. Used when no existing grid layout exists for a domain class.</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>validates and normalizes a grid, modifying the grid so that all of the domain object’s members (properties, collections, actions) are bound to regions of the grid. This is done using existing metadata, most notably that of the <a href="rgant.html#_rgant-MemberOrder"><code>@MemberOrder</code></a> annotation. Such a grid, if persisted as the layout XML file for the domain class, allows the <code>@MemberOrder</code> annotation to be removed from the source code of the domain class (but other annotations must be retained).</td>
</tr>
<tr>
<td><i class="conum" data-value="7"></i><b>7</b></td>
<td>Takes a normalized grid and enriches it with additional metadata (taken from Apache Isis' internal metadata) that can be represented in the layout XML. Such a grid, if persisted as the layout XML file for the domain class, allows all layout annotations (<a href="rgant.html#_rgant-ActionLayout"><code>@ActionLayout</code></a>, <a href="rgant.html#_rgant-PropertyLayout"><code>@PropertyLayout</code></a> and <a href="rgant.html#_rgant-CollectionLayout"><code>@CollectionLayout</code></a>) to be removed from the source code of the domain class.</td>
</tr>
<tr>
<td><i class="conum" data-value="8"></i><b>8</b></td>
<td>Takes a normalized grid and strips out removes all members, leaving only the grid structure. Such a grid, if persisted as the layout XML file for the domain class, requires that the <a href="rgant.html#_rgant-MemberOrder"><code>@MemberOrder</code></a> annotation is retained in the source code of said class in order to bind members to the regions of the grid.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The first four methods just delegate to the corresponding methods in <a href="#_rgsvc_spi_GridSystemService"><code>GridSystemService</code></a>, while the last four delegate to the corresponding method in <a href="#_rgsvc_spi_GridSystemService"><code>GridSystemService</code></a>. The service inspects the <code>Grid</code>'s concrete class to determine which actual <code>GridSystemService</code> instance to delegate to.</p>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_6">3.7.2. Implementation</h4>
<div class="paragraph">
<p>The framework provides a default implementation of this service, namely <code>GridServiceDefault</code>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_5">3.7.3. Registering the Services</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>), then the
default implementation of <code>GridLoaderService</code> is automatically registered and injected, and no further
configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).
That said, there should be little reason to use a different implementation; if behaviour does need to be changed, it would also be possible to replace the implementation of either the <code>GridLoaderService</code> or the <code>GridSystemService</code>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_5">3.7.4. Related Services</h4>
<div class="paragraph">
<p>This service calls <a href="#_rgsvc_spi_GridLoaderService"><code>GridLoaderService</code></a> and <a href="#_rgsvc_spi_GridSystemService"><code>GridSystemService</code></a>.</p>
</div>
<div class="paragraph">
<p>This service is called by <a href="#_rgsvc_api_LayoutService"><code>LayoutService</code></a>, exposed in the UI through <code>LayoutServiceMenu</code> (to download the layout XML as a zip file for all domain objects) and the <a href="rgcms.html#_rgcms_classes_mixins_Object"><code>downloadLayoutXml()</code></a> mixin (to download the layout XML for a single domain
object).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_HintStore">3.8. <code>HintStore</code></h3>
<div class="paragraph">
<p>The <code>HintStore</code> service defines an SPI for the <a href="ugvw.html">Wicket viewer</a> to store UI hints on a per-object basis.
For example, the viewer remembers which tabs are selected, and for collections which view is selected (eg table or hidden),
which page of a table to render, or whether "show all" (rows) is toggled.</p>
</div>
<div class="paragraph">
<p>The default implementation of this service uses the HTTP session. The service is an SPI because the amount of data
stored could potentially be quite large (for large numbers of users who use the app all day). An SPI makes it easy to
plug in an alternative implementation that is more sophisticated than the default (eg implementing MRU/LRU queue, or
using a NoSQL database, or simply to disabling the functionality altogether).</p>
</div>
<div class="sect3">
<h4 id="_spi_8">3.8.1. SPI</h4>
<div class="paragraph">
<p>The SPI of <code>HintStore</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">HintStore</span> {
<span class="predefined-type">String</span> get(<span class="directive">final</span> Bookmark bookmark, <span class="predefined-type">String</span> hintKey); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="type">void</span> set(<span class="directive">final</span> Bookmark bookmark, <span class="predefined-type">String</span> hintKey, <span class="predefined-type">String</span> value); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="type">void</span> remove(<span class="directive">final</span> Bookmark bookmark, <span class="predefined-type">String</span> hintKey); <i class="conum" data-value="3"></i><b>(3)</b>
<span class="type">void</span> removeAll(Bookmark bookmark); <i class="conum" data-value="4"></i><b>(4)</b>
<span class="predefined-type">Set</span><<span class="predefined-type">String</span>> findHintKeys(Bookmark bookmark); <i class="conum" data-value="5"></i><b>(5)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>obtain a hint (eg which tab to open) for a particular object. Object identity is represented by <code>Bookmark</code>, as
per the <a href="#_rgsvc_api_BookmarkService"><code>BookmarkService</code></a>, so that alternative implementations can easily serialize this state to a string.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>set the state of a hint. (The value of) all hints are represented as strings.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>remove a single hint for an object;</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>remove all hints</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>obtain all known hints for an object</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_7">3.8.2. Implementation</h4>
<div class="paragraph">
<p>The core framework provides a default implementation of this service (<code>org.apache.isis.viewer.wicket.viewer.services.HintStoreUsingWicketSession</code>).</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_2">3.8.3. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>HintStore</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_6">3.8.4. Related Services</h4>
<div class="paragraph">
<p>The <a href="#ugvw.adoc">Wicket viewer</a> exposes the <a href="rgcms.html#_rgcms_classes_mixins_Object_clearHints">"clear hints"</a>
mixin action that is for use by end-users of the application to clear any UI hints that have accumulated for a
domain object.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_LocaleProvider">3.9. <code>LocaleProvider</code></h3>
<div class="paragraph">
<p>The <code>LocaleProvider</code> service is one of the services that work together to implement Apache Isis' support for i18n, being used by Isis' default implementation of <a href="#_rgsvc_spi_TranslationService"><code>TranslationService</code></a>.</p>
</div>
<div class="paragraph">
<p>The role of the service itself is simply to return the <code>Locale</code> of the current user.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>For the "big picture" and further details on Apache Isis' i18n support, see <a href="ugbtb.html#_ugbtb_i18n">here</a>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_spi_9">3.9.1. SPI</h4>
<div class="paragraph">
<p>The SPI defined by this service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">LocaleProvider</span> {
<span class="annotation">@Programmatic</span>
<span class="predefined-type">Locale</span> getLocale();
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This is notionally request-scoped, returning the <code>Locale</code> of the current user; <em>not</em> that of the server. (Note that the implementation is not required to actually be <a href="rgant.html#_rgant-RequestScoped"><code>@RequestScoped</code></a>, however).</p>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_8">3.9.2. Implementation</h4>
<div class="paragraph">
<p>Isis' <a href="ugvw.html">Wicket viewer</a> provides an implementation of this service (<code>LocaleProviderWicket</code>) which leverages Apache Wicket APIs.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Currently there is no equivalent implementation for the <a href="ugvro.html">RestfulObjects viewer</a>.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_6">3.9.3. Registering the Services</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>), <em>and</em> that the
<a href="ugvw.html">Wicket viewer</a> is being used, then an implementation of <code>LocaleProvider</code> is
automatically registered and injected (it is annotated with <code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_7">3.9.4. Related Services</h4>
<div class="paragraph">
<p>This service works in conjunction with <a href="#_rgsvc_spi_TranslationService"><code>TranslationService</code></a> and <a href="#_rgsvc_spi_TranslationsResolver"><code>TranslationsResolver</code></a> in order to provide i18n support.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_RoutingService">3.10. <code>RoutingService</code></h3>
<div class="paragraph">
<p>The <code>RoutingService</code> provides the ability to return (and therefore render) an alternative object from an action invocation.</p>
</div>
<div class="paragraph">
<p>There are two primary use cases:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>if an action returns an aggregate leaf (that is, a child object which has an owning parent), then the parent object can be
returned instead.<br></p>
<div class="paragraph">
<p>For example, an action returning <code>OrderItem</code> might instead render the owning <code>Order</code> object. It is the responsibility
of the implementation to figure out what the "owning" object might be.</p>
</div>
</li>
<li>
<p>if an action returns <code>null</code> or is <code>void</code>, then return some other "useful" object.<br></p>
<div class="paragraph">
<p>For example, return the home page (eg as defined by the <a href="rgant.html#_rgant-HomePage"><code>@HomePage</code></a> annotation).</p>
</div>
</li>
</ul>
</div>
<div class="paragraph">
<p>Currently the routing service is used only by the <a href="ugvw.html">Wicket viewer</a>; it is ignored by the <a href="ugvro.html">Restful Objects</a> viewer.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Unlike most other domain services, the framework will check <em>all</em> available implementations of
<code>RoutingService</code> to return a route, rather than the first implementation found; in other words it uses the
chain-of-responsibility pattern. Services are called in the order defined by
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a>). The route used will be the
result of the first implementation checked that declares that it can provide a route.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_spi_10">3.10.1. SPI</h4>
<div class="paragraph">
<p>The SPI defined by this service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">RoutingService</span> {
<span class="annotation">@Programmatic</span>
<span class="type">boolean</span> canRoute(<span class="predefined-type">Object</span> original); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="annotation">@Programmatic</span>
<span class="predefined-type">Object</span> route(<span class="predefined-type">Object</span> original); <i class="conum" data-value="2"></i><b>(2)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>whether this implementation recognizes and can "route" the object. The <code>route(…​)</code> method is only called if this method returns <code>true</code>.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>the object to use; this may be the same as the original object, some other object, or (indeed) <code>null</code>.</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_9">3.10.2. Implementation</h4>
<div class="paragraph">
<p>The framework provides a default implementation which will always return the original object provided, or the home page
if a <code>null</code> or <code>void</code> was provided. It uses the <a href="#_rgsvc_api_HomePageProviderService"><code>HomePageProviderService</code></a>.</p>
</div>
<div class="paragraph">
<p>There can be multiple implementations of <code>RoutingService</code> registered. These are checked in turn (chain of responsibility
pattern), ordered according to <a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a>
(as explained in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).
The route from the first service that returns <code>true</code> from its <code>canRoute(…​)</code> method will be used.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_7">3.10.3. Registering the Services</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis'
default implementation of <code>RoutingService</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_8">3.10.4. Related Services</h4>
<div class="paragraph">
<p>The default implementation of ths service uses the
<a href="#_rgsvc_api_HomePageProviderService"><code>HomePageProviderService</code></a>.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_TranslationService">3.11. <code>TranslationService</code></h3>
<div class="paragraph">
<p>The <code>TranslationService</code> is the cornerstone of Apache Isis' i18n support. Its role is to be able to provide translated versions of the various elements within the Apache Isis metamodel (service and object classes, properties, collections, actions, action parameters) and also to translate business rule (disable/valid) messages, and exceptions. These translations provide for both singular and plural forms.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>For the "big picture" and further details on Apache Isis' i18n support, see <a href="ugbtb.html#_ugbtb_i18n">here</a>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_spi_11">3.11.1. SPI</h4>
<div class="paragraph">
<p>The SPI defined by this service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">TranslationService</span> {
<span class="annotation">@Programmatic</span>
<span class="predefined-type">String</span> translate(<span class="predefined-type">String</span> context, <span class="predefined-type">String</span> text); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="annotation">@Programmatic</span>
<span class="predefined-type">String</span> translate(<span class="predefined-type">String</span> context, <i class="conum" data-value="2"></i><b>(2)</b>
<span class="predefined-type">String</span> singularText,
<span class="predefined-type">String</span> pluralText, <span class="type">int</span> num);
<span class="type">enum</span> Mode { READ, WRITE;}
<span class="annotation">@Programmatic</span>
Mode getMode(); <i class="conum" data-value="3"></i><b>(3)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>translate the text, in the locale of the "current user".</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>return a translation of either the singular or the plural text, dependent on the <code>num</code> parameter, in the locale of the "current user"</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>whether this implementation is operating in read or in write mode.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>If in read mode, then the translations are expected to be present.</p>
</div>
<div class="paragraph">
<p>If in write mode, then the implementation is saving translation keys, and will always return the untranslated translation.</p>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_10">3.11.2. Implementation</h4>
<div class="paragraph">
<p>The Apache Isis framework provides a default implementation (<code>TranslationServicePo</code>) that uses the GNU <code>.pot</code> and <code>.po</code> files for translations. It relies on the <code>LocaleProvider</code> service (to return the <code>Locale</code> of the current user) and also the <code>TranslationsResolver</code> service (to read existing translations).</p>
</div>
<div class="paragraph">
<p>The framework also provides a supporting <code>TranslationServicePoMenu</code> provides menu items under the "Prototyping" secondary menu for controlling this service and downloading <code>.pot</code> files for translation.</p>
</div>
<div class="paragraph">
<p>For more details on the implementation, see <a href="ugbtb.html#_ugbtb_i18n">i18n support</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_8">3.11.3. Registering the Services</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>TranslationService</code> service (along with the supporting menu service) are automatically registered and injected (it is annotated with <code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>If the menu items are not required then these can be suppressed either using security or by implementing a <a href="ugbtb.html#_ugbtb_decoupling_vetoing-visibility">vetoing subscriber</a>.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
<div class="sect3">
<h4 id="_rgsvc_api_LayoutService_related-mixins-and-menus">3.11.4. Related Menus</h4>
<div class="paragraph">
<p>The <code>TranslationServicePoMenu</code> menu exposes the <code>TranslationServicePo</code> service’s <code>toPot()</code> method so that all
translations can be downloaded as a single file.</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_9">3.11.5. Related Services</h4>
<div class="paragraph">
<p>This service works in conjunction with <a href="#_rgsvc_spi_LocaleProvider"><code>LocaleProvider</code></a> and <a href="#_rgsvc_spi_TranslationsResolver"><code>TranslationsResolver</code></a> in order to provide i18n support.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_TranslationsResolver">3.12. <code>TranslationsResolver</code></h3>
<div class="paragraph">
<p>The <code>TranslationsResolver</code> service is one of the services that work together to implement Apache Isis' support for i18n, being used by Isis' default implementation of <a href="#_rgsvc_spi_TranslationService"><code>TranslationService</code></a>.</p>
</div>
<div class="paragraph">
<p>The role of the service itself is locate and return translations.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>For the "big picture" and further details on Apache Isis' i18n support, see <a href="ugbtb.html#_ugbtb_i18n">here</a>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_spi_12">3.12.1. SPI</h4>
<div class="paragraph">
<p>The SPI defined by this service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">TranslationsResolver</span> {
<span class="annotation">@Programmatic</span>
<span class="predefined-type">List</span><<span class="predefined-type">String</span>> readLines(<span class="directive">final</span> <span class="predefined-type">String</span> file);
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_11">3.12.2. Implementation</h4>
<div class="paragraph">
<p>Isis' <a href="ugvw.html">Wicket viewer</a> provides an implementation of this service (<code>TranslationsResolverWicket</code>) which leverages Apache Wicket APIs. This searches for translation files in the standard <code>WEB-INF/</code> directory.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Currently there is no equivalent implementation for the <a href="ugvro.html">RestfulObjects viewer</a>.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_3">3.12.3. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#<em>rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>), _and</em> that the <a href="ugvw.html">Wicket viewer</a> is being used, then an implementation of <code>TranslationsResolver</code> is
automatically registered and injected (it is annotated with <code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_10">3.12.4. Related Services</h4>
<div class="paragraph">
<p>This service works in conjunction with <a href="#_rgsvc_spi_LocaleProvider"><code>LocaleProvider</code></a> and <a href="#_rgsvc_spi_TranslationService"><code>TranslationService</code></a> in order to provide i18n support.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_UrlEncodingService">3.13. <code>UrlEncodingService</code></h3>
<div class="paragraph">
<p>The <code>UrlEncodingService</code> defines a consistent way to convert strings to/from a form safe for use
within a URL. The service is used by the framework to map <a href="ugbtb.html#_ugbtb_view-models">view model</a>
mementos (derived from the state of the view model itself) into a form that can be used as a view model. When the
framework needs to recreate the view model (for example to invoke an action on it), this URL is converted back into a
view model memento, from which the view model can then be hydrated.</p>
</div>
<div class="paragraph">
<p>Defining this functionality as an SPI has two use cases:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>first, (though some browsers support longer strings), there is a limit of 2083 characters for URLs. For view model
mementos that correspond to large strings (as might occur when serializing a JAXB
<a href="rgant.html#_rgant-XmlRootElement"><code>@XmlRootElement</code></a>-annotated view model), the service provides a
hook. <br></p>
<div class="paragraph">
<p>For example, each memento string could be mapped to a GUID held in some cluster-aware cache.</p>
</div>
</li>
<li>
<p>the service provides the ability, to encrypt the string in order to avoid leakage of potentially sensitive
state within the URL.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The framework provides a default implementation of this service, <code>UrlEncodingServiceUsingBaseEncoding</code> (also in the
applib) that uses <code>base-64</code> encoding to <code>UTF-8</code> charset.</p>
</div>
<div class="sect3">
<h4 id="_spi_13">3.13.1. SPI</h4>
<div class="paragraph">
<p>The SPI defined by the service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">UrlEncodingService</span> {
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <span class="predefined-type">String</span> encode(<span class="directive">final</span> <span class="predefined-type">String</span> str); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <span class="predefined-type">String</span> decode(<span class="predefined-type">String</span> str); <i class="conum" data-value="2"></i><b>(2)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>convert the string (eg view model memento) into a string safe for use within an URL</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>unconvert the string from its URL form into its original form URL</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_12">3.13.2. Implementation</h4>
<div class="paragraph">
<p>The framework provides a default implementation (<code>UrlEncodingServiceUsingBaseEncoding</code>) that simply converts the string
using base-64 encoding and UTF-8 character set. As already noted, be aware that the maximum length of a URL should not
exceed 2083 characters. For large view models, there’s the possibility that this limit could be exceeded; in such
cases register an alternative implementation of this service.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_UserProfileService">3.14. <code>UserProfileService</code></h3>
<div class="paragraph">
<p>The <code>UserProfileService</code> provides the ability for the domain application to return supplementary metadata about the current user. This information is used (by the <a href="ugvw.html">Wicket viewer</a>) to customize the appearance of the tertiary "Me" menu bar (top right). For example, rather than display the username, instead the user’s first and last name could be displayed.</p>
</div>
<div class="paragraph">
<p>Another use case is to allow the user to switch context in some fashion or other. This might be to emulate a sort of "sudo"-like function, or perhaps to focus on some particular set of data.</p>
</div>
<div class="sect3">
<h4 id="_spi_14">3.14.1. SPI</h4>
<div class="paragraph">
<p>The SPI defined by the service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">UserProfileService</span> {
<span class="annotation">@Programmatic</span>
<span class="predefined-type">String</span> userProfileName(); <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>is used (in the Wicket viewer) as the menu name of the tertiary "Me" menu bar.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>If the method returns <code>null</code> or throws an exception then the framework will default to using the current user name.</p>
</div>
<div class="paragraph">
<p>In the future this API may be expanded; one obvious possibility is to return a profile photo or avatar URL.</p>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_13">3.14.2. Implementation</h4>
<div class="paragraph">
<p>There is no default implementation of this service provided by the core Apache Isis framework.</p>
</div>
<div class="paragraph">
<p>An example implementation can be found in the (non-ASF)
<a href="http://github.com/isisaddons/isis-app-todoapp">Isis addons' todoapp</a>:</p>
</div>
<div class="imageblock">
<div class="content">
<a class="image" href="images/reference-services-spi/UserProfileService/todoapp.png"><img src="images/reference-services-spi/UserProfileService/todoapp.png" alt="todoapp" width="800px"></a>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Currently this feature is not integrated with Apache Isis' authentication mechanisms; the information provided is purely metadata provided for presentation purposes only.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_rgsvc_application-layer-api">4. Application Layer API</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Domain service APIs for the application layer allow the domain objects to control aspects of the application layer, such as sending info messages back to the end-user.</p>
</div>
<div class="paragraph">
<p>The table below summarizes the application layer APIs defined by Apache Isis. It also lists their corresponding implementation, either a default implementation provided by Apache Isis itself, or provided by one of the in (non-ASF) <a href="http://www.isisaddons.org">Isis Addons</a> modules.</p>
</div>
<table class="tableblock frame-all grid-all spread">
<caption class="title">Table 2. Application Layer API</caption>
<colgroup>
<col style="width: 25%;">
<col style="width: 50%;">
<col style="width: 12.5%;">
<col style="width: 12.5%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">API</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Implementation</th>
<th class="tableblock halign-left valign-top">Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_AcceptHeaderService"><code>o.a.i.applib.</code><br>
<code>services.acceptheader</code><br>
<code>AcceptHeaderService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Request-scoped access to HTTP Accept headers.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>AcceptHeaderServiceDefault</code><br>
<code>o.a.i.core</code><br>
<code>isis-viewer-restfulobjects-rendering</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Populated only when the domain objects are accessed using the <a href="ugvro.html">Restful Objects viewer</a>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_ActionInvocationContext"><code>o.a.i.applib.</code><br>
<code>services.actinv</code><br>
<code>ActionInvocation-</code><br>
<code>Context</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Request-scoped access to whether action is invoked on object and/or on collection of objects</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>ActionInvocationContext</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-applib</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">API is also concrete class</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_BackgroundService"><code>o.a.i.applib.</code><br>
<code>services.background</code><br>
<code>BackgroundService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Programmatic persistence of commands to be persisted (so can be executed by a background mechanism, eg scheduler)</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>BackgroundServiceDefault</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-runtime</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">depends on:<br>
<a href="#_rgsvc_spi_BackgroundCommandService"><code>BackgroundCommand-Service</code></a></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_CommandContext"><code>o.a.i.applib.</code><br>
<code>services.command</code><br>
<code>CommandContext</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Request-scoped access to capture the users’s <em>intention</em> to invoke an action or to edit a property.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>CommandContext</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-applib</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">API is also a concrete class.<br>
depends on:<br>
<a href="#_rgsvc_spi_CommandService"><code>CommandService</code></a> for persistent <code>Command</code>, else in-memory impl. used.
</p><p class="tableblock">The <a href="#_rgsvc_api_InteractionContext"><code>InteractionContext</code></a> manages the actual execution of the command.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_InteractionContext"><code>o.a.i.applib.</code><br>
<code>services.iactn</code><br>
<code>InteractionContext</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>(<code>1.13.0-SNAPSHOT</code>) Request-scoped access to the current member execution (action invocation or property edit),
represented as the <code>Interaction</code> context.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>InteractionContext</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-applib</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">API is also a concrete class.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_MessageService"><code>o.a.i.applib.</code><br>
<code>services.message</code><br>
<code>MessageService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Methods to inform or warn the user, or to raise errors.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>FactoryService-</code><br>
<code>Default</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-metamodel</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Supercedes methods in <a href="#_rgsvc_api_DomainObjectContainer"><code>DomainObjectContainer</code></a>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_SessionManagementService"><code>o.a.i.applib.</code><br>
<code>services.sessmgmt</code><br>
<code>SessionManagementService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Methods for batching long-running work (eg data migration) into multiple sessions.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>SessionManagementService-</code><br>
<code>Default</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-runtime</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_TitleService"><code>o.a.i.applib.</code><br>
<code>services.title</code><br>
<code>TitleService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Methods to programmatically obtain the title or icon of a domain object.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>TitleService-</code><br>
<code>Default</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-metamodel</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Supercedes methods in <a href="#_rgsvc_api_DomainObjectContainer"><code>DomainObjectContainer</code></a>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_TransactionService"><code>o.a.i.applib.</code><br>
<code>services.xactn</code><br>
<code>TransactionService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Methods for managing transactions.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>TransactionService-</code><br>
<code>Default</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-metamodel</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Supercedes methods in <a href="#_rgsvc_api_DomainObjectContainer"><code>DomainObjectContainer</code></a>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_WrapperFactory"><code>o.a.i.applib.</code><br>
<code>services.wrapper</code><br>
<code>WrapperFactory</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Interact with another domain object "as if" through the UI (enforcing business rules, firing domain events)</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>WrapperFactoryDefault</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-wrapper</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Key:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>o.a.i</code> is an abbreviation for <code>org.apache.isis</code></p>
</li>
<li>
<p><code>o.ia.m</code> is an abbreviation for <code>org.isisaddons.module</code></p>
</li>
<li>
<p><code>o.a.i.c.m.s</code> is an abbreviation for <code>org.apache.isis.core.metamodel.services</code></p>
</li>
<li>
<p><code>o.a.i.c.r.s</code> is an abbreviation for <code>org.apache.isis.core.runtime.services</code></p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_AcceptHeaderService">4.1. <code>AcceptHeaderService</code></h3>
<div class="paragraph">
<p>The <code>AcceptHeaderService</code> domain service is a <a href="rgant.html#_rgant-RequestScoped"><code>@RequestScoped</code></a> service that
simply exposes the HTTP <code>Accept</code> header to the domain. Its intended use is to support multiple versions of a REST API, where the responsibility for content negotiation (determining which version of the REST API is to be used) is managed by logic in the domain objects themselves.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>As an alternative to performing content negotiation within the domain classes, the <a href="rgfis.html#_rgfis_spi_ContentNegotiationService"><code>ContentNegotiationService</code></a> and
<a href="#_rgsvc_spi_ContentMappingService"><code>ContentMappingService</code></a> SPI domain services allow the framework to perform the content negotiation responsibility.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_api_implementation">4.1.1. API & Implementation</h4>
<div class="paragraph">
<p>The API defined by the service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>(nature = NatureOfService.DOMAIN)
<span class="annotation">@RequestScoped</span> <i class="conum" data-value="1"></i><b>(1)</b>
<span class="directive">public</span> <span class="type">interface</span> <span class="class">AcceptHeaderService</span> {
<span class="annotation">@Programmatic</span>
<span class="predefined-type">List</span><MediaType> getAcceptableMediaTypes(); <i class="conum" data-value="2"></i><b>(2)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>is <a href="rgant.html#_rgant-RequestScoped"><code>@RequestScoped</code></a>, so this domain service instance is scoped to a particular request and is then destroyed</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>returns the list of media types found in the HTTP Accept header.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The default implementation is provided by <code>o.a.i.v.ro.rendering.service.acceptheader.AcceptHeaderServiceForRest</code>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Note that the service will only return a list when the request is initiated through the <a href="ugvro.html">Restful Objects viewer</a>. Otherwise the service will return <code>null</code>.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_usage">4.1.2. Usage</h4>
<div class="paragraph">
<p>The intended use of this service is where there are multiple concurrent versions of a REST API, for backward
compatibility of existing clients. The <code>AcceptHeaderService</code> allows the responsibility for content negotiation
(determining which version of the REST API is to be used) to be performed by logic in the domain objects themselves.</p>
</div>
<div class="paragraph">
<p>The diagram below illustrated this:</p>
</div>
<div class="imageblock">
<div class="content">
<a class="image" href="images/reference-services-api/acceptheaderservice.png"><img src="images/reference-services-api/acceptheaderservice.png" alt="acceptheaderservice" width="700px"></a>
</div>
</div>
<div class="paragraph">
<p>The REST request is submitted to a domain service with a <a href="rgant.html#_rgant-DomainService_nature">nature</a> of <code>VIEW_REST_ONLY</code> (<code>MyRestApi</code> in the diagram). This uses the <code>AcceptHeaderService</code> to obtain the values of the
HTTP <code>Accept</code> header. Based on this it delegates to the appropriate underlying domain service (with a nature of
<code>DOMAIN</code> so that they are not exposed in the REST API at all).</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The service does not define any conventions as to the format of the media types. The option is to use the media type’s
type/subtype, eg <code>application/vnd.myrestapi-v1+json</code>; an alternative is to use a media type parameter as a hint, eg
<code>application/json;x-my-rest-api-version=1</code> (where <code>x-my-rest-api-version</code> is the media type parameter).</p>
</div>
<div class="paragraph">
<p>The Restful Objects specification does this something similar with its own <code>x-ro-domain-type</code> media type parameter;
this is used by the <a href="#_rgsvc_spi_ContentMappingService"><code>ContentMappingService</code></a> to determine how to
map domain objects to view models/DTOs.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_4">4.1.3. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' default
implementation of <code>AcceptHeaderService</code> class is automatically registered (it is annotated with <code>@DomainService</code>)
so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_ActionInvocationContext">4.2. <code>ActionInvocationContext</code></h3>
<div class="paragraph">
<p>The <code>ActionInvocationContext</code> domain service is a <a href="rgant.html#_rgant-RequestScoped"><code>@RequestScoped</code></a> service intended to support the implementation of "bulk" actions annotated with <a href="rgant.html#_rgant-Action_invokeOn"><code>@Action#invokeOn()</code></a>. This allows the user to select multiple objects in a table and then invoke the same action against all of them.</p>
</div>
<div class="paragraph">
<p>When an action is invoked in this way, this service allows each object instance to "know where it is" in the collection; it acts a little like an iterator. In particular, an object can determine if it is the last object to be called, and so can perform special processing, eg to return a summary calculated result.</p>
</div>
<div class="sect3">
<h4 id="_api_implementation_2">4.2.1. API & Implementation</h4>
<div class="paragraph">
<p>The API defined by the service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>(nature = NatureOfService.DOMAIN)
<span class="annotation">@RequestScoped</span> <i class="conum" data-value="1"></i><b>(1)</b>
<span class="directive">public</span> <span class="directive">static</span> <span class="type">class</span> <span class="class">ActionInvocationContext</span> {
<span class="directive">public</span> InvokedOn getInvokedOn() { ... } <i class="conum" data-value="2"></i><b>(2)</b>
<span class="directive">public</span> <span class="predefined-type">List</span><<span class="predefined-type">Object</span>> getDomainObjects() { ... } <i class="conum" data-value="3"></i><b>(3)</b>
<span class="directive">public</span> <span class="type">int</span> getSize() { ... }
<span class="directive">public</span> <span class="type">int</span> getIndex() { ... } <i class="conum" data-value="4"></i><b>(4)</b>
<span class="directive">public</span> <span class="type">boolean</span> isFirst() { ... }
<span class="directive">public</span> <span class="type">boolean</span> isLast() { ... }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>is <a href="rgant.html#_rgant-RequestScoped"><code>@RequestScoped</code></a>, so this domain service instance is scoped to a particular request and is then destroyed</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>an enum set to either <code>OBJECT</code> (if action has been invoked on a single object) or <code>COLLECTION</code> (if has been invoked on a collection).</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>returns the list of domain objects which are being acted upon</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>is the 0-based index to the object being acted upon.</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_usage_2">4.2.2. Usage</h4>
<div class="paragraph">
<p>For actions that are void or that return null, Apache Isis will return to the list once executed. But for bulk actions that are non-void, Apache Isis will render the returned object/value from the last object invoked (and simply discards the object/value of all actions except the last).</p>
</div>
<div class="paragraph">
<p>One idiom is for the domain objects to also use the <a href="#_rgsvc_api_Scratchpad"><code>Scratchpad</code></a> service to share information, for example to aggregate values. The <code>ActionInvocationContext#isLast()</code> method can then be used to determine if all the information has been gathered, and then do something with it (eg derive variance across a range of values, render a graph etc).</p>
</div>
<div class="paragraph">
<p>More prosaically, the <code>ActionInvocationContext</code> can be used to ensure that the action behaves appropriately depending on how it has been invoked (on a single object and/or a collection) whether it is called in bulk mode or regular mode. Here’s a snippet of code from the bulk action in the Isis addon example <a href="https://github.com/isisaddons/isis-app-todoapp/">todoapp</a> (not ASF):</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">ToDoItem</span> ... {
<span class="annotation">@Action</span>(invokeOn=InvokeOn.OBJECTS_AND_COLLECTIONS)
<span class="directive">public</span> ToDoItem completed() {
setComplete(<span class="predefined-constant">true</span>);
...
return actionInvocationContext.getInvokedOn() == InvokedOn.OBJECT
? <span class="local-variable">this</span> <i class="conum" data-value="1"></i><b>(1)</b>
: <span class="predefined-constant">null</span>; <i class="conum" data-value="2"></i><b>(2)</b>
}
<span class="annotation">@Inject</span>
ActionInvocationContext actionInvocationContext;
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>if invoked as a regular action, return this object;</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>otherwise (if invoked on collection of objects), return null, so that the <a href="ugvw.html">Wicket viewer</a> will re-render the list of objects</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_5">4.2.3. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' default
implementation of <code>ActionInvocationContext</code> class is automatically registered (it is annotated with <code>@DomainService</code>)
so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
<div class="sect3">
<h4 id="_unit_testing_support">4.2.4. Unit testing support</h4>
<div class="paragraph">
<p>The <code>ActionInvocationContext</code> class also has a couple of static factory methods intended to support unit testing:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>(nature = NatureOfService.DOMAIN)
<span class="annotation">@RequestScoped</span>
<span class="directive">public</span> <span class="type">class</span> <span class="class">ActionInvocationContext</span> {
<span class="directive">public</span> <span class="directive">static</span> ActionInvocationContext onObject(<span class="directive">final</span> <span class="predefined-type">Object</span> domainObject) {
<span class="keyword">return</span> <span class="keyword">new</span> ActionInvocationContext(InvokedOn.OBJECT, <span class="predefined-type">Collections</span>.singletonList(domainObject));
}
<span class="directive">public</span> <span class="directive">static</span> ActionInvocationContext onCollection(<span class="directive">final</span> <span class="predefined-type">Object</span>... domainObjects) {
<span class="keyword">return</span> onCollection(<span class="predefined-type">Arrays</span>.asList(domainObjects));
}
<span class="directive">public</span> <span class="directive">static</span> ActionInvocationContext onCollection(<span class="directive">final</span> <span class="predefined-type">List</span><<span class="predefined-type">Object</span>> domainObjects) {
<span class="keyword">return</span> <span class="keyword">new</span> ActionInvocationContext(InvokedOn.COLLECTION, domainObjects);
}
...
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_BackgroundService">4.3. <code>BackgroundService2</code></h3>
<div class="paragraph">
<p>The <code>BackgroundService2</code> domain service, and also the companion
<a href="#_rgsvc_spi_BackgroundCommandService"><code>BackgroundCommandService2</code></a> SPI service, enable commands
to be persisted such that they may be invoked in the background. (The <code>BackgroundService2</code> and
<code>BackgroundCommandService2</code> extensions to these services have been introduced in <code>1.13.0-SNAPSHOT</code>).</p>
</div>
<div class="paragraph">
<p>The <code>BackgroundService2</code> is responsible for capturing a memento representing the command in a typesafe way,
and persisting it rather than executing it directly.</p>
</div>
<div class="paragraph">
<p>The default <code>BackgroundServiceDefault</code> implementation works by using a proxy wrapper around the target so that it can
capture the action to invoke and its arguments. (As of <code>1.13.0-SNAPSHOT</code>), this is done using <a href="rgfis.html#_rgfis_spi_CommandDtoServiceInternal"><code>CommandDtoServiceInternal</code></a> (in previous releases it used (a private copy of) <a href="#_rgsvc_api_MementoService"><code>MementoService</code></a>).</p>
</div>
<div class="paragraph">
<p>The persistence delegates the persistence of the memento to an appropriate implementation of the companion
<code>BackgroundCommandService2</code>. One such implementation of <code>BackgroundCommandService</code> is provided by (non-ASF)
<a href="http://github.com/isisaddons/isis-module-command">Isis addons' command</a> module.</p>
</div>
<div class="paragraph">
<p>The persisting of commands is only half the story; there needs to be a separate process to read the commands and
execute them. The <code>BackgroundCommandExecution</code> abstract class (discussed
<a href="#_rgsvc_api_BackgroundService_BackgroundCommandExecution">below</a>) provides infrastructure to do this;
the concrete implementation of this class depends on the configured <code>BackgroundCommandService</code> (in order to query for
the persisted (background) <code>Command</code>s.</p>
</div>
<div class="sect3">
<h4 id="_api_implementation_3">4.3.1. API & Implementation</h4>
<div class="paragraph">
<p>The API is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">BackgroundService2</span> {
<T> T execute(<span class="directive">final</span> T object); <i class="conum" data-value="1"></i><b>(1)</b>
<T> T executeMixin(<span class="predefined-type">Class</span><T> mixinClass, <span class="predefined-type">Object</span> mixedIn); <i class="conum" data-value="2"></i><b>(2)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>returns a proxy around the domain object; any methods executed against this proxy will result in a command (to invoke the corresponding action) being persisted by <a href="#_rgsvc_spi_BackgroundCommandService2"><code>BackgroundCommandService2</code></a></td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>(<code>1.13.0-SNAPSHOT</code>) returns a proxy around the mixin; any methods executed against this proxy will result in a command (to invoke the corresponding mixin action) being persisted by <a href="#_rgsvc_spi_BackgroundCommandService2"><code>BackgroundCommandService2</code></a>.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The default implementation is provided by core (<code>o.a.i.core.runtime.services.background.BackgroundServiceDefault</code>).</p>
</div>
</div>
<div class="sect3">
<h4 id="_usage_3">4.3.2. Usage</h4>
<div class="paragraph">
<p>Using the service is very straight-forward; wrap the target domain object using <code>BackgroundService#execute(…​)</code> and invoke the method on the object returned by that method.</p>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">void</span> submitCustomerInvoices() {
<span class="keyword">for</span>(Customer customer: customerRepository.findCustomersToInvoice()) {
backgroundService.execute(customer).submitInvoice();
}
messageService.informUser(<span class="string"><span class="delimiter">"</span><span class="content">Calculating...</span><span class="delimiter">"</span></span>);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This will create a bunch of background commands executing the <code>submitInvoice()</code> action for each of the customers returned from the customer repository.</p>
</div>
<div class="paragraph">
<p>The action method invoked must be part of the Apache Isis metamodel, which is to say it must be public, accept only scalar arguments, and must not be annotated with <a href="rgant.html#_rgant-Programmatic"><code>@Programmatic</code></a> or <code>@Ignore</code>. However, it may be annotated with <a href="rgant.html#_rgant-Action_hidden"><code>@Action#hidden()</code></a> or <a href="rgant.html#_rgant-ActionLayout_hidden"><code>@ActionLayout#hidden()</code></a> and it will still be invoked.</p>
</div>
<div class="paragraph">
<p>In fact, when invoked by the background service, no business rules (hidden, disabled, validation) are enforced; the action method must take responsibility for performing appropriate validation and error checking.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>If you want to check business rules, you can use <a href="rgant.html#_rgant-WrapperFactory"><code>@WrapperFactory#wrapNoExecute(…​)</code></a>.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_end_user_experience">4.3.3. End-user experience</h4>
<div class="paragraph">
<p>For the end-user, executing an action that delegates work off to the <code>BackgroundService</code> raises the problem of how does the user know the work is complete?</p>
</div>
<div class="paragraph">
<p>One option is for the background jobs to take responsibility to notify the user themselves. In the above example, this would be the <code>submitInvoice()</code> method called upon each customer. One could imagine more complex designs where only the final command executed notifies the user.</p>
</div>
<div class="paragraph">
<p>However, an alternative is to rely on the fact that the <code>BackgroundService</code> will automatically hint that the <code>Command</code> representing the original interaction (to <code>submitCustomerInvoices()</code> in the example above) should be persisted. This will be available if the related <a href="#_rgsvc_api_CommandContext"><code>CommandContext</code></a> and <a href="#_rgsvc_spi_CommandService"><code>CommandService</code></a> domain services are configured, and the <code>CommandService</code> supports persistent commands. Note that (non-ASF) <a href="http://github.com/isisaddons/isis-module-command">Isis addons' command</a> module does indeed provide such an implementation of <code>CommandService</code> (as well as of the required <code>BackgroundCommandService</code>).</p>
</div>
<div class="paragraph">
<p>Thus, the original action can run a query to obtain it corresponding <code>Command</code>, and return this to the user. The upshot is that the child <code>Command</code>s created by the <code>BackgroundService</code> will then be associated with <code>Command</code> for the original action.</p>
</div>
<div class="paragraph">
<p>We could if we wanted write the above example as follows:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> Command submitCustomerInvoices() {
<span class="keyword">for</span>(Customer customer: customerRepository.findCustomersToInvoice()) {
backgroundService.execute(customer).submitInvoice();
}
<span class="keyword">return</span> commandContext.getCommand();
}
<span class="annotation">@Inject</span>
CommandContext commandContext; <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 injected <a href="#_rgsvc_api_CommandContext"><code>CommandContext</code></a> domain service.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The user would be returned a domain object representing their action invocation.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_9">4.3.4. Registering the Services</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>BackgroundService</code> is automatically registered (it is annotated with <code>@DomainService</code>) so no
further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_11">4.3.5. Related Services</h4>
<div class="paragraph">
<p>This service is closely related to the <a href="#_rgsvc_api_CommandContext"><code>CommandContext</code></a> and also that service’s supporting <a href="#_rgsvc_spi_CommandService"><code>CommandService</code></a> service.</p>
</div>
<div class="paragraph">
<p>The <code>CommandContext</code> service is responsible for providing a parent <code>Command</code> with which the background <code>Command</code>s can then be associated as children, while the <code>CommandService</code> is responsible for persisting those parent <code>Command`s. The latter is analogous to the way in which the `BackgroundCommandService</code> persists the child background `Command`s.</p>
</div>
<div class="paragraph">
<p>The implementations of <code>CommandService</code> and <code>BackgroundCommandService</code> go together; typically both parent <code>Command`s and child background `Command`s will be persisted in the same way. The (non-ASF) <a href="http://github.com/isisaddons/isis-module-command">Isis addons' command</a> module provides implementations of both (see <a href="#_rgsvc_spi_CommandService">`CommandService</code></a> and <a href="#_rgsvc_spi_BackgroundCommandService"><code>BackgroundCommandService</code></a>).</p>
</div>
<div class="paragraph">
<p>The <a href="rgfis.html#_rgfis_spi_CommandDtoServiceInternal"><code>CommandDtoServiceInternal</code></a> (<code>1.13.0-SNAPSHOT</code>) is used to obtain
a memento of the command such that it can be persisted. (In earlier versions, <a href="#_rgsvc_api_MementoService"><code>MementoService</code></a> was used for this purpose).</p>
</div>
</div>
<div class="sect3">
<h4 id="_rgsvc_api_BackgroundService_BackgroundCommandExecution">4.3.6. <code>BackgroundCommandExec’n</code> abstract class</h4>
<div class="paragraph">
<p>The <code>BackgroundCommandExecution</code> (in isis-core) is an abstract template class provided by isis-core that defines an abstract hook method to obtain background `Command`s to be executed:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="directive">abstract</span> <span class="type">class</span> <span class="class">BackgroundCommandExecution</span>
<span class="directive">extends</span> AbstractIsisSessionTemplate {
...
protected <span class="directive">abstract</span> <span class="predefined-type">List</span><? <span class="directive">extends</span> Command> findBackgroundCommandsToExecute();
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The developer is required to implement this hook method in a subclass.</p>
</div>
</div>
<div class="sect3">
<h4 id="_rgsvc_api_BackgroundService_Quartz">4.3.7. Quartz Scheduler Configuration</h4>
<div class="paragraph">
<p>The last part of the puzzle is to actually run the (appropriate implementation of) `BackgroundCommandExecution). This could be run in a batch job overnight, or run continually by, say, the <a href="http://quartz-scheduler.org">Quartz</a> scheduler or by <a href="http://camel.apache.org" class="bare">http://camel.apache.org</a>]Apache Camel]. This section looks at configuring Quartz.</p>
</div>
<div class="paragraph">
<p>If using (non-ASF) <a href="http://github.com/isisaddons/isis-module-command">Isis addons' command</a> module, then note that this already provides a suitable concrete implementation, namely <code>org.isisaddons.module.command.dom.BackgroundCommandExecutionFromBackgroundCommandServiceJdo</code>. We therefore just need to schedule this to run as a Quartz job.</p>
</div>
<div class="paragraph">
<p>First, we need to define a Quartz job, for example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">import</span> <span class="include">org.isisaddons.module.command.dom.BackgroundCommandExecutionFromBackgroundCommandServiceJdo</span>;
<span class="directive">public</span> <span class="type">class</span> <span class="class">BackgroundCommandExecutionQuartzJob</span> <span class="directive">extends</span> AbstractIsisQuartzJob {
<span class="directive">public</span> BackgroundCommandExecutionQuartzJob() {
<span class="local-variable">super</span>(<span class="keyword">new</span> BackgroundCommandExecutionFromBackgroundCommandServiceJdo());
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>where <code>AbstractIsisQuartzJob</code> is in turn the following boilerplate:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">domainapp.webapp.quartz</span>;
<span class="keyword">import</span> <span class="include">org.quartz.Job</span>;
<span class="keyword">import</span> <span class="include">org.quartz.JobExecutionContext</span>;
<span class="keyword">import</span> <span class="include">org.quartz.JobExecutionException</span>;
...
public <span class="type">class</span> <span class="class">AbstractIsisQuartzJob</span> <span class="directive">implements</span> Job {
<span class="directive">public</span> <span class="directive">static</span> <span class="type">enum</span> ConcurrentInstancesPolicy {
SINGLE_INSTANCE_ONLY,
MULTIPLE_INSTANCES
}
<span class="directive">private</span> <span class="directive">final</span> AbstractIsisSessionTemplate isisRunnable;
<span class="directive">private</span> <span class="directive">final</span> ConcurrentInstancesPolicy concurrentInstancesPolicy;
<span class="directive">private</span> <span class="type">boolean</span> executing;
<span class="directive">public</span> AbstractIsisQuartzJob(AbstractIsisSessionTemplate isisRunnable) {
<span class="local-variable">this</span>(isisRunnable, ConcurrentInstancesPolicy.SINGLE_INSTANCE_ONLY);
}
<span class="directive">public</span> AbstractIsisQuartzJob(
AbstractIsisSessionTemplate isisRunnable,
ConcurrentInstancesPolicy concurrentInstancesPolicy) {
<span class="local-variable">this</span>.isisRunnable = isisRunnable;
<span class="local-variable">this</span>.concurrentInstancesPolicy = concurrentInstancesPolicy;
}
<span class="directive">public</span> <span class="type">void</span> execute(<span class="directive">final</span> JobExecutionContext context)
<span class="directive">throws</span> JobExecutionException {
<span class="directive">final</span> AuthenticationSession authSession = newAuthSession(context);
<span class="keyword">try</span> {
<span class="keyword">if</span>(concurrentInstancesPolicy == ConcurrentInstancesPolicy.SINGLE_INSTANCE_ONLY &&
executing) {
<span class="keyword">return</span>;
}
executing = <span class="predefined-constant">true</span>;
isisRunnable.execute(authSession, context);
} <span class="keyword">finally</span> {
executing = <span class="predefined-constant">false</span>;
}
}
AuthenticationSession newAuthSession(JobExecutionContext context) {
<span class="predefined-type">String</span> user = getKey(context, SchedulerConstants.USER_KEY);
<span class="predefined-type">String</span> rolesStr = getKey(context, SchedulerConstants.ROLES_KEY);
<span class="predefined-type">String</span><span class="type">[]</span> roles = Iterables.toArray(
Splitter.on(<span class="string"><span class="delimiter">"</span><span class="content">,</span><span class="delimiter">"</span></span>).split(rolesStr), <span class="predefined-type">String</span>.class);
<span class="keyword">return</span> <span class="keyword">new</span> SimpleSession(user, roles);
}
<span class="predefined-type">String</span> getKey(JobExecutionContext context, <span class="predefined-type">String</span> key) {
<span class="keyword">return</span> context.getMergedJobDataMap().getString(key);
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This job can then be configured to run using Quartz' <code>quartz-config.xml</code> file:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="preprocessor"><?xml version="1.0" encoding="UTF-8"?></span>
<span class="tag"><job-scheduling-data</span>
<span class="attribute-name">xmlns</span>=<span class="string"><span class="delimiter">"</span><span class="content">http://www.quartz-scheduler.org/xml/JobSchedulingData</span><span class="delimiter">"</span></span>
<span class="attribute-name">xmlns:xsi</span>=<span class="string"><span class="delimiter">"</span><span class="content">http://www.w3.org/2001/XMLSchema-instance</span><span class="delimiter">"</span></span>
<span class="attribute-name">xsi:schemaLocation</span>=<span class="string"><span class="delimiter">"</span><span class="content">http://www.quartz-scheduler.org/xml/JobSchedulingData</span>
<span class="content">http://www.quartz-scheduler.org/xml/job_scheduling_data_1_8.xsd</span><span class="delimiter">"</span></span>
<span class="attribute-name">version</span>=<span class="string"><span class="delimiter">"</span><span class="content">1.8</span><span class="delimiter">"</span></span><span class="tag">></span>
<span class="tag"><schedule></span>
<span class="tag"><job></span>
<span class="tag"><name></span>BackgroundCommandExecutionJob<span class="tag"></name></span>
<span class="tag"><group></span>Isis<span class="tag"></group></span>
<span class="tag"><description></span>
Poll and execute any background actions persisted by the BackgroundActionServiceJdo domain service
<span class="tag"></description></span>
<span class="tag"><job-class></span>domainapp.webapp.quartz.BackgroundCommandExecutionQuartzJob<span class="tag"></job-class></span>
<span class="tag"><job-data-map></span>
<span class="tag"><entry></span>
<span class="tag"><key></span>webapp.scheduler.user<span class="tag"></key></span>
<span class="tag"><value></span>scheduler_user<span class="tag"></value></span>
<span class="tag"></entry></span>
<span class="tag"><entry></span>
<span class="tag"><key></span>webapp.scheduler.roles<span class="tag"></key></span>
<span class="tag"><value></span>admin_role<span class="tag"></value></span>
<span class="tag"></entry></span>
<span class="tag"></job-data-map></span>
<span class="tag"></job></span>
<span class="tag"><trigger></span>
<span class="tag"><cron></span>
<span class="tag"><name></span>BackgroundCommandExecutionJobEveryTenSeconds<span class="tag"></name></span>
<span class="tag"><job-name></span>BackgroundCommandExecutionJob<span class="tag"></job-name></span>
<span class="tag"><job-group></span>Isis<span class="tag"></job-group></span>
<span class="tag"><cron-expression></span>0/10 * * * * ?<span class="tag"></cron-expression></span>
<span class="tag"></cron></span>
<span class="tag"></trigger></span>
<span class="tag"></schedule></span>
<span class="tag"></job-scheduling-data></span></code></pre>
</div>
</div>
<div class="paragraph">
<p>The remaining two pieces of configuration are the <code>quartz.properties</code> file:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="ini">org.quartz.scheduler.instanceName = SchedulerQuartzConfigXml
org.quartz.threadPool.threadCount = 1
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
org.quartz.plugin.jobInitializer.class =org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin
org.quartz.plugin.jobInitializer.fileNames = webapp/scheduler/quartz-config.xml
org.quartz.plugin.jobInitializer.failOnFileNotFound = true</code></pre>
</div>
</div>
<div class="paragraph">
<p>and the entry in <code>web.xml</code> for the Quartz servlet:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag"><servlet></span>
<span class="tag"><servlet-name></span>QuartzInitializer<span class="tag"></servlet-name></span>
<span class="tag"><servlet-class></span>org.quartz.ee.servlet.QuartzInitializerServlet<span class="tag"></servlet-class></span>
<span class="tag"><init-param></span>
<span class="tag"><param-name></span>config-file<span class="tag"></param-name></span>
<span class="tag"><param-value></span>webapp/scheduler/quartz.properties<span class="tag"></param-value></span>
<span class="tag"></init-param></span>
<span class="tag"><init-param></span>
<span class="tag"><param-name></span>shutdown-on-unload<span class="tag"></param-name></span>
<span class="tag"><param-value></span>true<span class="tag"></param-value></span>
<span class="tag"></init-param></span>
<span class="tag"><init-param></span>
<span class="tag"><param-name></span>start-scheduler-on-load<span class="tag"></param-name></span>
<span class="tag"><param-value></span>true<span class="tag"></param-value></span>
<span class="tag"></init-param></span>
<span class="tag"><load-on-startup></span>1<span class="tag"></load-on-startup></span>
<span class="tag"></servlet></span></code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_CommandContext">4.4. <code>CommandContext</code></h3>
<div class="paragraph">
<p>The <code>CommandContext</code> service is a <a href="rgant.html#_rgant-RequestScoped">request-scoped</a> service that reifies the invocation of an action on a domain object into an object itself. This reified information is encapsulated within the <code>Command</code> object.</p>
</div>
<div class="paragraph">
<p>By default, the <code>Command</code> is held in-memory only; once the action invocation has completed, the <code>Command</code> object is gone. The optional
supporting <a href="#_rgsvc_spi_CommandService"><code>CommandService</code></a> enables the implementation of <code>Command</code> to be pluggable. With an appropriate implementation (eg as provided by the (non-ASF) <a href="http://github.com/isisaddons/isis-module-command">Isis addons' command</a> module’s <a href="#_rgsvc_spi_CommandService"><code>CommandService</code></a>) the <code>Command</code> may then be persisted.</p>
</div>
<div class="paragraph">
<p>As of <code>1.13.0-SNAPSHOT</code>, the primary use case for persistent <code>Command</code>s is in support of background commands; they
act as a parent to any background commands that can be persisted either explicitly using the
<a href="#_rgsvc_api_BackgroundService"><code>BackgroundService</code></a>, or implicitly by way of the
<a href="rgant.html#_rgant-Action_command"><code>@Action#command()</code></a> annotation.</p>
</div>
<div class="paragraph">
<p>In previous versions of the framework, persistent <code>Command</code>s also supported a number of other use cases:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>they enable profiling of the running application (which actions are invoked then most often, what is their response time)</p>
</li>
<li>
<p>if <a href="#_rgsvc_spi_PublishingService"><code>PublishingService</code></a> or
<a href="#_rgsvc_spi_PublisherService"><code>PublisherService</code></a> (<code>1.13.0-SNAPSHOT</code>) is configured, they provide better traceability
as the <code>Command</code> is also correlated with any published events, again through the unique <code>transactionId</code> GUID</p>
</li>
<li>
<p>if <a href="#_rgsvc_spi_AuditService"><code>AuditingService</code></a> or
<a href="#_rgsvc_spi_AuderService"><code>AuditerService</code></a> (<code>1.13.0-SNAPSHOT</code>) is configured, they provide better audit
information, since the <code>Command</code> (the 'cause' of an action) can be correlated to the audit records (the "effect" of
the action) through the <code>transactionId</code> GUID</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>As of <code>1.13.0-SNAPSHOT</code>, these other uses cases are now more fully supported through the
<a href="#_rgsvc_api_InteractionContext"><code>InteractionContext</code></a> service and persistent implementations of the
<code>Interaction</code> object, eg as provided by the (non-ASF)
<a href="http://github.com/isisaddons/isis-module-publishmq">Isis addons' publishmq</a> module.</p>
</div>
<div class="sect3">
<h4 id="_rgsvc_api_CommandContext_screencast">4.4.1. Screencast</h4>
<div class="paragraph">
<p>The <a href="https://www.youtube.com/watch?v=tqXUZkPB3EI">screencast</a> provides a run-through of the command (profiling) service, auditing service, publishing service. It also shows how commands can be run in the background either explicitly by scheduling through the background service or implicitly by way of a framework annotation.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Note that this screencast shows an earlier version of the <a href="ugvw.html">Wicket viewer</a> UI (specifically, pre 1.8.0).</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_api_implementation_4">4.4.2. API & Implementation</h4>
<div class="paragraph">
<p>The <code>CommandContext</code> request-scoped service defines the following very simple API:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@RequestScoped</span>
<span class="directive">public</span> <span class="type">class</span> <span class="class">CommandContext</span> {
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> Command getCommand() { ... }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This class (<code>o.a.i.applib.services.CommandContext</code>) is also the default implementation. Under normal circumstances there shouldn’t be any need to replace this implementation with another.</p>
</div>
<div class="paragraph">
<p>The <code>Command</code> type referenced above is in fact an interface, defined as:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">Command</span> <span class="directive">extends</span> HasTransactionId {
<span class="directive">public</span> <span class="directive">abstract</span> <span class="predefined-type">String</span> getUser(); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="directive">public</span> <span class="directive">abstract</span> <span class="predefined-type">Timestamp</span> getTimestamp(); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="directive">public</span> <span class="directive">abstract</span> Bookmark getTarget(); <i class="conum" data-value="3"></i><b>(3)</b>
<span class="directive">public</span> <span class="directive">abstract</span> <span class="predefined-type">String</span> getMemberIdentifier(); <i class="conum" data-value="4"></i><b>(4)</b>
<span class="directive">public</span> <span class="directive">abstract</span> <span class="predefined-type">String</span> getTargetClass(); <i class="conum" data-value="5"></i><b>(5)</b>
<span class="directive">public</span> <span class="directive">abstract</span> <span class="predefined-type">String</span> getTargetAction(); <i class="conum" data-value="6"></i><b>(6)</b>
<span class="directive">public</span> <span class="predefined-type">String</span> getArguments(); <i class="conum" data-value="7"></i><b>(7)</b>
<span class="directive">public</span> <span class="predefined-type">String</span> getMemento(); <i class="conum" data-value="8"></i><b>(8)</b>
<span class="directive">public</span> ExecuteIn getExecuteIn(); <i class="conum" data-value="9"></i><b>(9)</b>
<span class="directive">public</span> <span class="predefined-type">Executor</span> getExecutor(); <i class="conum" data-value="10"></i><b>(10)</b>
<span class="directive">public</span> Persistence getPersistence(); <i class="conum" data-value="11"></i><b>(11)</b>
<span class="directive">public</span> <span class="type">boolean</span> isPersistHint(); <i class="conum" data-value="12"></i><b>(12)</b>
<span class="directive">public</span> <span class="directive">abstract</span> <span class="predefined-type">Timestamp</span> getStartedAt(); <i class="conum" data-value="13"></i><b>(13)</b>
<span class="directive">public</span> <span class="directive">abstract</span> <span class="predefined-type">Timestamp</span> getCompletedAt(); <i class="conum" data-value="14"></i><b>(14)</b>
<span class="directive">public</span> Command getParent(); <i class="conum" data-value="15"></i><b>(15)</b>
<span class="directive">public</span> Bookmark getResult(); <i class="conum" data-value="16"></i><b>(16)</b>
<span class="directive">public</span> <span class="predefined-type">String</span> getException(); <i class="conum" data-value="17"></i><b>(17)</b>
<span class="annotation">@Deprecated</span>
<span class="type">int</span> next(<span class="directive">final</span> <span class="predefined-type">String</span> sequenceAbbr); <i class="conum" data-value="18"></i><b>(18)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td><code>getUser()</code> - is the user that initiated the action.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td><code>getTimestamp()</code> - the date/time at which this action was created.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td><code>getTarget()</code> - bookmark of the target object (entity or service) on which this action was performed</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td><code>getMemberIdentifier()</code> - holds a string representation of the invoked action</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td><code>getTargetClass()</code> - a human-friendly description of the class of the target object</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td><code>getTargetAction()</code> - a human-friendly name of the action invoked on the target object</td>
</tr>
<tr>
<td><i class="conum" data-value="7"></i><b>7</b></td>
<td><code>getArguments()</code> - a human-friendly description of the arguments with which the action was invoked</td>
</tr>
<tr>
<td><i class="conum" data-value="8"></i><b>8</b></td>
<td><code>getMemento()</code> - a formal (XML or similar) specification of the action to invoke/being invoked</td>
</tr>
<tr>
<td><i class="conum" data-value="9"></i><b>9</b></td>
<td><code>getExecuteIn()</code> - whether this command is executed in the foreground or background</td>
</tr>
<tr>
<td><i class="conum" data-value="10"></i><b>10</b></td>
<td><code>getExecutor()</code> - the (current) executor of this command, either user, or background service, or other (eg redirect after post).</td>
</tr>
<tr>
<td><i class="conum" data-value="11"></i><b>11</b></td>
<td><code>getPersistence()</code>- the policy controlling whether this command should ultimately be persisted (either "persisted", "if hinted", or "not persisted")</td>
</tr>
<tr>
<td><i class="conum" data-value="12"></i><b>12</b></td>
<td><code>isPersistHint()</code> - whether that the command should be persisted, if persistence policy is "if hinted".</td>
</tr>
<tr>
<td><i class="conum" data-value="13"></i><b>13</b></td>
<td><code>getStartedAt()</code> - the date/time at which this action started (same as <code>timestamp</code> property for foreground commands)</td>
</tr>
<tr>
<td><i class="conum" data-value="14"></i><b>14</b></td>
<td><code>getCompletedAt()</code> - the date/time at which this action completed.</td>
</tr>
<tr>
<td><i class="conum" data-value="15"></i><b>15</b></td>
<td><code>getParent()</code> - for actions created through the <code>BackgroundService</code>, captures the parent action</td>
</tr>
<tr>
<td><i class="conum" data-value="16"></i><b>16</b></td>
<td><code>getResult()</code> - bookmark to object returned by action, if any</td>
</tr>
<tr>
<td><i class="conum" data-value="17"></i><b>17</b></td>
<td><code>getException()</code> - exception stack trace if action threw exception</td>
</tr>
<tr>
<td><i class="conum" data-value="18"></i><b>18</b></td>
<td>(as of <code>1.13.0-SNAPSHOT</code>) no longer used by the framework; see instead
<a href="#_rgsvc_api_InteractionContext"><code>InteractionContext</code></a> and <code>Interaction#next()</code>.</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_usage_4">4.4.3. Usage</h4>
<div class="paragraph">
<p>The typical way to indicate that an action should be treated as a command is to annotate it with the <a href="rgant.html#_rgant-Action_command"><code>@Action#command()</code></a> annotation.</p>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">ToDoItem</span> ... {
<span class="annotation">@Action</span>(command=CommandReification.ENABLED)
<span class="directive">public</span> ToDoItem completed() { ... }
}</code></pre>
</div>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>As an alternative to annotating every action with <code>@Action#command()</code>, alternatively this can be configured as the default using <code>isis.services.command.actions</code> configuration property.</p>
</div>
<div class="paragraph">
<p>See <a href="rgant.html#_rgant-Action_command"><code>@Action#command()</code></a> and <a href="rgcfg.html#_rgcfg_configuring-core">runtime configuration</a> for further details.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The <a href="rgant.html#_rgant-Action_command"><code>@Action#command()</code></a> annotation can also be used to specify whether the command should be performed in the background, for example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">ToDoItem</span> ... {
<span class="annotation">@Command</span>(executeIn=ExecuteIn.BACKGROUND)
<span class="directive">public</span> ToDoItem scheduleImplicitly() {
completeSlowly(<span class="integer">3000</span>);
<span class="keyword">return</span> <span class="local-variable">this</span>;
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>When a background command is invoked, the user is returned the command object itself (to provide a handle to the command being invoked).</p>
</div>
<div class="paragraph">
<p>This requires that an implementation of <a href="#_rgsvc_spi_CommandService"><code>CommandService</code></a> that persists the commands (such as the (non-ASF) <a href="http://github.com/isisaddons/isis-module-command">Isis addons' command</a> module’s <code>CommandService</code>) is configured. It also requires that a scheduler is configured to execute the background commands, see <a href="#_rgsvc_spi_BackgroundCommandService"><code>BackgroundCommandService</code></a>).</p>
</div>
</div>
<div class="sect3">
<h4 id="_interacting_with_the_services">4.4.4. Interacting with the services</h4>
<div class="paragraph">
<p>Typically domain objects will have little need to interact with the <code>CommandContext</code> and <code>Command</code> directly; what is
more useful is that these are persisted in support of the various use cases identified above.</p>
</div>
<div class="paragraph">
<p>One case however where a domain object might want to obtain the <code>Command</code> is to determine whether it has been invoked in the foreground, or in the background. It can do this using the <code>getExecutedIn()</code> method:</p>
</div>
<div class="paragraph">
<p>Although not often needed, this then allows the domain object to access the <code>Command</code> object through the
<code>CommandContext</code> service. To expand th above example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">ToDoItem</span> ... {
<span class="annotation">@Action</span>(
command=CommandReification.ENABLED,
commandExecuteIn=CommandExecuteIn.BACKGROUND
)
<span class="directive">public</span> ToDoItem completed() {
...
Command currentCommand = commandContext.getCommand();
...
}
<span class="annotation">@Inject</span>
CommandContext commandContext;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>If run in the background, it might then notify the user (eg by email) if all work is done.</p>
</div>
<div class="paragraph">
<p>This leads us onto a related point, distinguishing the current effective user vs the originating "real" user. When running in the foreground, the current user can be obtained from the <a href="#_rgsvc_api_UserService"><code>UserService</code></a>, using:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="predefined-type">String</span> user = userService.getUser().getName();</code></pre>
</div>
</div>
<div class="paragraph">
<p>If running in the background, however, then the current user will be the credentials of the background process, for example as run by a Quartz scheduler job.</p>
</div>
<div class="paragraph">
<p>The domain object can still obtain the original ("effective") user that caused the job to be created, using:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="predefined-type">String</span> user = commandContext.getCommand().getUser();</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_10">4.4.5. Registering the Services</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>CommandContext</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_12">4.4.6. Related Services</h4>
<div class="paragraph">
<p>The <a href="#_rgsvc_api_CommandContext"><code>CommandContext</code></a> service is very similar in nature to the <a href="#_rgsvc_api_InteactionContext"><code>InteactionContext</code></a>, in that the
<code>Command</code> object accessed through it is very similar to the <code>Interaction</code> object obtained from the <code>InteractionContext</code>.
The principle distinction is that while <code>Command</code> represents the <em>intention</em> to invoke an action or edit a property,
the <code>Interaction</code> (and contained <code>Execution</code>s) represents the actual execution.</p>
</div>
<div class="paragraph">
<p>Most of the time a <code>Command</code> will be followed directly by its corresponding <code>Interaction</code>. However, if the <code>Command</code>
is annotated to run in the background (using <a href="rgant.html#_rgant-Action_command"><code>@Action#commandExecuteIn()</code></a>, or
is explicitly created through the <a href="#_rgsvc_api_BackgroundService"><code>BackgroundService</code></a>, then the actual
interaction/execution is deferred until some other mechanism invokes the command (eg as described
<a href="ugbtb.html#_ugbtb_headless-access_BackgroundCommandExecution">here</a>). The persistence of background commands
requires a configured <a href="#_rgsvc_spi_BackgroundCommandService"><code>BackgroundCommandService</code></a>) to actually
persist such commands for execution.</p>
</div>
<div class="paragraph">
<p><code>Command</code>s - even if executed in the foreground - can also be persisted by way of the
<a href="#_rgsvc_spi_CommandService"><code>CommandService</code></a>. Implementations of <code>CommandService</code> and
<code>BackgroundCommandService</code> are intended to go together, so that child <code>Command</code>s persistent (to be executed in the
background) can be associated with their parent <code>Command</code>s (executed in the foreground, with the background <code>Command</code>
created explicitly through the <a href="#_rgsvc_api_BackgroundService"><code>BackgroundService</code></a>).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_InteractionContext">4.5. <code>InteractionContext</code> (<code>1.13.0-SNAPSHOT</code>)</h3>
<div class="paragraph">
<p>The <code>InteractionContext</code> (<code>1.13.0-SNAPSHOT</code>) is a request-scoped domain service that is used to obtain the current
<code>Interaction</code>.</p>
</div>
<div class="paragraph">
<p>An <code>Interaction</code> generally consists of a single top-level <code>Execution</code>, either to invoke an action or to edit a
property. If that top-level action or property uses <a href="#_rgsvc_api_WrapperFactory"><code>WrapperFactory</code></a> to
invoke child actions/properties, then those sub-executions are captured as a call-graph. The <code>Execution</code> is thus a
graph structure.</p>
</div>
<div class="paragraph">
<p>If a bulk action is performed (as per an action annotated using
<a href="rgant.html#_rgant-Action_invokeOn"><code>@Action#invokeOn()</code></a>), then this will result in multiple <code>Interaction</code>s, one
per selected object (not one <code>Interaction</code> with multiple top-level <code>Execution</code>s).</p>
</div>
<div class="paragraph">
<p>It is possible for <code>Interaction.Execution</code>s to be persisted; this is supported by the (non-ASF)
<a href="http://github.com/isisaddons/isis-module-publishmq">Isis addons' publishmq</a> module, for example. Persistent
<code>Interaction</code>s support several use cases:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>they enable profiling of the running application (which actions are invoked then most often, what is their response
time)</p>
</li>
<li>
<p>if auditing is configured (using either <a href="#_rgsvc_spi_AuditingService">auditing</a> or
<a href="#_rgsvc_spi_AuditerService"><code>AuditerService</code></a>), they provide better audit information, since the
<code>Interaction.Execution</code> captures the 'cause' of an interaction and can be correlated to the audit records (the "effect"
of the interaction) by way of the <a href="rgcms.html#_rgcms_classes_mixins_HasTransactionId"><code>transactionId</code></a></p>
</li>
</ul>
</div>
<div class="sect3">
<h4 id="_api_implementation_5">4.5.1. API & Implementation</h4>
<div class="paragraph">
<p>The public API of the service consists of several related classes:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>InteractionContext</code> domain service itself:</p>
</li>
<li>
<p><code>Interaction</code> class, obtainable from the <code>InteractionContext</code></p>
</li>
<li>
<p><code>Execution</code> class, obtainable from the <code>Interaction</code>.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The <code>Execution</code> class itself is abstract; there are two subclasses, <code>ActionInvocation</code> and <code>PropertyEdit</code>.</p>
</div>
<div class="sect4">
<h5 id="__code_interactioncontext_code"><code>InteractionContext</code></h5>
<div class="paragraph">
<p>The public API of the <code>InteractionContext</code> domain service itself consists of simply:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@RequestScoped</span>
<span class="directive">public</span> <span class="type">class</span> <span class="class">InteractionContext</span> {
<span class="directive">public</span> Interaction getInteraction(); <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>Returns the currently active {@link Interaction} for this thread.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>This class is concrete (is also the implementation).</p>
</div>
</div>
<div class="sect4">
<h5 id="__code_interaction_code"><code>Interaction</code></h5>
<div class="paragraph">
<p>The public API of the <code>Interaction</code> class consists of:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">Interaction</span> {
<span class="directive">public</span> <span class="predefined-type">UUID</span> getTransactionId(); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="directive">public</span> Execution getPriorExecution(); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="directive">public</span> Execution getCurrentExecution(); <i class="conum" data-value="3"></i><b>(3)</b>
<span class="directive">public</span> <span class="predefined-type">List</span><Execution> getExecutions(); <i class="conum" data-value="4"></i><b>(4)</b>
<span class="directive">public</span> <span class="type">int</span> next(<span class="directive">final</span> <span class="predefined-type">String</span> sequenceId); <i class="conum" data-value="5"></i><b>(5)</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 unique identifier of this interaction. This will be the same value as held in <code>Command</code> (obtainable from <a href="#_rgsvc_api_CommandContext"><code>CommandContext</code></a>).</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>The member <code>Execution</code> (action invocation or property edit) that preceded the current one.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>The current execution.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>* 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.</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>Generates numbers in a named sequence. Used by the framework both to number successive interaction <code>Execution</code>s and for events published by the <a href="#_rgsvc_spi_PublisherService"><code>PublisherService</code></a>.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>This class is concrete (is also the implementation).</p>
</div>
</div>
<div class="sect4">
<h5 id="__code_interaction_execution_code"><code>Interaction.Execution</code></h5>
<div class="paragraph">
<p>The <code>Interaction.Execution</code> (static nested) class represents an action invocation/property edit as a node in a
call-stack execution graph. Sub-executions can be performed using the
<a href="#_rgsvc_api_WrapperFactory"><code>WrapperFactory</code></a>.</p>
</div>
<div class="paragraph">
<p>It has the following public API:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="directive">abstract</span> <span class="type">class</span> <span class="class">Execution</span> {
<span class="directive">public</span> Interaction getInteraction(); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="directive">public</span> InteractionType getInteractionType(); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="directive">public</span> <span class="predefined-type">String</span> getMemberIdentifier(); <i class="conum" data-value="3"></i><b>(3)</b>
<span class="directive">public</span> <span class="predefined-type">Object</span> getTarget(); <i class="conum" data-value="4"></i><b>(4)</b>
<span class="directive">public</span> <span class="predefined-type">String</span> getTargetClass(); <i class="conum" data-value="5"></i><b>(5)</b>
<span class="directive">public</span> <span class="predefined-type">String</span> getTargetMember();
<span class="directive">public</span> Execution getParent(); <i class="conum" data-value="6"></i><b>(6)</b>
<span class="directive">public</span> <span class="predefined-type">List</span><Execution> getChildren();
<span class="directive">public</span> AbstractDomainEvent getEvent(); <i class="conum" data-value="7"></i><b>(7)</b>
<span class="directive">public</span> <span class="predefined-type">Timestamp</span> getStartedAt(); <i class="conum" data-value="8"></i><b>(8)</b>
<span class="directive">public</span> <span class="predefined-type">Timestamp</span> getCompletedAt();
<span class="directive">public</span> <span class="predefined-type">Object</span> getReturned(); <i class="conum" data-value="9"></i><b>(9)</b>
<span class="directive">public</span> <span class="exception">Exception</span> getThrew();
<span class="directive">public</span> T getDto(); <i class="conum" data-value="10"></i><b>(10)</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 owning <code>Interaction</code>.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Whether this is an action invocation or a property edit.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>A string uniquely identifying the action or property (similar to Javadoc syntax).</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>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).</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>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.</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>The parent action/property that invoked this action/property edit (if any), and any actions/property edits made in
turn via the <a href="#_rgsvc_api_WrapperFactory"><code>WrapperFactory</code></a>.</td>
</tr>
<tr>
<td><i class="conum" data-value="7"></i><b>7</b></td>
<td>The domain event fired via the <a href="#_rgsvc_api_EventBusService"><code>EventBusService</code></a> representing the
execution of this action invocation/property edit.</td>
</tr>
<tr>
<td><i class="conum" data-value="8"></i><b>8</b></td>
<td>The date/time at which this execution started/completed.</td>
</tr>
<tr>
<td><i class="conum" data-value="9"></i><b>9</b></td>
<td>The object returned by the action invocation/property edit, or the exception thrown. For <code>void</code> methods and for actions returning collections, the value will be <code>null</code>.</td>
</tr>
<tr>
<td><i class="conum" data-value="10"></i><b>10</b></td>
<td>A DTO (instance of the <a href="rgcms.html#_rgcms_schema_ixn">"ixn" schema</a>) being a serializable representation of this action invocation/property edit.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>There are two concrete subclasses of <code>Execution</code>.</p>
</div>
<div class="paragraph">
<p>The first is <code>ActionInvocation</code>, representing the execution of an action being invoked:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">ActionInvocation</span> <span class="directive">extends</span> Execution {
<span class="directive">public</span> <span class="predefined-type">List</span><<span class="predefined-type">Object</span>> getArgs(); <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 objects passed in as the arguments to the action’s parameters. Any of these could be <code>null</code>.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The second is <code>PropertyEdit</code>, and naturally enough represents the execution of a property being edited:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">PropertyEdit</span> <span class="directive">extends</span> Execution {
<span class="directive">public</span> <span class="predefined-type">Object</span> getNewValue(); <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 object used as the new value of the property. Could be <code>null</code> if the property is being cleared.</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_interacting_with_the_services_2">4.5.2. Interacting with the services</h4>
<div class="paragraph">
<p>Typically domain objects will have little need to interact with the <code>InteractionContext</code> and <code>Interaction</code> directly.
The services are used within the framework however, primarily to support the
<a href="#_rgsvc_spi_PublisherService"><code>PublisherService</code></a> SPI, and to emit domain events over the
<a href="#_rgsvc_api_EventBusService"><code>EventBusService</code></a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_6">4.5.3. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' default
implementation of <code>InteractionContext</code> class is automatically registered (it is annotated with <code>@DomainService</code>)
so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>The framework also takes responsibility for instantiating the <code>Interaction</code>, using the
<a href="#_rgsvc_api_FactoryService"><code>FactoryService</code></a>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Unlike the similar <a href="#_rgsvc_api_CommandContext"><code>CommandContext</code></a> (discussed
<a href="#_rgsvc_api_InteractionContext_Related-Classes">below</a>) there is no domain service to different
implementations of <code>Interaction</code> to be used. If this were to be needed, then a custom implementation of
<a href="#_rgsvc_api_FactoryService"><code>FactoryService</code></a> could always used).</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_rgsvc_api_InteractionContext_Related-Classes">4.5.4. Related Classes</h4>
<div class="paragraph">
<p>This service is very similar in nature to <a href="#_rgsvc_api_CommandContext"><code>CommandContext</code></a>, in that the
<code>Interaction</code> object accessed through it is very similar to the <code>Command</code> object obtained from the <code>CommandContext</code>.
The principle distinction is that while <code>Command</code> represents the <em>intention</em> to invoke an action or edit a property,
the <code>Interaction</code> (and contained <code>Execution</code>s) represents the actual execution.</p>
</div>
<div class="paragraph">
<p>Most of the time a <code>Command</code> will be followed directly by its corresponding <code>Interaction</code>. However, if the <code>Command</code>
is annotated to run in the background (using <a href="rgant.html#_rgant-Action_command"><code>@Action#commandExecuteIn()</code></a>, or
is explicitly created through the <a href="#_rgsvc_api_BackgroundService"><code>BackgroundService</code></a>, then the actual
interaction/execution is deferred until some other mechanism invokes the command (eg as described
<a href="ugbtb.html#_ugbtb_headless-access_BackgroundCommandExecution">here</a>).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_MessageService">4.6. <code>MessageService</code></h3>
<div class="paragraph">
<p>The <code>MessageService</code> allows domain objects to raise information, warning or error messages. These messages can either be simple strings, or can be translated.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The methods in this service replace similar methods (now deprecated) in <a href="#_rgsvc_api_DomainObjectContainer"><code>DomainObjectContainer</code></a>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_api_and_usage">4.6.1. API and Usage</h4>
<div class="paragraph">
<p>The API of <code>MessageService</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">MessageService</span> {
<span class="type">void</span> informUser(<span class="predefined-type">String</span> message); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="predefined-type">String</span> informUser(TranslatableString message, <span class="predefined-type">Class</span><?> contextClass, <span class="predefined-type">String</span> contextMethod); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="type">void</span> warnUser(<span class="predefined-type">String</span> message); <i class="conum" data-value="3"></i><b>(3)</b>
<span class="predefined-type">String</span> warnUser(TranslatableString message, <span class="predefined-type">Class</span><?> contextClass, <span class="predefined-type">String</span> contextMethod); <i class="conum" data-value="4"></i><b>(4)</b>
<span class="type">void</span> raiseError(<span class="predefined-type">String</span> message); <i class="conum" data-value="5"></i><b>(5)</b>
<span class="predefined-type">String</span> raiseError(TranslatableString message, <span class="predefined-type">Class</span><?> contextClass, <span class="predefined-type">String</span> contextMethod); <i class="conum" data-value="6"></i><b>(6)</b>
...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>display as a transient message to the user (not requiring acknowledgement). In the <a href="ugvw.html">Wicket viewer</a> this is implemented as a toast that automatically disappears after a period of time.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>ditto, but with translatable string, for <a href="ugbtb.html#_ugbtb_i18n">i18n support</a>.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>warn the user about a situation with the specified message. In the <a href="ugvw.html">Wicket viewer</a> this is implemented as a toast that must be closed by the end-user.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>ditto, but with translatable string, for i18n support.</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>show the user an unexpected application error. In the <a href="ugvw.html">Wicket viewer</a> this is implemented as a toast (with a different colour) that must be closed by the end-user.</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>ditto, but with translatable string, for i18n support.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> Order addItem(Product product, <span class="annotation">@ParameterLayout</span>(named=<span class="string"><span class="delimiter">"</span><span class="content">Quantity</span><span class="delimiter">"</span></span>) <span class="type">int</span> quantity) {
<span class="keyword">if</span>(productRepository.stockLevel(product) == <span class="integer">0</span>) {
messageService.warnUser(
product.getDescription() + <span class="string"><span class="delimiter">"</span><span class="content"> out of stock; order fulfillment may be delayed</span><span class="delimiter">"</span></span>);
}
...
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_14">4.6.2. Implementation</h4>
<div class="paragraph">
<p>The core framework provides a default implementation of this service (<code>o.a.i.core.runtime.services.message.MessageServiceDefault</code>).</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_7">4.6.3. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>MessageService</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_SessionManagementService">4.7. <code>SessionManagementService</code></h3>
<div class="paragraph">
<p>The <code>SessionManagementService</code> provides the ability to programmatically manage sessions. The primary use case is
for fixture scripts or other routines that are invoked from the UI and which create or modify large amounts of data.
A classic example is migrating data from one system to another.</p>
</div>
<div class="sect3">
<h4 id="_api">4.7.1. API</h4>
<div class="paragraph">
<p>The API of <code>SessionManagementService</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">SessionManagementService</span> {
<span class="type">void</span> nextSession();
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Normally, the framework will automatically start a session and then a transaction before each user interaction
(action invocation or property modification), and wil then commit that transaction and close the session after the
interaction has completed. If the interaction throws an exception then the transaction is aborted.</p>
</div>
<div class="paragraph">
<p>The <code>nextSession()</code> method allows a domain object to commit the transaction, close the session, then open a new
session and start a new transaction.</p>
</div>
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Any domain objects that were created in the "previous" session are no longer usable, and must not be rendered in the UI.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_15">4.7.2. Implementation</h4>
<div class="paragraph">
<p>The core framework provides a default implementation of this service (<code>o.a.i.core.runtime.services.xactn.SessionManagementServiceDefault</code>).</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_8">4.7.3. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>SessionManagementService</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_TitleService">4.8. <code>TitleService</code></h3>
<div class="paragraph">
<p>The <code>TitleService</code> provides methods to programmatically obtain the title and icon of a domain object.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The methods in this service replace similar methods (now deprecated) in <a href="#_rgsvc_api_DomainObjectContainer"><code>DomainObjectContainer</code></a>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_api_2">4.8.1. API</h4>
<div class="paragraph">
<p>The API of <code>TitleService</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">PresentationService</span> {
<span class="predefined-type">String</span> titleOf(<span class="predefined-type">Object</span> domainObject); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="predefined-type">String</span> iconNameOf(<span class="predefined-type">Object</span> domainObject); <i class="conum" data-value="2"></i><b>(2)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>return the title of the object, as rendered in the UI by the Apache Isis viewers.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>return the icon name of the object, as rendered in the UI by the Apache Isis viewers.</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_usage_5">4.8.2. Usage</h4>
<div class="paragraph">
<p>By way of example, here’s some code based on a system for managing government benefits:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">QualifiedAdult</span> {
<span class="directive">private</span> Customer qualifying;
<span class="directive">public</span> <span class="predefined-type">String</span> title() {
<span class="keyword">return</span> <span class="string"><span class="delimiter">"</span><span class="content">QA for </span><span class="delimiter">"</span></span> + titleService.titleOf(qualifying);
}
...
<span class="annotation">@Inject</span>
TitleService titleService;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>In this example, whatever the title of a <code>Customer</code>, it is reused within the title of that customer’s <code>QualifiedAdult</code> object.</p>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_16">4.8.3. Implementation</h4>
<div class="paragraph">
<p>The core framework provides a default implementation of this service (<code>o.a.i.core.metamodel.services.title.TitleServiceDefault</code>).</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_9">4.8.4. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>TitleService</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_TransactionService">4.9. <code>TransactionService</code></h3>
<div class="paragraph">
<p>The <code>TransactionService</code> provides a small number of methods to allow domain objects to influence user transactions.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The methods in this service replace similar methods (now deprecated) in <a href="#_rgsvc_api_DomainObjectContainer"><code>DomainObjectContainer</code></a>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_api_3">4.9.1. API</h4>
<div class="paragraph">
<p>The API of <code>TransactionService</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">TransactionService</span> {
Transaction currentTransaction(); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="type">void</span> nextTransaction(); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="type">void</span> flushTransaction(); <i class="conum" data-value="3"></i><b>(3)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>to obtain a handle on the current <code>Transaction</code>, discussed further below</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>The framework automatically start a transaction before each user interaction (action invocation or property edit),
and will commit that transaction after the interaction has completed. Under certain circumstances (eg actions used to
perform data migration, say, or for large fixture scripts), it can be helpful to programmatically complete one
transaction and start another one.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>If the user interaction creates/persists an object or deletes an object (eg using the
<a href="#_rgsvc_api_RepositoryService"><code>RepositoryService</code></a>'s <code>persist()</code> or <code>delete()</code> methods), then the
framework actually queues up the work and only performs the persistence command either at the end of the transaction
or immediately prior to the next query. Performing a flush will cause any pending calls to be performed immediately.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The <code>nextTransaction()</code> is also used by the <a href="ugvw.html">Wicket viewer</a>'s support for bulk actions; each action
is invoked in its own transaction.</p>
</div>
<div class="paragraph">
<p>The <code>Transaction</code> object - as obtained by <code>currentTransaction()</code> method, above - is a minimal wrapper around the
underlying database transaction. Its API is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">Transaction</span> {
<span class="predefined-type">UUID</span> getTransactionId(); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="type">int</span> getSequence(); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="type">void</span> flush(); <i class="conum" data-value="3"></i><b>(3)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>is a unique identifier for the interaction/request, as defined by the
<a href="rgcms.html#_rgcms_classes_mixins_HasTransactionId"><code>HasTransactionId</code></a> mixin.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>there can actually be multiple transactions within such a request/interaction; the sequence is a (0-based) is used
to distinguish such.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>as per <code>TransactionService#flushTransaction()</code> described above.</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_17">4.9.2. Implementation</h4>
<div class="paragraph">
<p>The core framework provides a default implementation of this service (<code>o.a.i.core.metamodel.services.xactn.TransactionServiceDefault</code>).</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_10">4.9.3. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>TransactionService</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_WrapperFactory">4.10. <code>WrapperFactory</code></h3>
<div class="paragraph">
<p>The <code>WrapperFactory</code> provides the ability to enforce business rules for programmatic interactions between domain objects. If there is a (lack-of-) trust boundary between the caller and callee — eg if they reside in different modules — then the wrapper factory is a useful mechanism to ensure that any business constraints defined by te callee are honoured.</p>
</div>
<div class="paragraph">
<p>For example, if the calling object attempts to modify an unmodifiable property on the target object, then an exception will be thrown. Said another way: interactions are performed "as if" they are through the viewer.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>For a discussion of the use of the <code>WrapperFactory</code> within integration tests (the primary or at least original use case for this service) can be found <a href="ugtst.html#_ugtst_integ-test-support_wrapper-factory">here</a></p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>This capability goes beyond enforcing the (imperative) constraints within the <code>hideXxx()</code>, <code>disableXxx()</code> and <code>validateXxx()</code> supporting methods; it also enforces (declarative) constraints such as those represented by annotations, eg <code>@MaxLength</code> or <code>@Regex</code>.</p>
</div>
<div class="paragraph">
<p>This capability is frequently used within <a href="ugtst.html#_ugtst_integ-test-support">integration tests</a>, but can also be used in production code. (There are analogies that can be drawn here with the way that JEE beans can interact through an EJB local interface).</p>
</div>
<div class="sect3">
<h4 id="_api_4">4.10.1. API</h4>
<div class="paragraph">
<p>The API provided by the service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">WrapperFactory</span> {
<span class="annotation">@Programmatic</span>
<T> T wrap(T domainObject); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="annotation">@Programmatic</span>
<T> T unwrap(T possibleWrappedDomainObject); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="annotation">@Programmatic</span>
<T> <span class="type">boolean</span> isWrapper(T possibleWrappedDomainObject); <i class="conum" data-value="3"></i><b>(3)</b>
<span class="directive">public</span> <span class="directive">static</span> <span class="type">enum</span> ExecutionMode { <i class="conum" data-value="4"></i><b>(4)</b>
EXECUTE(<span class="predefined-constant">true</span>,<span class="predefined-constant">true</span>),
SKIP_RULES(<span class="predefined-constant">false</span>, <span class="predefined-constant">true</span>), <i class="conum" data-value="5"></i><b>(5)</b>
NO_EXECUTE(<span class="predefined-constant">true</span>, <span class="predefined-constant">false</span>); <i class="conum" data-value="6"></i><b>(6)</b>
}
<span class="annotation">@Programmatic</span>
<T> T wrap(T domainObject, ExecutionMode mode); <i class="conum" data-value="7"></i><b>(7)</b>
<span class="annotation">@Programmatic</span>
<T> T wrapNoExecute(T domainObject); <i class="conum" data-value="8"></i><b>(8)</b>
<span class="annotation">@Programmatic</span>
<T> T wrapSkipRules(T domainObject); <i class="conum" data-value="9"></i><b>(9)</b>
...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>wraps the underlying domain object. If it is already wrapped, returns the object back unchanged.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Obtains the underlying domain object, if wrapped. If the object is not wrapped, returns back unchanged.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>whether the supplied object has been wrapped.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>enumerates how the wrapper interacts with the underlying domain object.</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>validate all business rules and then execute.</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>skip all business rules and then execute (including creating <a href="rgant.html#_rgant-Action_command">command</a>s and firing pre- and post-execute <a href="rgant.html#_rgant-Action_domainEvent">domain event</a>s).</td>
</tr>
<tr>
<td><i class="conum" data-value="7"></i><b>7</b></td>
<td>validate all business rules (including those from <a href="rgant.html#_rgant-Action_domainEvent">domain event</a>s) but do not execute.</td>
</tr>
<tr>
<td><i class="conum" data-value="8"></i><b>8</b></td>
<td>convenience method to invoke <code>wrap(…​)</code> with <code>ExecuteMode#NO_EXECUTE</code> (make this feature more discoverable)</td>
</tr>
<tr>
<td><i class="conum" data-value="9"></i><b>9</b></td>
<td>convenience method to invoke <code>wrap(…​)</code> with <code>ExecuteMode#SKIP_RULES</code> (make this feature more discoverable)</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The service works by returning a "wrapper" around a supplied domain object (a <a href="http://www.javassist.org">javassist</a> proxy), and it is this wrapper that ensures that the hide/disable/validate rules implies by the Apache Isis programming model are enforced. The wrapper can be interacted with as follows:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>a <code>get…​()</code> method for properties or collections</p>
</li>
<li>
<p>a <code>set…​()</code> method for properties</p>
</li>
<li>
<p>an <code>addTo…​()</code> or <code>removeFrom…​()</code> method for collections</p>
</li>
<li>
<p>any action</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Calling any of the above methods may result in a (subclass of) <code>InteractionException</code> if the object disallows it. For example, if a property is annotated with <code>@Hidden</code> then a <code>HiddenException</code> will be thrown. Similarly if an action has a <code>validateXxx()</code> method and the supplied arguments are invalid then an <code>InvalidException</code> will be thrown.</p>
</div>
<div class="paragraph">
<p>In addition, the following methods may also be called:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>the <a href="rgcms.html#_rgcms_methods_reserved_title"><code>title()</code></a> and <code>toString()</code> methods</p>
</li>
<li>
<p>any <a href="rgcms.html#_rgcms_methods_prefixes_default"><code>default…​()</code></a>, <a href="rgcms.html#_rgcms_methods_prefixes_choices"><code>choices…​()</code></a> or <a href="rgcms.html#_rgcms_methods_prefixes_autoComplete"><code>autoComplete…​()</code></a> methods</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>An exception will be thrown if any other methods are thrown.</p>
</div>
</div>
<div class="sect3">
<h4 id="_usage_6">4.10.2. Usage</h4>
<div class="paragraph">
<p>The caller will typically obtain the target object (eg from some repository) and then use the injected <code>WrapperFactory</code> to wrap it before interacting with it.</p>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">CustomerAgent</span> {
<span class="annotation">@Action</span>
<span class="directive">public</span> <span class="type">void</span> refundOrder(<span class="directive">final</span> Order order) {
<span class="directive">final</span> Order wrappedOrder = wrapperFactory.wrap(order);
<span class="keyword">try</span> {
wrappedOrder.refund();
} <span class="keyword">catch</span>(InteractionException ex) { <i class="conum" data-value="1"></i><b>(1)</b>
container.raiseError(ex.getMessage()); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="keyword">return</span>;
}
}
...
<span class="annotation">@Inject</span>
WrapperFactory wrapperFactory;
<span class="annotation">@Inject</span>
DomainObjectContainer container;
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>if any constraints on the <code>Order’s `refund()</code> action would be violated, then …​</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>…​ these will be trapped and raised to the user as a warning.</td>
</tr>
</table>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>It ought to be possible to implement an <a href="#_rgsvc_spi_ExceptionRecognizer"><code>ExceptionRecognizer</code></a>s that would allow the above boilerplate to be removed. This recognizer service would recognize the <code>InteractionException</code> and convert to a suitable message.</p>
</div>
<div class="paragraph">
<p>At the time of writing Apache Isis does not provide an out-of-the-box implementation of such an <code>ExceptionRecognizer</code>; but it should be simple enough to write one…</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_listener_api">4.10.3. Listener API</h4>
<div class="paragraph">
<p>The <code>WrapperFactory</code> also provides a listener API to allow other services to listen in on interactions.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">WrapperFactory</span> {
...
<span class="annotation">@Programmatic</span>
<span class="predefined-type">List</span><InteractionListener> getListeners(); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <span class="type">boolean</span> addInteractionListener(InteractionListener listener); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <span class="type">boolean</span> removeInteractionListener(InteractionListener listener); <i class="conum" data-value="3"></i><b>(3)</b>
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <span class="type">void</span> notifyListeners(InteractionEvent ev); <i class="conum" data-value="4"></i><b>(4)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>all <code>InteractionListener</code>s that have been registered.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>registers an <code>InteractionListener</code>, to be notified of interactions on all wrappers. The listener will be notified of interactions even on wrappers created before the listener was installed. (From an implementation perspective this is because the wrappers delegate back to the container to fire the events).</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>remove an <code>InteractionListener</code>, to no longer be notified of interactions on wrappers.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>used by the framework itself</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The original intent of this API was to enable test transcripts to be captured (in a BDD-like fashion) from integration tests. No such feature has yet been implemented however. Also, the capabilities have by and large been superceded by Apache Isis' support for domain events. We may therefore deprecate this API in the future.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_11">4.10.4. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>WrapperFactory</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_rgsvc_application-layer-spi">5. Application Layer SPI</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Domain service SPIs influence how the framework handles application layer concerns, for example which home page to render to the end-user.</p>
</div>
<div class="paragraph">
<p>The table below summarizes the application layer SPIs defined by Apache Isis. It also lists their corresponding implementation, either a default implementation provided by Apache Isis itself, or provided by one of the in (non-ASF) <a href="http://www.isisaddons.org">Isis Addons</a> modules.</p>
</div>
<table class="tableblock frame-all grid-all spread">
<caption class="title">Table 3. Application Layer SPI</caption>
<colgroup>
<col style="width: 25%;">
<col style="width: 50%;">
<col style="width: 12.5%;">
<col style="width: 12.5%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">API</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Implementation</th>
<th class="tableblock halign-left valign-top">Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_BackgroundCommandService"><code>o.a.i.applib.</code><br>
<code>services.background</code><br>
<code>BackgroundCommandService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Persisted a memento of an action invocation such that it can be executed asynchronously ("in the background") eg by a scheduler.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>BackgroundCommandServiceJdo</code><br>
<code>o.ia.m.command</code><br>
<code>isis-module-command</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">related services:
<code>BackgroundCommandService-</code><br>
<code>JdoContributions</code>,
<code>BackgroundCommandService-</code><br>
<code>JdoRepository</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_CommandService"><code>o.a.i.applib.</code><br>
<code>services.command.spi</code><br>
<code>CommandService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Service to act as a factory and repository (create and save) of command instances, ie representations of an action invocation. Used for command/auditing and background services.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>CommandServiceJdo</code><br>
<code>o.ia.m.command</code><br>
<code>isis-module-command</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">related services:<br>
<code>CommandService-</code>
`JdoContributions`,
`CommandService-`
<code>JdoRepository</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_HomePageProviderService"><code>o.a.i.applib.</code><br>
<code>services.homepage</code><br>
<code>HomePageProviderService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Returns the home page object, if any is defined.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>HomePageProvider</code><br>
<code>ServiceDefault</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-runtime</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Used by the default implementation of <a href="#_rgsvc_spi_RoutingService"><code>RoutingService</code></a>.</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Key:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>o.a.i</code> is an abbreviation for <code>org.apache.isis</code></p>
</li>
<li>
<p><code>o.ia.m</code> is an abbreviation for <code>org.isisaddons.module</code></p>
</li>
<li>
<p><code>o.a.i.c.m.s</code> is an abbreviation for <code>org.apache.isis.core.metamodel.services</code></p>
</li>
<li>
<p><code>o.a.i.c.r.s</code> is an abbreviation for <code>org.apache.isis.core.runtime.services</code></p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_BackgroundCommandService">5.1. <code>BackgroundCommandService</code></h3>
<div class="paragraph">
<p>The <code>BackgroundCommandService</code> (SPI) service supports the <a href="#_rgsvc_api_BackgroundService"><code>BackgroundService</code></a> (API) service, persisting action invocations as commands such that they can subsequently be invoked in the background.</p>
</div>
<div class="paragraph">
<p>The <code>BackgroundService</code> is responsible for capturing a memento representing the action invocation, and then hands off to the <a href="#_rgsvc_spi_BackgroundCommandService"><code>BackgroundCommandService</code></a> <code>BackgroundCommandService</code> to actually persist it.</p>
</div>
<div class="paragraph">
<p>The persisting of commands is only half the story; there needs to be a separate process to read the commands and execute them. The abstract <a href="#_rgsvc_api_BackgroundService_BackgroundCommandExecution"><code>BackgroundCommandExecution</code></a> provides a mechanism to execute such commands. This can be considered an API, albeit "internal" because the implementation relies on internals of the framework.</p>
</div>
<div class="sect3">
<h4 id="_spi_15">5.1.1. SPI</h4>
<div class="paragraph">
<p>The SPI of the <code>BackgroundCommandService</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">BackgroundCommandService</span> {
<span class="type">void</span> schedule(
ActionInvocationMemento aim, <i class="conum" data-value="1"></i><b>(1)</b>
Command parentCommand, <i class="conum" data-value="2"></i><b>(2)</b>
<span class="predefined-type">String</span> targetClassName,
<span class="predefined-type">String</span> targetActionName,
<span class="predefined-type">String</span> targetArgs);
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>is a wrapper around a <a href="#_rgsvc_api_MementoService"><code>MementoService</code></a>'s <code>Memento</code>, capturing the details of the action invocation to be retained (eg persisted to a database) so that it can be executed at a later time</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>reference to the parent <code>Command</code> requesting the action be performed as a background command. This allows information such as the initiating user to be obtained.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The API of <code>ActionInvocationMemento</code> in turn is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">ActionInvocationMemento</span> {
<span class="directive">public</span> <span class="predefined-type">String</span> getActionId() { ... }
<span class="directive">public</span> <span class="predefined-type">String</span> getTargetClassName() { ... }
<span class="directive">public</span> <span class="predefined-type">String</span> getTargetActionName() { ... }
<span class="directive">public</span> Bookmark getTarget() { ... }
<span class="directive">public</span> <span class="type">int</span> getNumArgs() { ... }
<span class="directive">public</span> <span class="predefined-type">Class</span><?> getArgType(<span class="type">int</span> num) <span class="directive">throws</span> <span class="exception">ClassNotFoundException</span> { ... }
<span class="directive">public</span> <T> T getArg(<span class="type">int</span> num, <span class="predefined-type">Class</span><T> type) { ... }
<span class="directive">public</span> <span class="predefined-type">String</span> asMementoString() { ... } <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>lets the <code>BackgroundCommandService</code> implementation convert the action invocation into a simple string.</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="__internal_spi">5.1.2. "Internal" SPI</h4>
<div class="paragraph">
<p>The <code>BackgroundCommandExecution</code> (in isis-core) is an abstract template class for <a href="ugbtb.html#_ugbtb_headless-access_AbstractIsisSessionTemplate">headless access</a>, that defines an abstract hook method to obtain background `Command`s to be executed:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="directive">abstract</span> <span class="type">class</span> <span class="class">BackgroundCommandExecution</span>
<span class="directive">extends</span> AbstractIsisSessionTemplate {
...
protected <span class="directive">abstract</span> <span class="predefined-type">List</span><? <span class="directive">extends</span> Command> findBackgroundCommandsToExecute();
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The developer is required to implement this hook method in a subclass.</p>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_18">5.1.3. Implementation</h4>
<div class="paragraph">
<p>The (non-ASF) <a href="http://github.com/isisaddons/isis-module-command">Isis addons' command</a> module provides an implementation (<code>org.isisaddons.module.command.dom.BackgroundCommandServiceJdo</code>) that persists <code>Command</code>s using the JDO/DataNucleus object store. It further provides a number of supporting services:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>org.isisaddons.module.command.dom.BackgroundCommandServiceJdoRepository</code> is a repository to search for persisted background <code>Command</code>s</p>
</li>
<li>
<p><code>org.isisaddons.module.command.dom.BackgroundCommandServiceJdoContributions</code> contributes actions for searching for persisted child and sibling <code>Command</code>s.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The module also provides a concrete subclass of <code>BackgroundCommandExecution</code> that knows how to query for persisted (background) `Command`s such that they can be executed by a scheduler.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Details of setting up the Quartz scheduler to actually execute these persisted commands can be found on the <a href="#_rgsvc_api_BackgroundService"><code>BackgroundService</code></a> page.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_usage_7">5.1.4. Usage</h4>
<div class="paragraph">
<p>Background commands can be created either declaratively or imperatively.</p>
</div>
<div class="paragraph">
<p>The declarative approach involves annotating an action using <a href="rgant.html#_rgant-Action_command"><code>@Action#command()</code></a> with <code>@Action#commandExecuteIn=CommandExecuteIn.BACKGROUND</code>.</p>
</div>
<div class="paragraph">
<p>The imperative approach involves explicitly calling the <a href="#_rgsvc_api_BackgroundService"><code>BackgroundService</code></a> from within domain object’s action.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_11">5.1.5. Registering the Services</h4>
<div class="paragraph">
<p>The (non-ASF) <a href="http://github.com/isisaddons/isis-module-command">Isis addons' command</a> module provides an implementation
of this service (<code>BackgroundCommandService</code>), and also provides a number of related domain services
(<code>BackgroundCommandServiceJdo</code>, <code>BackgroundCommandJdoRepository</code> and <code>BackgroundCommandServiceJdoContributions</code>). This
module also provides service implementations of the
<a href="#_rgsvc_spi_CommandService"><code>CommandService</code></a>.</p>
</div>
<div class="paragraph">
<p>Assuming that an <code>AppManifest</code> is being used to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>)
then this can be activated by updating the <code>pom.xml</code> and updating the <code>AppManifest#getModules()</code> method.</p>
</div>
<div class="paragraph">
<p>If contributions are not required in the UI, these can be suppressed either using security or by implementing a
<a href="ugbtb.html#_ugbtb_decoupling_vetoing-visibility">vetoing subscriber</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_13">5.1.6. Related Services</h4>
<div class="paragraph">
<p>As discussed above, this service supports the <a href="#_rgsvc_api_BackgroundService"><code>BackgroundService</code></a> , persisting `Command`s such that they can be executed in the background.</p>
</div>
<div class="paragraph">
<p>There is also a tie-up with the <a href="#_rgsvc_api_CommandContext"><code>CommandContext</code></a> and its supporting <a href="#_rgsvc_spi_CommandService"><code>CommandService</code></a> domain service. The <code>CommandContext</code> service is responsible for providing a parent <code>Command</code> with which the background <code>Command`s can then be associated as children, while the `CommandService</code> is responsible for persisting those parent <code>Command`s (analogous to the way in which the `BackgroundCommandService</code> persists the child background <code>Command`s). The `BackgroundCommandService</code> ensures that these background <code>Command`s are associated with the parent "foreground" `Command</code>.</p>
</div>
<div class="paragraph">
<p>What that means is that the implementations of <code>CommandService</code> and <code>BackgroundCommandService</code> go together, hence both implemented in the (non-ASF) <a href="http://github.com/isisaddons/isis-module-command">Isis addons' command</a> module.).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_CommandService">5.2. <code>CommandService</code></h3>
<div class="paragraph">
<p>The <code>CommandService</code> service supports the <a href="#_rgsvc_api_CommandContext"><code>CommandContext</code></a> service such
that <code>Command</code> objects (that reify the invocation of an action/edit of a property on a domain object) can be persisted.</p>
</div>
<div class="paragraph">
<p>As of <code>1.13.0-SNAPSHOT</code>, the primary use case for persistent <code>Command</code>s is in support of background commands; they
act as a parent to any background commands that can be persisted either explicitly using the
<a href="#_rgsvc_api_BackgroundService"><code>BackgroundService</code></a>, or implicitly by way of the
<a href="rgant.html#_rgant-Action_command"><code>@Action#command()</code></a> annotation.</p>
</div>
<div class="paragraph">
<p>In previous versions of the framework, persistent <code>Command</code>s also supported a number of other use cases:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>they enable profiling of the running application (which actions are invoked then most often, what is their response time)</p>
</li>
<li>
<p>if <a href="#_rgsvc_spi_PublishingService"><code>PublishingService</code></a> or
<a href="#_rgsvc_spi_PublisherService"><code>PublisherService</code></a> (<code>1.13.0-SNAPSHOT</code>) is configured, they provide better traceability
as the <code>Command</code> is also correlated with any published events, again through the unique <code>transactionId</code> GUID</p>
</li>
<li>
<p>if <a href="#_rgsvc_spi_AuditService"><code>AuditingService</code></a> or
<a href="#_rgsvc_spi_AuderService"><code>AuditerService</code></a> (<code>1.13.0-SNAPSHOT</code>) is configured, they provide better audit
information, since the <code>Command</code> (the 'cause' of an action) can be correlated to the audit records (the "effect" of
the action) through the <code>transactionId</code> GUID</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>As of <code>1.13.0-SNAPSHOT</code>, these other uses cases are now more fully supported through the
<a href="#_rgsvc_api_InteractionContext"><code>InteractionContext</code></a> service and persistent implementations of the
<code>Interaction</code> object, eg as provided by the (non-ASF)
<a href="http://github.com/isisaddons/isis-module-publishmq">Isis addons' publishmq</a> module.</p>
</div>
<div class="sect3">
<h4 id="_screencast">5.2.1. Screencast</h4>
<div class="paragraph">
<p>The <a href="https://www.youtube.com/watch?v=tqXUZkPB3EI">screencast</a> below provides a run-through of the command (profiling) service, auditing service, publishing service. It also shows how commands can be run in the background either explicitly by scheduling through the background service or implicitly by way of a framework annotation.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Note that this screencast shows an earlier version of the <a href="ugvw.html">Wicket viewer</a> UI (specifically, pre 1.8.0).</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_spi_16">5.2.2. SPI</h4>
<div class="paragraph">
<p>The <code>CommandService</code> service defines the following very simple API:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">CommandService</span> {
Command create(); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="annotation">@Deprecated</span>
<span class="type">void</span> startTransaction(Command command, <span class="predefined-type">UUID</span> transactionId); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="type">boolean</span> persistIfPossible(Command command); <i class="conum" data-value="3"></i><b>(3)</b>
<span class="type">void</span> complete(Command command); <i class="conum" data-value="4"></i><b>(4)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Instantiate the appropriate instance of the <code>Command</code> (as defined by the
<a href="#_rgsvc_api_CommandContext"><code>CommandContext</code></a> service). Its members will be populated automatically by
the framework.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>(as of <code>1.13.0-SNAPSHOT</code>) is <strong>NO LONGER CALLED</strong> and is deprecated: the framework automatically populates the <code>Command</code>'s <code>timestamp</code>,
<code>user</code> and <code>transactionId</code> fields, so there is no need for the service implementation to initialize any of these. In
particular, the <code>Command</code> will already have been initialized with the provided <code>transactionId</code> argument.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Set the hint that the <code>Command</code> should be persisted if possible (when completed, see below).</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>"Complete" the command, typically meaning that the command should be persisted it if its <code>Command#getPersistence()</code>
flag and persistence hint (<code>Command#isPersistHint()</code>) indicate that it should be. <br></td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_19">5.2.3. Implementation</h4>
<div class="paragraph">
<p>The (non-ASF) <a href="http://github.com/isisaddons/isis-module-command">Isis addons' command</a> module provides an implementation (<code>org.isisaddons.module.command.dom.CommandServiceJdo</code>) that persists <code>Command</code>s using the JDO/DataNucleus object store. It further provides a number of supporting services:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>org.isisaddons.module.command.dom.CommandServiceJdoRepository</code> is a repository to search for persisted <code>Command</code>s</p>
</li>
<li>
<p><code>org.isisaddons.module.command.dom.CommandServiceJdoContributions</code> contributes actions for searching for persisted child and sibling <code>Command</code>s.</p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="_usage_8">5.2.4. Usage</h4>
<div class="paragraph">
<p>The typical way to indicate that an action should be reified into a <code>Command</code> is by annotating the action using <a href="rgant.html#_rgant-Action_command"><code>@Action#command()</code></a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_12">5.2.5. Registering the Services</h4>
<div class="paragraph">
<p>The (non-ASF) <a href="http://github.com/isisaddons/isis-module-command">Isis addons' command</a> module provides an implementation
of this service (<code>CommandService</code>), and also provides a number of related domain services
(<code>CommandJdoRepository</code> and <code>CommandServiceJdoContributions</code>). This
module also provides service implementations of the
<a href="#_rgsvc_spi_CommandService"><code>BackgroundCommandService</code></a>.</p>
</div>
<div class="paragraph">
<p>Assuming that an <code>AppManifest</code> is being used to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>)
then this can be activated by updating the <code>pom.xml</code> and updating the <code>AppManifest#getModules()</code> method.</p>
</div>
<div class="paragraph">
<p>If contributions are not required in the UI, these can be suppressed either using security or by implementing a
<a href="ugbtb.html#_ugbtb_decoupling_vetoing-visibility">vetoing subscriber</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_14">5.2.6. Related Services</h4>
<div class="paragraph">
<p>As discussed above, this service supports the <a href="#_rgsvc_api_CommandContext"><code>CommandContext</code></a>, providing the ability for <code>Command</code> objects to be
persisted. This is closely related to the <a href="#_rgsvc_spi_BackgroundCommandService"><code>BackgroundCommandService</code></a>that allows the <a href="#_rgsvc_api_BackgroundService"><code>BackgroundService</code></a> to schedule commands for background/asynchronous execution.</p>
</div>
<div class="paragraph">
<p>The implementations of <code>CommandService</code> and <code>BackgroundCommandService</code> are intended to go together, so that persistent parent `Command`s can be associated with their child background `Command`s.</p>
</div>
<div class="paragraph">
<p>The services provided by this module combines very well with the <a href="#<em>rgsvc_spi_AuditingService"><code>AuditingService</code></a>. The <code>CommandService</code> captures the _cause</em> of an interaction (an action was invoked, a property was edited), while the <code>AuditingService3</code> captures the <em>effect</em> of that interaction in terms of changed state.</p>
</div>
<div class="paragraph">
<p>You may also want to configure the <a href="#_rgsvc_spi_PublishingService"><code>PublishingService</code></a>.</p>
</div>
<div class="paragraph">
<p>All three of these services collaborate implicitly by way of the <a href="rgcms.html#_rgcms_classes_mixins_HasTransactionId"><code>HasTransactionId</code></a> interface.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_HomePageProviderService">5.3. <code>HomePageProviderService</code></h3>
<div class="paragraph">
<p>This service simply provides access to the home page object (if any) that is returned from the domain service
action annotated with <a href="rgant.html#_rgant-HomePage"><code>@HomePage</code></a>.</p>
</div>
<div class="paragraph">
<p>It is originally introduced to support the default implementation of
<a href="#_rgsvc_spi_RoutingService"><code>RoutingService</code></a>, but was factored out to support alternative implementations
of that service (and may be useful for other use cases).</p>
</div>
<div class="sect3">
<h4 id="_api_implementation_6">5.3.1. API & Implementation</h4>
<div class="paragraph">
<p>The API defined by <code>HomePageProviderService</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>(nature = NatureOfService.DOMAIN)
<span class="directive">public</span> <span class="type">interface</span> <span class="class">HomePageProviderService</span> {
<span class="annotation">@Programmatic</span>
<span class="predefined-type">Object</span> homePage();
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The default implementation is provided by <code>o.a.i.core.runtime.services.homepage.HomePageProviderServiceDefault</code>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_12">5.3.2. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>HomePageProviderService</code> is automatically registered (it is annotated with <code>@DomainService</code>) so no further
configuration is required.</p>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_rgsvc_core-domain-api">6. Core/Domain API</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The core/domain APIs provide general-purpose services to the domain objects, for example obtaining the current time or user, or instantiating domain objects.</p>
</div>
<div class="paragraph">
<p>The table below summarizes the core/domain APIs defined by Apache Isis. It also lists their corresponding implementation, either a default implementation provided by Apache Isis itself, or provided by one of the in (non-ASF) <a href="http://www.isisaddons.org">Isis Addons</a> modules.</p>
</div>
<table class="tableblock frame-all grid-all spread">
<caption class="title">Table 4. Core/Domain Layer API</caption>
<colgroup>
<col style="width: 25%;">
<col style="width: 50%;">
<col style="width: 12.5%;">
<col style="width: 12.5%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">API</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Implementation</th>
<th class="tableblock halign-left valign-top">Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_ClockService"><code>o.a.i.applib.</code><br>
<code>services.clock</code><br>
<code>ClockService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Access the current time (and for testing, allow the time to be changed)</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>ClockService</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-applib</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">API is also a concrete class.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_ConfigurationService"><code>o.a.i.applib.</code><br>
<code>services.config</code><br>
<code>ConfigurationService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Access configuration properties (eg from <code>isis.properties</code> file)</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>ConfigurationService-</code><br>
<code>Default</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-runtime</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The <code>ConfigurationServiceMenu</code> exposes the <code>allConfigurationProperties</code> action in the user interface.<br>
+
Supercedes methods in <a href="#_rgsvc_api_DomainObjectContainer"><code>DomainObjectContainer</code></a>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_DomainObjectContainer"><code>o.a.i.applib</code><br>
<code>DomainObjectContainer</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Miscellaneous functions, eg obtain title of object.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>DomainObjectContainer-</code><br>
<code>Default</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-metamodel</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_EventBusService"><code>o.a.i.applib.</code><br>
<code>services.eventbus</code><br>
<code>EventBusService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Programmatically post events to the internal event bus. Also used by Apache Isis itself to broadcast domain events:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="rgant.html#_rgant-Action_domainEvent"><code>Action#domainEvent()</code></a></p>
</li>
<li>
<p><a href="rgant.html#_rgant-Property_domainEvent"><code>Property#domainEvent()</code></a></p>
</li>
<li>
<p><a href="rgant.html#_rgant-Collection_domainEvent"><code>Collection#domainEvent()</code></a></p>
</li>
</ul>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>EventBusServiceJdo</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-runtime</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_FactoryService"><code>o.a.i.applib.</code><br>
<code>services.factory</code><br>
<code>FactoryService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Methods to instantiate and initialize domain objects</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>FactoryService-</code><br>
<code>Default</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-metamodel</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Supercedes methods in <a href="#_rgsvc_api_DomainObjectContainer"><code>DomainObjectContainer</code></a>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_Scratchpad"><code>o.a.i.applib.</code><br>
<code>services.scratchpad</code><br>
<code>Scratchpad</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Request-scoped service for interchanging information between and aggregating over multiple method calls; in particular for use by "bulk" actions (invoking of an action for all elements of a collection)</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Scratchpad</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-applib</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">API is also a concrete class</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_UserService"><code>o.a.i.applib.</code><br>
<code>services.xactn</code><br>
<code>UserService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Methods to access the currently-logged on user.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>UserService-</code><br>
<code>Default</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-metamodel</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Supercedes methods in <a href="#_rgsvc_api_DomainObjectContainer"><code>DomainObjectContainer</code></a>.</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Key:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>o.a.i</code> is an abbreviation for <code>org.apache.isis</code></p>
</li>
<li>
<p><code>o.ia.m</code> is an abbreviation for <code>org.isisaddons.module</code></p>
</li>
<li>
<p><code>o.a.i.c.m.s</code> is an abbreviation for <code>org.apache.isis.core.metamodel.services</code></p>
</li>
<li>
<p><code>o.a.i.c.r.s</code> is an abbreviation for <code>org.apache.isis.core.runtime.services</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>There is also a number of deprecated domain services.</p>
</div>
<table class="tableblock frame-all grid-all spread">
<caption class="title">Table 5. Deprecated Domain Services</caption>
<colgroup>
<col style="width: 25%;">
<col style="width: 25%;">
<col style="width: 25%;">
<col style="width: 25%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">API</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Implementation</th>
<th class="tableblock halign-left valign-top">Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>o.a.i.applib.</code><br>
<code>annotation</code>
<code>Bulk.InteractionContext</code></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Request-scoped access to whether action is invoked on object and/or on collection of objects</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p><code>Bulk.InteractionContext</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-applib</code></p>
</div></div></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Replaced by <a href="#_rgsvc_api_ActionInvocationContext"><code>ActionInvocationContext</code></a></p>
</div></div></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Key:</p>
</div>
<div class="paragraph">
<p>Key:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>o.a.i</code> is an abbreviation for <code>org.apache.isis</code></p>
</li>
<li>
<p><code>o.ia.m</code> is an abbreviation for <code>org.isisaddons.module</code></p>
</li>
<li>
<p><code>o.a.i.c.m.s</code> is an abbreviation for <code>org.apache.isis.core.metamodel.services</code></p>
</li>
<li>
<p><code>o.a.i.c.r.s</code> is an abbreviation for <code>org.apache.isis.core.runtime.services</code></p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_ClockService">6.1. <code>ClockService</code></h3>
<div class="paragraph">
<p>Most applications deal with dates and times in one way or another. For example, if an <code>Order</code> is placed, then the <code>Customer</code> may have 30 days to pay the <code>Invoice</code>, otherwise a penalty may be levied.</p>
</div>
<div class="paragraph">
<p>However, such date/time related functionality can quickly complicate automated testing: "today+30" will be a different value every time the test is run.</p>
</div>
<div class="paragraph">
<p>Even disregarding testing, there may be a requirement to ensure that date/times are obtained from an NNTP server (rather than the system PC). While instantiating a <code>java.util.Date</code> to current the current time is painless enough, we would not want complex technical logic for querying an NNTP server spread around domain logic code.</p>
</div>
<div class="paragraph">
<p>Therefore it’s common to provide a domain service whose responsibility is to provide the current time. This service can be injected into any domain object (and can be mocked out for unit testing). Apache Isis provides such a facade through the <code>ClockService</code>.</p>
</div>
<div class="sect3">
<h4 id="_api_implementation_7">6.1.1. API & Implementation</h4>
<div class="paragraph">
<p>The API defined by <code>ClockService</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>(nature = NatureOfService.DOMAIN)
<span class="directive">public</span> <span class="type">class</span> <span class="class">ClockService</span> {
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> LocalDate now() { ... }
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> LocalDateTime nowAsLocalDateTime() { ... }
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> DateTime nowAsDateTime() { ... }
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <span class="predefined-type">Timestamp</span> nowAsJavaSqlTimestamp() { ... }
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <span class="type">long</span> nowAsMillis() { ... }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This class (<code>o.a.i.applib.services.clock.ClockService</code>) is also the default implementation. The time provided by this default implementation is based on the system clock.</p>
</div>
</div>
<div class="sect3">
<h4 id="_testing_support">6.1.2. Testing Support</h4>
<div class="paragraph">
<p>The default <code>ClockService</code> implementation in fact simply delegates to another class defined in the API, namely the <code>o.a.i.applib.clock.Clock</code>, an abstract singleton class. It is not recommended that your code use the <code>Clock</code> directly, but you should understand how this all works:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>there are two subclasses implementations <code>Clock</code>, namely <code>SystemClock</code> and <code>FixtureClock</code>.</p>
</li>
<li>
<p>the first implementation that is instantiated registers itself as the singleton.</p>
</li>
<li>
<p>if running in <a href="rgcfg.html#_rgcfg_deployment-types">production</a> (server) mode, then (unless another implementation has beaten it to the punch) the framework will instantiate the <code>`SystemClock</code>. Once instantiated this cannot be replaced.</p>
</li>
<li>
<p>if running in <a href="rgcfg.html#<em>rgcfg_deployment-types">prototype</a> mode, then the framework will instead instantiate <code>FixtureClock</code>. This _can</em> be replaced if required.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The <code>FixtureClock</code> will behave as the system clock, unless its is explicitly set using <code>FixtureClock#setDate(…​)</code> or <code>FixtureClock#setTime(…​)</code> and so forth.</p>
</div>
<div class="sect4">
<h5 id="_alternative_implementations_2">Alternative Implementations</h5>
<div class="paragraph">
<p>Suppose you want (as discussed in the introduction to this service) to use a clock that delegates to NNTP. For most domain services this would amount to implementing the appropriate service and registering in <code>isis.properties</code> so that it is used in preference to any implementations provided by default by the framework.</p>
</div>
<div class="paragraph">
<p>In the case of the <code>ClockService</code>, though, this approach (unfortunately) will not work, because parts of Apache Isis (still) delegate to the <code>Clock</code> singleton rather than using the <code>ClockService</code> domain service.</p>
</div>
<div class="paragraph">
<p>The workaround, therefore, is to implement your functionality as a subclass of <code>Clock</code>. You can write a domain service that will ensure that your implementation is used ahead of any implementations provided by the framework.</p>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>(nature=NatureOfService.DOMAIN)
<span class="directive">public</span> <span class="type">class</span> <span class="class">NntpClockServiceInitializer</span> {
<span class="annotation">@Programmatic</span>
<span class="annotation">@PostConstruct</span>
<span class="directive">public</span> <span class="type">void</span> postConstruct(<span class="predefined-type">Map</span><<span class="predefined-type">String</span>,<span class="predefined-type">String</span>> properties) {
<span class="keyword">new</span> NntpClock(properties); <i class="conum" data-value="1"></i><b>(1)</b>
}
<span class="directive">private</span> <span class="directive">static</span> <span class="type">class</span> <span class="class">NntpClock</span> <span class="directive">extends</span> Clock {
NntpClock(<span class="predefined-type">Map</span><<span class="predefined-type">String</span>,<span class="predefined-type">String</span>> properties) { ... } <i class="conum" data-value="2"></i><b>(2)</b>
<span class="directive">protected</span> <span class="type">long</span> time() { ... } <i class="conum" data-value="3"></i><b>(3)</b>
... NNTP stuff here ...
}
}
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>enough to simply instantiate the <code>Clock</code>; it will register itself as singleton</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>connect to NNTP service using configuration properties from <code>isis.properties</code></td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>call to NNTP service here</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_13">6.1.3. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>ClockService</code> is automatically registered (it is annotated with <code>@DomainService</code>) so no further
configuration is required.</p>
</div>
<div class="paragraph">
<p>If you want to use a different implementation of <code>Clock</code>, eg delegating to NNTP, then do <em>not</em> register directly, but
instead subclass from <code>o.a.i.applib.clock.Clock</code> singleton (as described in the section above).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_ConfigurationService">6.2. <code>ConfigurationService</code></h3>
<div class="paragraph">
<p>The <code>ConfigurationService</code> allows domain objects to read the configuration properties aggregated from the various <a href="rgcfg.html#_rgcfg_configuration-files">configuration files</a>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The methods in this service replace similar methods (now deprecated) in <a href="#_rgsvc_api_DomainObjectContainer"><code>DomainObjectContainer</code></a>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_api_and_usage_2">6.2.1. API and Usage</h4>
<div class="paragraph">
<p>The API of <code>ConfigurationService</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">ConfigurationService</span> {
<span class="predefined-type">String</span> getProperty(<span class="predefined-type">String</span> name); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="predefined-type">String</span> getProperty(<span class="predefined-type">String</span> name, <span class="predefined-type">String</span> defaultValue); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="predefined-type">List</span><<span class="predefined-type">String</span>> getPropertyNames(); <i class="conum" data-value="3"></i><b>(3)</b>
<span class="predefined-type">Set</span><ConfigurationProperty> allProperties(); <i class="conum" data-value="4"></i><b>(4)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Return the configuration property with the specified name; else return null.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Return the configuration property with the specified name; if it doesn’t exist then return the specified default value.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Return the names of all the available properties.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>Returns all properties, each as an instance of the <code>ConfigurationProperty</code> view model.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>For example, here’s a fictitious service that might wrap <a href="http://twitter4j.org/en/configuration.html">Twitter4J</a>. say:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>(nature=NatureOfService.DOMAIN)
<span class="directive">public</span> <span class="type">class</span> <span class="class">TweetService</span> {
<span class="annotation">@Programmatic</span>
<span class="annotation">@PostConstruct</span>
<span class="directive">public</span> <span class="type">void</span> init() {
<span class="local-variable">this</span>.oauthConsumerKey = configurationService.getProperty(<span class="string"><span class="delimiter">"</span><span class="content">tweetservice.oauth.consumerKey</span><span class="delimiter">"</span></span>);
<span class="local-variable">this</span>.oauthConsumerSecret = configurationService.getProperty(<span class="string"><span class="delimiter">"</span><span class="content">tweetservice.oauth.consumerSecret</span><span class="delimiter">"</span></span>);
<span class="local-variable">this</span>.oauthAccessToken = configurationService.getProperty(<span class="string"><span class="delimiter">"</span><span class="content">tweetservice.oauth.accessToken</span><span class="delimiter">"</span></span>);
<span class="local-variable">this</span>.oauthAccessTokenSecret = configurationService.getProperty(<span class="string"><span class="delimiter">"</span><span class="content">tweetservice.oauth.accessTokenSecret</span><span class="delimiter">"</span></span>);
}
...
<span class="annotation">@Inject</span>
ConfigurationService configurationService;
}</code></pre>
</div>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>If you <em>do</em> have a domain service that needs to access properties, then note that an alternative is to define a <a href="rgant.html#_rgant-PostConstruct"><code>@PostConstruct</code></a> method and pass in a <code>Map<String,String></code> of properties. The two techniques are almost identical; it’s mostly a matter of taste.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_20">6.2.2. Implementation</h4>
<div class="paragraph">
<p>The core framework provides a default implementation of this service (<code>o.a.i.core.runtime.services.config.ConfigurationServiceDefault</code>).</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_14">6.2.3. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>ConfigurationService</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_15">6.2.4. Related services</h4>
<div class="paragraph">
<p>The <code>ConfigurationServiceMenu</code> exposes the <code>allConfigurationProperties</code> action in the user interface.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_DomainObjectContainer">6.3. <code>DomainObjectContainer</code></h3>
<div class="paragraph">
<p>The <code>DomainObjectContainer</code> service provides a set of general purpose functionality for domain objects to call. Principal amongst these are a generic APIs for querying objects and creating and persisting objects. In addition, the service provides access to security context (the "current user"), allows information and warning messages to be raised, and various other miscellaneous functions.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>(Almost all of) the methods in this service have been moved out into a number of more fine-grained services: <a href="#_rgsvc_api_RepositoryService"><code>RepositoryService</code></a>, <a href="#_rgsvc_api_MessageService"><code>MessageService</code></a>, <a href="#_rgsvc_api_FactoryService"><code>FactoryService</code></a>, <a href="#_rgsvc_api_TitleService"><code>TitleService</code></a>, <a href="#_rgsvc_api_ConfigurationService"><code>ConfigurationService</code></a>, <a href="#_rgsvc_api_UserService"><code>UserService</code></a> and <a href="#_rgsvc_api_ServiceRegistry"><code>ServiceRegistry</code></a>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_apis">6.3.1. APIs</h4>
<div class="paragraph">
<p>The sections below discuss the functions provided by the service, broken out into categories.</p>
</div>
<div class="sect4">
<h5 id="_rgsvc_api_DomainObjectContainer_object-creation-api">Object Creation API</h5>
<div class="paragraph">
<p>The object creation APIs are used to instantiate new domain objects or view models.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">DomainObjectContainer</span> {
<T> T newTransientInstance(<span class="directive">final</span> <span class="predefined-type">Class</span><T> ofType); <i class="conum" data-value="1"></i><b>(1)</b>
<T> T newViewModelInstance(<span class="directive">final</span> <span class="predefined-type">Class</span><T> ofType, <span class="directive">final</span> <span class="predefined-type">String</span> memento); <i class="conum" data-value="2"></i><b>(2)</b>
<T> T mixin(); <i class="conum" data-value="3"></i><b>(3)</b>
...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>create a new non-persisted domain entity. Any services will be automatically injected into the service.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>create a new view model, with the specified memento (as per <a href="rgcms.html#_rgcms_classes_super_AbstractViewModel">ViewModel#viewModelMemento()</a>. In general it is easier to just annotate with <a href="rgant.html#_rgant-ViewModel"><code>@ViewModel</code></a> and let Apache Isis manage the memento automatically.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>programmatically instantiate a mixin, as annotated with
<a href="rgant.html#_rgant-Mixin"><code>@Mixin</code></a> or <a href="rgant.html#_rgant-DomainObject_nature"><code>@DomainObject#nature()</code></a>.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Customer cust = container.newTransientInstance(Customer.class);
cust.setFirstName(<span class="string"><span class="delimiter">"</span><span class="content">Freddie</span><span class="delimiter">"</span></span>);
cust.setLastName(<span class="string"><span class="delimiter">"</span><span class="content">Mercury</span><span class="delimiter">"</span></span>);
container.persist(cust);</code></pre>
</div>
</div>
<div class="paragraph">
<p>As an alternative to using <code>newTransientInstance(…​)</code> or <code>mixin(…​)</code>, you could also simply <code>new()</code> up the object.
Doing this will not inject any domain services, but they can be injected manually using <a href="rg .html#_rgsvc_api_DomainObjectContainer_services-api">#injectServicesInto(…​)`</a>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Calling <code>new(…​)</code> also this circumvents Apache Isis' <a href="rgcms.html#_rgcms_methods_reserved_created"><code>created()</code></a>
callback, and in addition any default values for properties (either explicitly set by
<a href="rgcms.html#_rgcms_methods_prefixes_default"><code>default…​()</code></a> or defaulted implicitly according to Apache Isis'
own conventions) will not be called either. If you don’t intend to use these features, though, the net effect is code
that has less coupling to Isis and is arguably easier to understand (has "less magic" happening).</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="_rgsvc_api_DomainObjectContainer_generic-repository-api">Generic Repository API</h5>
<div class="paragraph">
<p>The repository API acts as an abstraction over the JDO/DataNucleus objectstore. You can use it during prototyping to write naive queries (find all rows, then filter using the Guava <code>Predicate</code> API, or you can use it to call JDO <a href="http://www.datanucleus.org/products/accessplatform_4_0/jdo/query.html#named">named queries</a> using JDOQL.</p>
</div>
<div class="paragraph">
<p>As an alternative, you could also use <a href="http://www.datanucleus.org/products/accessplatform_4_0/jdo/jdoql_typesafe.html">JDO typesafe queries</a> through the <a href="#_rgsvc_api_IsisJdoSupport"><code>IsisJdoSupport</code></a> service.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">DomainObjectContainer</span> {
<span class="directive">public</span> <T> <span class="predefined-type">List</span><T> allInstances(<span class="predefined-type">Class</span><T> ofType, <span class="type">long</span>... range); <i class="conum" data-value="1"></i><b>(1)</b>
<T> <span class="predefined-type">List</span><T> allMatches(<span class="predefined-type">Query</span><T> query); <i class="conum" data-value="2"></i><b>(2)</b>
<T> <span class="predefined-type">List</span><T> allMatches(<span class="predefined-type">Class</span><T> ofType, <span class="predefined-type">Predicate</span><? <span class="local-variable">super</span> T> predicate, <span class="type">long</span>... range); <i class="conum" data-value="3"></i><b>(3)</b>
<T> <span class="predefined-type">List</span><T> allMatches(<span class="predefined-type">Class</span><T> ofType, <span class="predefined-type">String</span> title, <span class="type">long</span>... range); <i class="conum" data-value="4"></i><b>(4)</b>
<T> <span class="predefined-type">List</span><T> allMatches(<span class="predefined-type">Class</span><T> ofType, T pattern, <span class="type">long</span>... range); <i class="conum" data-value="5"></i><b>(5)</b>
...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>all persisted instances of specified type. Mostly for prototyping, though can be useful to obtain all instances of domain entities if the number is known to be small. The optional varargs parameters are for paging control; more on this below.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>all persistence instances matching the specified <code>Query</code>. Query itself is an Isis abstraction on top of JDO/DataNucleus' Query API. <strong>This is the primary API used for querying</strong></td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>all persistenced instances of specified type matching <code>Predicate</code>. Only really intended for prototyping because in effect constitutes a client-side WHERE clause</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>all persisted instances with the specified string as their title. Only very occasionally used</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>all persisted instances matching object (query-by-example). Only very occasionally used</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>There are various implementations of the <code>Query</code> API, but these either duplicate functionality of the other overloads of <code>allMatches(…​)</code> or they are not supported by the JDO/DataNucleus object store. The only significant implementation of <code>Query</code> to be aware of is <code>QueryDefault</code>, which identifies a named query and a set of parameter/argument tuples.</p>
</div>
<div class="paragraph">
<p>For example, in the (non-ASF) <a href="http://github.com/isisaddons/isis-app-todoapp">Isis addons' todoapp</a> the <code>ToDoItem</code> is annotated:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@javax</span>.jdo.annotations.Queries( {
<span class="annotation">@javax</span>.jdo.annotations.Query(
name = <span class="string"><span class="delimiter">"</span><span class="content">findByAtPathAndComplete</span><span class="delimiter">"</span></span>, language = <span class="string"><span class="delimiter">"</span><span class="content">JDOQL</span><span class="delimiter">"</span></span>, <i class="conum" data-value="1"></i><b>(1)</b>
value = <span class="string"><span class="delimiter">"</span><span class="content">SELECT </span><span class="delimiter">"</span></span>
+ <span class="string"><span class="delimiter">"</span><span class="content">FROM todoapp.dom.module.todoitem.ToDoItem </span><span class="delimiter">"</span></span>
+ <span class="string"><span class="delimiter">"</span><span class="content">WHERE atPath.indexOf(:atPath) == 0 </span><span class="delimiter">"</span></span> <i class="conum" data-value="2"></i><b>(2)</b>
+ <span class="string"><span class="delimiter">"</span><span class="content"> && complete == :complete</span><span class="delimiter">"</span></span>), <i class="conum" data-value="3"></i><b>(3)</b>
...
})
<span class="directive">public</span> <span class="type">class</span> <span class="class">ToDoItem</span> ... {
...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>name of the query</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>defines the <code>atPath</code> parameter</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>defines the <code>complete</code> parameter</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>This JDO query definitions are used in the <code>ToDoItemRepositoryImplUsingJdoql</code> service:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>(nature = NatureOfService.DOMAIN)
<span class="directive">public</span> <span class="type">class</span> <span class="class">ToDoItemRepositoryImplUsingJdoql</span> <span class="directive">implements</span> ToDoItemRepositoryImpl {
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <span class="predefined-type">List</span><ToDoItem> findByAtPathAndCategory(<span class="directive">final</span> <span class="predefined-type">String</span> atPath, <span class="directive">final</span> Category category) {
<span class="keyword">return</span> container.allMatches(
<span class="keyword">new</span> QueryDefault<>(ToDoItem.class,
<span class="string"><span class="delimiter">"</span><span class="content">findByAtPathAndCategory</span><span class="delimiter">"</span></span>, <i class="conum" data-value="1"></i><b>(1)</b>
<span class="string"><span class="delimiter">"</span><span class="content">atPath</span><span class="delimiter">"</span></span>, atPath, <i class="conum" data-value="2"></i><b>(2)</b>
<span class="string"><span class="delimiter">"</span><span class="content">category</span><span class="delimiter">"</span></span>, category)); <i class="conum" data-value="3"></i><b>(3)</b>
}
...
<span class="annotation">@javax</span>.inject.Inject
DomainObjectContainer container;
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>corresponds to the "findByAtPathAndCategory" JDO named query</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>provide argument for the <code>atPath</code> parameter. The pattern is parameter, argument, parameter, argument, …​ and so on.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>provide argument for the <code>category</code> parameter. The pattern is parameter, argument, parameter, argument, …​ and so on.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Other JDOQL named queries (not shown) follow the exact same pattern.</p>
</div>
<div class="paragraph">
<p>With respect to the other query APIs, the varargs parameters are optional, but allow for (client-side and managed) paging. The first parameter is the <code>start</code> (0-based, the second is the <code>count</code>.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>It is also possible to query using DataNucleus' type-safe query API. For more details, see <a href="#_rgsvc_api_IsisJdoSupport"><code>IsisJdoSupport</code></a>.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="_rgsvc_api_DomainObjectContainer_object-persistence-api">Object Persistence API</h5>
<div class="paragraph">
<p>The persistence API is used to persist newly created objects (as per <a href="#_rgsvc_api_DomainObjectContainer_object-creation-api"><code>#newTransientInstance(…​)</code></a>, above and to delete (remove) objects that are persistent.</p>
</div>
<div class="paragraph">
<p>Note that there is no API for updating existing objects; the framework (or rather, JDO/DataNucleus) performs object dirty tracking and so any objects that are modified in the course of a request will be automatically updated).</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">DomainObjectContainer</span> {
<span class="type">boolean</span> isPersistent(<span class="predefined-type">Object</span> domainObject); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="type">boolean</span> isViewModel(<span class="predefined-type">Object</span> domainObject); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="type">void</span> persist(<span class="predefined-type">Object</span> domainObject); <i class="conum" data-value="3"></i><b>(3)</b>
<span class="type">void</span> persistIfNotAlready(<span class="predefined-type">Object</span> domainObject); <i class="conum" data-value="4"></i><b>(4)</b>
<span class="type">void</span> remove(<span class="predefined-type">Object</span> persistentDomainObject); <i class="conum" data-value="5"></i><b>(5)</b>
<span class="type">void</span> removeIfNotAlready(<span class="predefined-type">Object</span> domainObject); <i class="conum" data-value="6"></i><b>(6)</b>
<span class="type">boolean</span> flush(); <i class="conum" data-value="7"></i><b>(7)</b>
...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>test whether a particular domain object is persistent or not.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>test whether a particular domain object is a view model or not. Note that this includes any domain objects annotated with <a href="rgant.html#_rgant-DomainObject_nature"><code>@DomainObject#nature=Nature.EXTERNAL_ENTITY)</code></a> or <a href="rgant.html#_rgant-DomainObject_nature"><code>@DomainObject#nature=Nature.INMEMORY_ENTITY</code></a></td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>persist a transient object. Note though that this will throw an exception if the object is already persistent; this can happen if JDO/DataNucleus’s <a href="http://www.datanucleus.org/products/accessplatform_4_0/jdo/orm/cascading.html">persistence-by-reachability</a> is in effect. For this reason it is generally better to use <code>persistIfNotAlready(…​)</code>. Also note that <code>persist(…​)</code> has been deprecate. When moving to <a href="rgsvc_api_RepositoryService.html#_rgsvc_api_RepositoryService"><code>RepositoryService#persist()</code></a> take into account that its behavior is identical to <4>, being a no-op if the object is persistent, instead of throwing an exception.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>persist an object but only if know to not have been persistent. But if the object is persistent, is a no-op</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>remove (ie DELETE) a persistent object. For similar reasons to the persistence, it is generally better to use:</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>remove (ie DELETE) an object only if known to be persistent. But if the object has already been deleted, then is a no-op.</td>
</tr>
<tr>
<td><i class="conum" data-value="7"></i><b>7</b></td>
<td>flushes all pending changes to the objectstore. Explained further below.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Customer cust = container.newTransientInstance(Customer.class);
cust.setFirstName(<span class="string"><span class="delimiter">"</span><span class="content">Freddie</span><span class="delimiter">"</span></span>);
cust.setLastName(<span class="string"><span class="delimiter">"</span><span class="content">Mercury</span><span class="delimiter">"</span></span>);
container.persistIfNotAlready(cust);</code></pre>
</div>
</div>
<div class="paragraph">
<p>You should be aware that by default Apache Isis queues up calls to <code>#persist()</code> and <code>#remove()</code>. These are then executed either when the request completes (and the transaction commits), or if the queue is flushed. This can be done either implicitly by the framework, or as the result of a direct call to <code>#flush()</code>.</p>
</div>
<div class="paragraph">
<p>By default the framework itself will cause <code>#flush()</code> to be called whenever a query is executed by way of <code>#allMatches(Query)</code>, as documented <a href="#_rgsvc_api_DomainObjectContainer_generic-repository-api">above</a>. However, this behaviour can be disabled using the <a href="rgcfg.html#_rgcfg_configuring-core">configuration property</a> <code>isis.services.container.disableAutoFlush</code>.</p>
</div>
</div>
<div class="sect4">
<h5 id="_rgsvc_api_DomainObjectContainer_messages-api">Messages API</h5>
<div class="paragraph">
<p>The <code>DomainObjectContainer</code> allows domain objects to raise information, warning or error messages. These messages can either be simple strings, or can be translated.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">DomainObjectContainer</span> {
<span class="type">void</span> informUser(<span class="predefined-type">String</span> message); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="predefined-type">String</span> informUser(TranslatableString message, <span class="predefined-type">Class</span><?> contextClass, <span class="predefined-type">String</span> contextMethod); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="type">void</span> warnUser(<span class="predefined-type">String</span> message); <i class="conum" data-value="3"></i><b>(3)</b>
<span class="predefined-type">String</span> warnUser(TranslatableString message, <span class="predefined-type">Class</span><?> contextClass, <span class="predefined-type">String</span> contextMethod); <i class="conum" data-value="4"></i><b>(4)</b>
<span class="type">void</span> raiseError(<span class="predefined-type">String</span> message); <i class="conum" data-value="5"></i><b>(5)</b>
<span class="predefined-type">String</span> raiseError(TranslatableString message, <span class="predefined-type">Class</span><?> contextClass, <span class="predefined-type">String</span> contextMethod); <i class="conum" data-value="6"></i><b>(6)</b>
...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>display as a transient message to the user (not requiring acknowledgement). In the <a href="ugvw.html">Wicket viewer</a> this is implemented as a toast that automatically disappears after a period of time.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>ditto, but with translatable string, for <a href="ugbtb.html#_ugbtb_i18n">i18n support</a>.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>warn the user about a situation with the specified message. In the <a href="ugvw.html">Wicket viewer</a> this is implemented as a toast that must be closed by the end-user.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>ditto, but with translatable string, for i18n support.</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>show the user an unexpected application error. In the <a href="ugvw.html">Wicket viewer</a> this is implemented as a toast (with a different colour) that must be closed by the end-user.</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>ditto, but with translatable string, for i18n support.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> Order addItem(Product product, <span class="annotation">@ParameterLayout</span>(named=<span class="string"><span class="delimiter">"</span><span class="content">Quantity</span><span class="delimiter">"</span></span>) <span class="type">int</span> quantity) {
<span class="keyword">if</span>(productRepository.stockLevel(product) == <span class="integer">0</span>) {
container.warnUser(
product.getDescription() + <span class="string"><span class="delimiter">"</span><span class="content"> out of stock; order fulfillment may be delayed</span><span class="delimiter">"</span></span>);
}
...
}</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="_rgsvc_api_DomainObjectContainer_security-api">Security API</h5>
<div class="paragraph">
<p>The security API allows the domain object to obtain the identity of the user interacting with said object.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">DomainObjectContainer</span> {
UserMemento getUser();
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>where in turn (the essence of) <code>UserMemento</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="directive">final</span> <span class="type">class</span> <span class="class">UserMemento</span> {
<span class="directive">public</span> <span class="predefined-type">String</span> getName() { ... }
<span class="directive">public</span> <span class="type">boolean</span> isCurrentUser(<span class="directive">final</span> <span class="predefined-type">String</span> userName) { ... }
<span class="directive">public</span> <span class="predefined-type">List</span><RoleMemento> getRoles() { ... }
<span class="directive">public</span> <span class="type">boolean</span> hasRole(<span class="directive">final</span> RoleMemento role) { ... }
<span class="directive">public</span> <span class="type">boolean</span> hasRole(<span class="directive">final</span> <span class="predefined-type">String</span> roleName) { ... }
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>and <code>RoleMemento</code> is simpler still:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="directive">final</span> <span class="type">class</span> <span class="class">RoleMemento</span> {
<span class="directive">public</span> <span class="predefined-type">String</span> getName() { ... }
<span class="directive">public</span> <span class="predefined-type">String</span> getDescription() { ... }
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The roles associated with the <code>UserMemento</code> will be based on the configured <a href="ugsec.html">security</a> (typically Shiro).</p>
</div>
<div class="paragraph">
<p>In addition, when using the <a href="ugvw.html">Wicket viewer</a> there will be an additional "org.apache.isis.viewer.wicket.roles.USER" role; this is used internally to restrict access to web pages without authenticating.</p>
</div>
</div>
<div class="sect4">
<h5 id="_rgsvc_api_DomainObjectContainer_presentation-api">Presentation API</h5>
<div class="paragraph">
<p>A responsibility of every domain object is to return a title. This can be done declaratively using the <a href="rgant.html#_rgant-Title"><code>@Title</code></a> annotation on property/ies, or it can be done imperatively by writing a <a href="rgcms.html#_rgcms_methods_reserved_title"><code>title()</code></a> method.</p>
</div>
<div class="paragraph">
<p>It’s quite common for titles to be built up of the titles of other objects. If using building up the title using <code>@Title</code> then Apache Isis will automatically use the title of the objects referenced by the annotated properties. We also need programmatic access to these titles if going the imperative route.</p>
</div>
<div class="paragraph">
<p>Similarly, it often makes sense if <a href="#_rgsvc_api_DomainObjectContainer_messages-api">raising messages</a> to use the title of an object in a message rather (than a some other property of the object), because this is how end-users will be used to identifying the object.</p>
</div>
<div class="paragraph">
<p>The API defined by <code>DomainObjectContainer</code> is simply:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">DomainObjectContainer</span> {
<span class="predefined-type">String</span> titleOf(<span class="predefined-type">Object</span> domainObject); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="predefined-type">String</span> iconNameOf(<span class="predefined-type">Object</span> domainObject); <i class="conum" data-value="2"></i><b>(2)</b>
...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>return the title of the object, as rendered in the UI by the Apache Isis viewers.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>return the icon name of the object, as rendered in the UI by the Apache Isis viewers.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>By way of example, here’s some code from the (non-ASF) <a href="http://github.com/isisaddons/isis-app-todoapp">Isis addons' todoapp</a> showing the use of the API in an message:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"> <span class="directive">public</span> <span class="predefined-type">List</span><ToDoItem> delete() {
<span class="directive">final</span> <span class="predefined-type">String</span> title = container.titleOf(<span class="local-variable">this</span>); <i class="conum" data-value="1"></i><b>(1)</b>
...
container.removeIfNotAlready(<span class="local-variable">this</span>);
container.informUser(
TranslatableString.tr(
<span class="string"><span class="delimiter">"</span><span class="content">Deleted {title}</span><span class="delimiter">"</span></span>, <span class="string"><span class="delimiter">"</span><span class="content">title</span><span class="delimiter">"</span></span>, title), <i class="conum" data-value="2"></i><b>(2)</b>
<span class="local-variable">this</span>.getClass(), <span class="string"><span class="delimiter">"</span><span class="content">delete</span><span class="delimiter">"</span></span>);
...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>the title is obtained first, because we’re not allowed to reference object after it’s been deleted</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>use the title in an i18n <code>TranslatableString</code></td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="_rgsvc_api_DomainObjectContainer_properties-api">Properties API</h5>
<div class="paragraph">
<p>The properties API allows domain objects to read the configuration properties aggregated from the various <a href="rgcfg.html#_rgcfg_configuration-files">configuration files</a>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">DomainObjectContainer</span> {
<span class="predefined-type">String</span> getProperty(<span class="predefined-type">String</span> name); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="predefined-type">String</span> getProperty(<span class="predefined-type">String</span> name, <span class="predefined-type">String</span> defaultValue); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="predefined-type">List</span><<span class="predefined-type">String</span>> getPropertyNames(); <i class="conum" data-value="3"></i><b>(3)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Return the configuration property with the specified name; else return null.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Return the configuration property with the specified name; if it doesn’t exist then return the specified default value.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Return the names of all the available properties.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>For example, here’s a fictitious service that might wrap <a href="http://twitter4j.org/en/configuration.html">Twitter4J</a>. say:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>(nature=NatureOfService.DOMAIN)
<span class="directive">public</span> <span class="type">class</span> <span class="class">TweetService</span> {
<span class="annotation">@Programmatic</span>
<span class="annotation">@PostConstruct</span>
<span class="directive">public</span> <span class="type">void</span> init() {
<span class="local-variable">this</span>.oauthConsumerKey = container.getProperty(<span class="string"><span class="delimiter">"</span><span class="content">tweetservice.oauth.consumerKey</span><span class="delimiter">"</span></span>);
<span class="local-variable">this</span>.oauthConsumerSecret = container.getProperty(<span class="string"><span class="delimiter">"</span><span class="content">tweetservice.oauth.consumerSecret</span><span class="delimiter">"</span></span>);
<span class="local-variable">this</span>.oauthAccessToken = container.getProperty(<span class="string"><span class="delimiter">"</span><span class="content">tweetservice.oauth.accessToken</span><span class="delimiter">"</span></span>);
<span class="local-variable">this</span>.oauthAccessTokenSecret = container.getProperty(<span class="string"><span class="delimiter">"</span><span class="content">tweetservice.oauth.accessTokenSecret</span><span class="delimiter">"</span></span>);
}
...
<span class="annotation">@Inject</span>
DomainObjectContainer container;
}</code></pre>
</div>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>If you <em>do</em> have a domain service that needs to access properties, then note that an alternative is to define a <a href="rgant.html#_rgant-PostConstruct"><code>@PostConstruct</code></a> method and pass in a <code>Map<String,String></code> of properties. The two techniques are almost identical; it’s mostly a matter of taste.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="_rgsvc_api_DomainObjectContainer_services-api">Services API</h5>
<div class="paragraph">
<p>The services API allows your domain objects to programmatically inject services into arbitrary objects, as well as to look up services by type.</p>
</div>
<div class="paragraph">
<p>The methods are:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">DomainObjectContainer</span> {
<T> T injectServicesInto(<span class="directive">final</span> T domainObject); <i class="conum" data-value="1"></i><b>(1)</b>
<T> T lookupService(<span class="predefined-type">Class</span><T> service); <i class="conum" data-value="2"></i><b>(2)</b>
<T> <span class="predefined-type">Iterable</span><T> lookupServices(<span class="predefined-type">Class</span><T> service); <i class="conum" data-value="3"></i><b>(3)</b>
...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>injects services into domain object; used extensively internally by the framework (eg to inject to other services, or to entities, or integration test instances, or fixture scripts). Service injection is done automatically if objects are created using <code>#newTransientInstance()</code>, described <a href="#_rgsvc_api_DomainObjectContainer_object-creation-api">above</a></td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>returns the first registered service that implements the specified class</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>returns an <code>Iterable</code> in order to iterate over all registered services that implement the specified class</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The primary use case is to instantiate domain objects using a regular constructor ("new is the new new") rather than using the <a href="#_rgsvc_api_DomainObjectContainer_object-creation-api"><code>#newTransientInstance()</code></a> API, and then using the <code>#injectServicesInto(…​)</code> API to set up any dependencies.</p>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Customer cust = container.injectServicesInto( <span class="keyword">new</span> Customer());
cust.setFirstName(<span class="string"><span class="delimiter">"</span><span class="content">Freddie</span><span class="delimiter">"</span></span>);
cust.setLastName(<span class="string"><span class="delimiter">"</span><span class="content">Mercury</span><span class="delimiter">"</span></span>);
container.persist(cust);</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="_rgsvc_api_DomainObjectContainer_validation-api">Validation API</h5>
<div class="paragraph">
<p>The intent of this API is to provide a mechanism where an object can programmatically check the state any class
invariants. Specifically, this means the validating the current state of all properties, as well as any object-level
validation defined by <a href="rgcms.html#_rgcms_methods_reserved_validate"><code>validate()</code></a>.</p>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<i class="fa icon-warning" title="Warning"></i>
</td>
<td class="content">
<div class="paragraph">
<p>These methods have been deprecated; this feature should be considered experimental and your mileage may vary.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The API provided is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">DomainObjectContainer</span> {
<span class="type">boolean</span> isValid(<span class="predefined-type">Object</span> domainObject);
<span class="predefined-type">String</span> validate(<span class="predefined-type">Object</span> domainObject);
...
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_21">6.3.2. Implementation</h4>
<div class="paragraph">
<p>The core framework provides a default implementation of this service (<code>o.a.i.core.metamodel.services.container.DomainObjectContainerDefault</code>).</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_15">6.3.3. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>DomainObjectContainer</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_EventBusService">6.4. <code>EventBusService</code></h3>
<div class="paragraph">
<p>The <code>EventBusService</code> allows domain objects to emit events to subscribing domain services using an in-memory event bus.</p>
</div>
<div class="paragraph">
<p>The primary user of the service is the framework itself, which automatically emit events for <a href="rgant.html#_rgant-Action_domainEvent">actions</a>, <a href="rgant.html#_rgant-Property_domainEvent">properties</a> and <a href="rgant.html#_rgant-Collection_domainEvent">collections</a>. Multiple events are generated:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>when an object member is to be viewed, an event is fired; subscribers can veto (meaning that the member is hidden)</p>
</li>
<li>
<p>when an object member is to be enabled, the same event instance is fired; subscribers can veto (meaning that the member is disabled, ie cannot be edited/invoked)</p>
</li>
<li>
<p>when an object member is being validated, then a new event instance is fired; subscribers can veto (meaning that the candidate values/action arguments are rejected)</p>
</li>
<li>
<p>when an object member is about to be changed, then the same event instance is fired; subscribers can perform pre-execution operations</p>
</li>
<li>
<p>when an object member has been changed, then the same event instance is fired; subscribers can perform post-execution operations</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>If a subscriber throws an exception in the first three steps, then the interaction is vetoed. If a subscriber throws an exception in the last two steps, then the transaction is aborted. For more on this topic, see <a href="rgant.html#_rgant-Action_domainEvent"><code>@Action#domainEvent()</code></a>, <a href="rgant.html#_rgant-Property_domainEvent"><code>@Property#domainEvent()</code></a> and <a href="rgant.html#_rgant-Collection_domainEvent"><code>@Collection#domainEvent()</code></a>.</p>
</div>
<div class="paragraph">
<p>It is also possible for domain objects to programmatically generate domain events. However the events are published, the primary use case is to decoupling interactions from one module/package/namespace and another.</p>
</div>
<div class="paragraph">
<p>Two implementations are available, using either <a href="https://code.google.com/p/guava-libraries/">Guava</a>'s <a href="https://code.google.com/p/guava-libraries/wiki/EventBusExplained"><code>EventBus</code></a>, or alternatively using the <a href="http://www.axonframework.org/">AxonFramework</a>'s <a href="http://www.axonframework.org/docs/2.4/single.html#d5e1489">SimpleEventBus</a>. It is also possible to plug in a custom implementation.</p>
</div>
<div class="sect3">
<h4 id="_rgsvc_api_EventBusService_api-and-implementation">6.4.1. API & Implementation</h4>
<div class="paragraph">
<p>The API defined by <code>EventBusService</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="directive">abstract</span> <span class="type">class</span> <span class="class">EventBusService</span> {
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <span class="type">void</span> post(<span class="predefined-type">Object</span> event) { ... } <i class="conum" data-value="1"></i><b>(1)</b>
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <span class="type">void</span> register(<span class="directive">final</span> <span class="predefined-type">Object</span> domainService) { ... } <i class="conum" data-value="2"></i><b>(2)</b>
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <span class="type">void</span> unregister(<span class="directive">final</span> <span class="predefined-type">Object</span> domainService) { ... } <i class="conum" data-value="3"></i><b>(3)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>posts the event onto event bus</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>allows domain services to register themselves. This should be done in their <a href="rgant.html#_rgant-PostConstruct"><code>@PostConstruct</code></a> initialization method (for both singleton and <a href="rgant.html#_rgant-RequestScoped"><code>@RequestScoped</code></a> domain services.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>exists for symmetry, but need never be called (it is in fact deliberately a no-op).</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Isis provides a default implementation of the service, <code>o.a.i.objectstore.jdo.datanucleus.service.eventbus.EventBusServiceJdo</code>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_subscribers">6.4.2. Registering Subscribers</h4>
<div class="paragraph">
<p>The <code>register()</code> method should be called in the <a href="rgant.html#_rgant-PostConstruct"><code>@PostConstruct</code></a> lifecycle method. It is valid and probably the least confusing to readers to also "unregister" in the <a href="rgant.html#_rgant-PreDestroy"><code>@PreDestroy</code></a> lifecycle method (though as noted <a href="#_rgsvc_api_EventBusService_api-and-implementation">above</a>, unregistering is actually a no-op).</p>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>(nature=NatureOfService.DOMAIN) <i class="conum" data-value="1"></i><b>(1)</b>
<span class="annotation">@DomainServiceLayout</span>( menuOrder=<span class="string"><span class="delimiter">"</span><span class="content">1</span><span class="delimiter">"</span></span>) <i class="conum" data-value="2"></i><b>(2)</b>
<span class="directive">public</span> <span class="type">class</span> <span class="class">MySubscribingDomainService</span> {
<span class="annotation">@PostConstruct</span>
<span class="directive">public</span> <span class="type">void</span> postConstruct() {
eventBusService.register(<span class="local-variable">this</span>); <i class="conum" data-value="3"></i><b>(3)</b>
}
<span class="annotation">@PreDestroy</span>
<span class="directive">public</span> <span class="type">void</span> preDestroy() {
eventBusService.unregister(<span class="local-variable">this</span>); <i class="conum" data-value="4"></i><b>(4)</b>
}
...
<span class="annotation">@javax</span>.inject.Inject
EventBusService eventBusService;
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>subscribers are typically not visible in the UI, so specify a <code>DOMAIN</code> nature</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>It’s important that subscribers register before any domain services that might emit events on the event bus service.
For example, the (non-ASF) <a href="http://github.com/isisaddons/isis-module-security">Isis addons' security</a> module provides a
domain service that automatically seeds certain domain entities; these will generate
<a href="rgcms.html#_rgcms_classes_lifecycleevent">lifecycle events</a> and so any subscribers must be registered before such seed
services. The easiest way to do this is to use the <a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> attribute.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>register with the event bus service during <a href="rgant.html#_rgant-PostConstruct"><code>@PostConstruct</code></a>
initialization</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>corresponding deregister when shutting down</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>This works for both singleton (application-scoped) and also <a href="rgant.html#_rgant-RequestScoped"><code>@RequestScoped</code></a> domain services.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The <a href="rgcms.html#_rgcms_classes_super_AbstractSubscriber"><code>AbstractSubscriber</code></a> class automatically performs this
registration. As a convenience, it is also annotated with the
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> attribute.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_annotating_members">6.4.3. Annotating Members</h4>
<div class="paragraph">
<p>As discussed in the introduction, the framework will automatically emit domain events for all of the object members (actions, properties or collections) of an object whenever that object is rendered or (more generally) interacted with.</p>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">Customer</span> {
<span class="annotation">@Action</span>
<span class="directive">public</span> Customer placeOrder(Product product, <span class="annotation">@ParameterLayout</span>(named=<span class="string"><span class="delimiter">"</span><span class="content">Quantity</span><span class="delimiter">"</span></span>) <span class="type">int</span> qty) { ... }
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>will propagate an instance of the default <code>o.a.i.applib.services.eventbus.ActionDomainEvent.Default</code> class. If using the Guava event bus this can be subscribed to using:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>(nature=NatureOfService.DOMAIN)
<span class="directive">public</span> <span class="type">class</span> <span class="class">MySubscribingDomainService</span>
<span class="annotation">@Programmatic</span>
<span class="annotation">@com</span>.google.common.eventbus.Subscribe
<span class="directive">public</span> <span class="type">void</span> on(ActionDomainEvent ev) { ... }
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>or if using Axonframework, the subscriber uses a different annotation:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>(nature=NatureOfService.DOMAIN)
<span class="directive">public</span> <span class="type">class</span> <span class="class">MySubscribingDomainService</span>
<span class="annotation">@Programmatic</span>
<span class="annotation">@org</span>.axonframework.eventhandling.annotation.EventHandle
<span class="directive">public</span> <span class="type">void</span> on(ActionDomainEvent ev) { ... }
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>More commonly though you will probably want to emit domain events of a specific subtype. As a slightly more interesting example, suppose in a library domain that a <code>LibraryMember</code> wants to leave the library. A letter should be sent out detailing any books that they still have out on loan:</p>
</div>
<div class="paragraph">
<p>In the <code>LibraryMember</code> class, we publish the event by way of an annotation:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">LibraryMember</span> {
<span class="annotation">@Action</span>(domainEvent=LibraryMemberLeaveEvent.class) <i class="conum" data-value="1"></i><b>(1)</b>
<span class="directive">public</span> <span class="type">void</span> leave() { ... }
...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td><code>LibraryMemberLeaveEvent</code> is a subclass of <code>o.a.i.applib.eventbus.ActionDomainEvent</code>. The topic of subclassing is discussed in more detail <a href="#_rgsvc_api_EventBusService_event-hierarchy">below</a>.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Meanwhile, in the <code>BookRepository</code> domain service, we subscribe to the event and act upon it. For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">BookRepository</span> {
<span class="annotation">@Programmatic</span>
<span class="annotation">@com</span>.google.common.eventbus.Subscribe
<span class="directive">public</span> <span class="type">void</span> onLibraryMemberLeaving(LibraryMemberLeaveEvent e) {
LibraryMember lm = e.getLibraryMember();
<span class="predefined-type">List</span><<span class="predefined-type">Book</span>> lentBooks = findBooksOnLoanFor(lm);
<span class="keyword">if</span>(!lentBooks.isEmpty()) {
sendLetter(lm, lentBooks);
}
}
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This design allows the <code>libraryMember</code> module to be decoupled from the <code>book</code> module.</p>
</div>
</div>
<div class="sect3">
<h4 id="_rgsvc_api_EventBusService_event-hierarchy">6.4.4. Event hierarchy</h4>
<div class="paragraph">
<p>By creating domain event subtypes we can be more semantically precise and in turn providesmore flexibility for subscribers: they can choose whether to be broadly applicable (by subscribing to a superclass) or to be tightly focussed (by subscribing to a subclass).</p>
</div>
<div class="paragraph">
<p>We recommend that you define event classes at (up to) four scopes:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>at the top "global" scope is the Apache Isis-defined <code>o.a.i.applib.event.ActionDomainEvent</code></p>
</li>
<li>
<p>for the "module" scope, create a static class to represent the module itself, and creating nested classes within</p>
</li>
<li>
<p>for each "class" scope, create a nested static event class in the domain object’s class for all of the domain object’s actions</p>
</li>
<li>
<p>for each "action" scope, create a nested static event class for that action, inheriting from the "domain object" class.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>To put all that into code; at the module level we can define:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">com.mycompany.modules.libmem</span>;
...
public <span class="directive">static</span> <span class="type">class</span> <span class="class">LibMemModule</span> {
<span class="directive">private</span> LibMemModule() {}
<span class="directive">public</span> <span class="directive">abstract</span> <span class="directive">static</span> <span class="type">class</span> <span class="class">ActionDomainEvent</span><S>
<span class="directive">extends</span> org.apache.isis.applib.event.ActionDomainEvent<S> {}
... <i class="conum" data-value="1"></i><b>(1)</b>
public <span class="directive">abstract</span> <span class="directive">static</span> <span class="type">class</span> <span class="class">PropertyDomainEvent</span><S,T>
<span class="directive">extends</span> org.apache.isis.applib.event.PropertyDomainEvent<S,T> {}
<span class="directive">public</span> <span class="directive">abstract</span> <span class="directive">static</span> <span class="type">class</span> <span class="class">CollectionDomainEvent</span><S,E>
<span class="directive">extends</span> org.apache.isis.applib.event.CollectionDomainEvent<S,E> {}
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>similar events for properties and collections should also be defined</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>For the class-level we can define:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="directive">static</span> <span class="type">class</span> <span class="class">LibraryMember</span> {
<span class="directive">public</span> <span class="directive">abstract</span> <span class="directive">static</span> <span class="type">class</span> <span class="class">ActionDomainEvent</span>
<span class="directive">extends</span> LibMemModule.ActionDomainEvent<LibraryMember> { }
... <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>similar events for properties and collections should also be defined</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>and finally at the action level we can define:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">LibraryMember</span> {
<span class="directive">public</span> <span class="directive">static</span> <span class="type">class</span> <span class="class">LeaveEvent</span> <span class="directive">extends</span> LibraryMember.ActionDomainEvent { }
<span class="annotation">@Action</span>(domainEvent=LeaveEvent.class)
<span class="directive">public</span> <span class="type">void</span> leave() { ... }
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The subscriber can subscribe either to the general superclass (as before), or to any of the classes in the hierarchy.</p>
</div>
<div class="sect4">
<h5 id="_variation_for_contributing_services">Variation (for contributing services)</h5>
<div class="paragraph">
<p>A slight variation on this is to not fix the generic parameter at the class level, ie:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="directive">static</span> <span class="type">class</span> <span class="class">LibraryMember</span> {
<span class="directive">public</span> <span class="directive">abstract</span> <span class="directive">static</span> <span class="type">class</span> <span class="class">ActionDomainEvent</span><S>
<span class="directive">extends</span> LibMemModule.ActionDomainEvent<S> { }
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>and instead parameterize down at the action level:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">LibraryMember</span> {
<span class="directive">public</span> <span class="directive">static</span> <span class="type">class</span> <span class="class">LeaveEvent</span>
<span class="directive">extends</span> LibraryMember.ActionDomainEvent<LibraryMember> { } <i class="conum" data-value="1"></i><b>(1)</b>
}
<span class="annotation">@Action</span>(domainEvent=LeaveEvent.class)
<span class="directive">public</span> <span class="type">void</span> leave() { ... }
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This then allows for other classes - in particular domain services contributing members - to also inherit from the class-level domain events.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_programmatic_posting">6.4.5. Programmatic posting</h4>
<div class="paragraph">
<p>To programmatically post an event, simply call <code>#post()</code>.</p>
</div>
<div class="paragraph">
<p>The <code>LibraryMember</code> example described above could for example be rewritten into:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">LibraryMember</span> {
...
public <span class="type">void</span> leave() {
...
eventBusService.post(<span class="keyword">new</span> LibraryMember.LeaveEvent(...)); <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><code>LibraryMember.LeaveEvent</code> could be <em>any</em> class, not just a subclass of <code>o.a.i.applib.event.ActionDomainEvent</code>.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>In practice we suspect there will be few cases where the programmatic approach is required rather than the declarative approach afforded by <a href="rgant.html#_rgant-Action_domainEvent"><code>@Action#domainEvent()</code></a> et al.</p>
</div>
</div>
<div class="sect3">
<h4 id="_using_code_wrapperfactory_code">6.4.6. Using <code>WrapperFactory</code></h4>
<div class="paragraph">
<p>An alternative way to cause events to be posted is through the <a href="#_rgsvc_api_WrapperFactory"><code>WrapperFactory</code></a>. This is useful when you wish to enforce a (lack-of-) trust boundary between the caller and the callee.</p>
</div>
<div class="paragraph">
<p>For example, suppose that <code>Customer#placeOrder(…​)</code> emits a <code>PlaceOrderEvent</code>, which is subscribed to by a <code>ReserveStockSubscriber</code>. This subscriber in turn calls <code>StockManagementService#reserveStock(…​)</code>. Any business rules on <code>#reserveStock(…​)</code> should be enforced.</p>
</div>
<div class="paragraph">
<p>In the <code>ReserveStockSubscriber</code>, we therefore use the <code>WrapperFactory</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>(nature=NatureOfService.DOMAIN)
<span class="directive">public</span> <span class="type">class</span> <span class="class">ReserveStockSubscriber</span> {
<span class="annotation">@Programmatic</span>
<span class="annotation">@Subscribe</span>
<span class="directive">public</span> <span class="type">void</span> on(Customer.PlaceOrderEvent ev) {
wrapperFactory.wrap(stockManagementService)
.reserveStock(ev.getProduct(), ev.getQuantity());
}
...
<span class="annotation">@Inject</span>
StockManagementService stockManagementService;
<span class="annotation">@Inject</span>
WrapperFactory wrapperFactory;
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_spi">6.4.7. Implementation SPI</h4>
<div class="paragraph">
<p>The implementation of <code>EventBusService</code> provided by Apache Isis will by default use <a href="https://code.google.com/p/guava-libraries/">Guava</a>'s <a href="https://code.google.com/p/guava-libraries/wiki/EventBusExplained"><code>EventBus</code></a> as the underlying in-memory event bus. Alternatively the <a href="http://www.axonframework.org/">AxonFramework</a>'s <a href="http://www.axonframework.org/docs/2.4/single.html#d5e1489">SimpleEventBus</a> can be used. Which is used is specified through configuration property (described <a href="#_rgsvc_api_EventBusService_Configuration">below</a>).</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="title">Guava vs Axon, which to use?</div>
<div class="paragraph">
<p>Guava actually queues up events; they are not guaranteed to be dispatched immediately. This generally is not problem, but can be for cases where the subscriber may in turn want to post its own events (using <a href="#_rgsvc_api_WrapperFactory"><code>WrapperFactory</code></a>).</p>
</div>
<div class="paragraph">
<p>The Axon <code>SimpleEventBus</code>-based implementation on the other hand is fully synchronous; events are dispatched as soon as they are posted. This works well in all scenarios (that we have tested).</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>It is also possible to use some other implementation.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">EventBusImplementation</span> {
<span class="type">void</span> register(<span class="predefined-type">Object</span> domainService);
<span class="type">void</span> unregister(<span class="predefined-type">Object</span> domainService);
<span class="type">void</span> post(<span class="predefined-type">Object</span> event);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>As is probably obvious, the <code>EventBusService</code> just delegates down to these method calls when its own similarly named methods are called.</p>
</div>
<div class="paragraph">
<p>If you do provide your own implementation of this SPI, be aware that your subscribers will need to use whatever convention is required (eg different annotations) such that the events are correctly routed through to your subscribers.</p>
</div>
</div>
<div class="sect3">
<h4 id="_rgsvc_api_EventBusService_Configuration">6.4.8. Configuration</h4>
<div class="paragraph">
<p>The implementation of <code>EventBusService</code> provided by Apache Isis will by default use <a href="https://code.google.com/p/guava-libraries/">Guava</a>'s <a href="https://code.google.com/p/guava-libraries/wiki/EventBusExplained"><code>EventBus</code></a> as the underlying in-memory event bus. Alternatively the <a href="http://www.axonframework.org/">AxonFramework</a>'s <a href="http://www.axonframework.org/docs/2.4/single.html#d5e1489">SimpleEventBus</a> can be used.</p>
</div>
<div class="paragraph">
<p>To specify which, add the <a href="rgcfg.html#_rgcfg_configuring-core">configuration property</a> <code>isis.services.eventbus.implementation</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="ini">isis.services.eventbus.implementation=guava</code></pre>
</div>
</div>
<div class="paragraph">
<p>or</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="ini">isis.services.eventbus.implementation=axon</code></pre>
</div>
</div>
<div class="paragraph">
<p>If you have written your own implementation of the <code>EventBusServiceImplementation</code> SPI, then specify instead its fully-qualified class name:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="ini">isis.services.eventbus.implementation=com.mycompany.isis.MyEventBusServiceImplementation</code></pre>
</div>
</div>
<div class="paragraph">
<p>In addition, there is one further configuration property, whether to allow "late registration":</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="ini">isis.services.eventbus.allowLateRegistration=false</code></pre>
</div>
</div>
<div class="paragraph">
<p>Late registration refers to the idea that a domain service can register itself with the <code>EventBusService</code> after events have been posted. Since domain services are set up at boot time, this almost certainly constitutes a bug in the code and so by default late registration is <em>not</em> allowed. Setting the above property to <code>true</code> disables this check.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_13">6.4.9. Registering the Services</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>EventBusService</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_16">6.4.10. Related Services</h4>
<div class="paragraph">
<p>The <code>EventBusService</code> is intended for fine-grained publish/subscribe for object-to-object interactions within an Apache Isis domain object model. The event propagation is strictly in-memory, and there are no restrictions on the object acting as the event (it need not be serializable, for example).</p>
</div>
<div class="paragraph">
<p>The <a href="#_rgsvc_spi_PublishingService"><code>PublishingService</code></a> meanwhile is intended for coarse-grained publish/subscribe for system-to-system interactions, from Apache Isis to some other system. Here the only events published are those that action invocations (for actions annotated with <a href="rgant.html#_rgant-Action_publishing"><code>@Action#publishing()</code></a>) and of changed objects (for objects annotated with <a href="rgant.html#_rgant-DomainObject_publishing"><code>@DomainObject#publishing()</code></a>).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_FactoryService">6.5. <code>FactoryService</code></h3>
<div class="paragraph">
<p>The <code>FactoryService</code> collects together methods for instantiating domain objects.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The methods in this service replace similar methods (now deprecated) in <a href="#_rgsvc_api_DomainObjectContainer"><code>DomainObjectContainer</code></a>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_api_5">6.5.1. API</h4>
<div class="paragraph">
<p>The API of <code>FactoryService</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">FactoryService</span> {
<T> T instantiate(<span class="directive">final</span> <span class="predefined-type">Class</span><T> ofType); <i class="conum" data-value="1"></i><b>(1)</b>
<T> T mixin(); <i class="conum" data-value="2"></i><b>(2)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>create a new non-persisted domain entity. Any services will be automatically injected into the service.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>programmatically instantiate a mixin, as annotated with <a href="rgant.html#_rgant-Mixin"><code>@Mixin</code></a> or <a href="rgant.html#_rgant-DomainObject_nature"><code>@DomainObject#nature()</code></a>.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The object is created in memory, but is not persisted. The benefits of using this method (instead of simply using the Java <code>new</code> keyword) are:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>any services will be injected into the object immediately (otherwise they will not be injected until the frameworkbecomes aware of the object, typically when it is persisted through the <a href="#_rgsvc_api_RepositoryService"><code>RepositoryService</code></a></p>
</li>
<li>
<p>the default value for any properties (usually as specified by <code>defaultXxx()</code> supporting methods) will not be set and the <code>created()</code> callback will be called.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The corollary is: if your code never uses <code>defaultXxx()</code> or the <code>created()</code> callback, then you can just <code>new</code> up the object. The <a href="#_rgsvc_api_ServiceRegistry"><code>ServiceRegistry</code></a> service can be used to inject services into the domain object.</p>
</div>
</div>
<div class="sect3">
<h4 id="_usage_9">6.5.2. Usage</h4>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Customer cust = factoryService.instantiate(Customer.class);
cust.setFirstName(<span class="string"><span class="delimiter">"</span><span class="content">Freddie</span><span class="delimiter">"</span></span>);
cust.setLastName(<span class="string"><span class="delimiter">"</span><span class="content">Mercury</span><span class="delimiter">"</span></span>);
repositoryService.persist(cust);</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_22">6.5.3. Implementation</h4>
<div class="paragraph">
<p>The core framework provides a default implementation of this service (<code>o.a.i.core.metamodel.services.factory.FactoryServiceDefault</code>).</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_16">6.5.4. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>FactoryService</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_17">6.5.5. Related Services</h4>
<div class="paragraph">
<p>The <a href="#_rgsvc_api_RepositoryService"><code>RepositoryService</code></a> is often used in conjunction with the <code>FactoryService</code>, to persist domain objects after they have been instantiated and populated.</p>
</div>
<div class="paragraph">
<p>An alternative to using the factory service is to simply instantiate the object ("new is the new new") and then use the
<a href="#_rgsvc_api_ServiceRegistry"><code>ServiceRegistry</code></a> service to inject other domain services into the
instantiated object.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_Scratchpad">6.6. <code>Scratchpad</code></h3>
<div class="paragraph">
<p>The <code>Scratchpad</code> service is a <a href="../../more-advanced-topics/how-to-09-020-How-to-write-a-typical-domain-service.html">request-scoped</a> service to allow objects to exchange information even if they do not directly call each other.</p>
</div>
<div class="sect3">
<h4 id="_api_implementation_8">6.6.1. API & Implementation</h4>
<div class="paragraph">
<p>The API of <code>Scratchpad</code> service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@RequestScoped</span>
<span class="directive">public</span> <span class="type">class</span> <span class="class">Scratchpad</span> {
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <span class="predefined-type">Object</span> get(<span class="predefined-type">Object</span> key) { ... }
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <span class="type">void</span> put(<span class="predefined-type">Object</span> key, <span class="predefined-type">Object</span> value) { ... }
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <span class="type">void</span> clear() { ... }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This class (<code>o.a.i.applib.services.scratchpad.Scratchpad</code>) is also the implementation. And, as you can see, the service is just a request-scoped wrapper around a <code>java.util.Map</code>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_usage_10">6.6.2. Usage</h4>
<div class="paragraph">
<p>The most common use-case is for <a href="rgant.html#_rgant-Action_invokeOn">bulk</a> actions that act upon multiple objects in a list. The (same) <code>Scratchpad</code> service is injected into each of these objects, and so they can use pass information.</p>
</div>
<div class="paragraph">
<p>For example, the Isis addons example <a href="https://github.com/isisaddons/isis-app-todoapp/">todoapp</a> (not ASF) demonstrates how the <code>Scratchpad</code> service can be used to calculate the total cost of the selected `ToDoItem`s:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Action</span>(
semantics=SemanticsOf.SAFE,
invokeOn=InvokeOn.COLLECTION_ONLY
)
<span class="directive">public</span> <span class="predefined-type">BigDecimal</span> totalCost() {
<span class="predefined-type">BigDecimal</span> total = (<span class="predefined-type">BigDecimal</span>) scratchpad.get(<span class="string"><span class="delimiter">"</span><span class="content">runningTotal</span><span class="delimiter">"</span></span>);
<span class="keyword">if</span>(getCost() != <span class="predefined-constant">null</span>) {
total = total != <span class="predefined-constant">null</span> ? total.add(getCost()) : getCost();
scratchpad.put(<span class="string"><span class="delimiter">"</span><span class="content">runningTotal</span><span class="delimiter">"</span></span>, total);
}
<span class="keyword">return</span> total.setScale(<span class="integer">2</span>);
}
<span class="annotation">@Inject</span>
Scratchpad scratchpad;</code></pre>
</div>
</div>
<div class="paragraph">
<p>A more complex example could use a <a href="ugbtb.html#_ugbtb_view-models">view model</a> to enable bulk updates to a set of objects. The view model’s job is to gather track of the items to be updated:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">ToDoItemUpdateBulkUpdate</span> <span class="directive">extends</span> AbstractViewModel {
<span class="directive">private</span> <span class="predefined-type">List</span><ToDoItem> _items = ...;
<span class="directive">public</span> ToDoItemBulkUpdate add(ToDoItem item) {
_items.add(item);
<span class="keyword">return</span> <span class="local-variable">this</span>;
}
... <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>not shown - the implementation of <code>ViewModel</code> for converting the list of <code>_items</code> into a string.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The bulk action in the objects simply adds the selected item to the view model:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Action</span>(
invokeOn=InvokeOn.COLLECTIONS_ONLY
semantics=SemanticsOf.SAFE
)
<span class="directive">public</span> ToDoItemBulkUpdate bulkUpdate() {
<span class="keyword">return</span> lookupBulkUpdateViewModel().add(<span class="local-variable">this</span>);
}
<span class="directive">private</span> ToDoItemBulkUpdate lookupBulkUpdateViewModel() {
ToDoItemBulkUpdate bulkUpdate =
(ToDoItemBulkUpdate) scratchpad.get(<span class="string"><span class="delimiter">"</span><span class="content">bulkUpdateViewModel</span><span class="delimiter">"</span></span>); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="keyword">if</span>(bulkUpdate == <span class="predefined-constant">null</span>) {
bulkUpdate = container.injectServicesInto(<span class="keyword">new</span> ToDoItemBulkUpdate());
scratchpad.put(<span class="string"><span class="delimiter">"</span><span class="content">bulkUpdateViewModel</span><span class="delimiter">"</span></span>, bulkUpdate); <i class="conum" data-value="2"></i><b>(2)</b>
}
<span class="keyword">return</span> bulkUpdate;
}
<span class="annotation">@Inject</span>
Scratchpad scratchpad;</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>look for the <code>ToDoItemBulkUpdate</code> in the scratchpad…​</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>…​ and add one if there isn’t one (ie for the first object returned).</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>If using the <a href="ugvw.html">Wicket viewer</a>, the <code>ToDoItemBulkUpdate</code> view model returned from the last action invoked will be displayed. Thereafter this view model can be used to perform a bulk update of the "enlisted" items.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_17">6.6.3. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>Scratchpad</code> service is automatically registered and injected (it is annotated with <code>@DomainService</code>)
so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_18">6.6.4. Related Services</h4>
<div class="paragraph">
<p>The <a href="#_rgsvc_api_ActionInteractionContext"><code>ActionInteractionContext</code></a> service allows <a href="rgant.html#_rgant-Action_invokeOn">bulk actions</a> to co-ordinate with each other.</p>
</div>
<div class="paragraph">
<p>The <a href="#_rgsvc_api_QueryResultsCache"><code>QueryResultsCache</code></a> is useful for caching the results of expensive method calls.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_UserService">6.7. <code>UserService</code></h3>
<div class="paragraph">
<p>The <code>UserService</code> allows the domain object to obtain the identity of the user interacting with said object.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The methods in this service replace similar methods (now deprecated) in <a href="#_rgsvc_api_DomainObjectContainer"><code>DomainObjectContainer</code></a>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_api_and_usage_3">6.7.1. API and Usage</h4>
<div class="paragraph">
<p>The API of <code>UserService</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">UserService</span> {
UserMemento getUser();
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>where in turn (the essence of) <code>UserMemento</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="directive">final</span> <span class="type">class</span> <span class="class">UserMemento</span> {
<span class="directive">public</span> <span class="predefined-type">String</span> getName() { ... }
<span class="directive">public</span> <span class="type">boolean</span> isCurrentUser(<span class="directive">final</span> <span class="predefined-type">String</span> userName) { ... }
<span class="directive">public</span> <span class="predefined-type">List</span><RoleMemento> getRoles() { ... }
<span class="directive">public</span> <span class="type">boolean</span> hasRole(<span class="directive">final</span> RoleMemento role) { ... }
<span class="directive">public</span> <span class="type">boolean</span> hasRole(<span class="directive">final</span> <span class="predefined-type">String</span> roleName) { ... }
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>and <code>RoleMemento</code> is simpler still:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="directive">final</span> <span class="type">class</span> <span class="class">RoleMemento</span> {
<span class="directive">public</span> <span class="predefined-type">String</span> getName() { ... }
<span class="directive">public</span> <span class="predefined-type">String</span> getDescription() { ... }
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The roles associated with the <code>UserMemento</code> will be based on the configured <a href="ugsec.html">security</a> (typically Shiro).</p>
</div>
<div class="paragraph">
<p>In addition, when using the <a href="ugvw.html">Wicket viewer</a> there will be an additional "org.apache.isis.viewer.wicket.roles.USER" role; this is used internally to restrict access to web pages without authenticating.</p>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_23">6.7.2. Implementation</h4>
<div class="paragraph">
<p>The core framework provides a default implementation of this service (<code>o.a.i.core.runtime.services.user.UserServiceDefault</code>).</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_18">6.7.3. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>UserService</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_rgsvc_integration-api">7. Integration API</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The integration APIs provide functionality to the domain objects to integrate with other bounded contexts, for example sending an email or serializing an object out to XML.</p>
</div>
<div class="paragraph">
<p>The table below summarizes the integration APIs defined by Apache Isis. It also lists their corresponding implementation, either a default implementation provided by Apache Isis itself, or provided by one of the in (non-ASF) <a href="http://www.isisaddons.org">Isis Addons</a> modules.</p>
</div>
<table class="tableblock frame-all grid-all spread">
<caption class="title">Table 6. Integration API</caption>
<colgroup>
<col style="width: 25%;">
<col style="width: 50%;">
<col style="width: 12.5%;">
<col style="width: 12.5%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">API</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Implementation</th>
<th class="tableblock halign-left valign-top">Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_BookmarkService"><code>o.a.i.applib.</code><br>
<code>services.bookmark</code><br>
<code>BookmarkService2</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Convert object reference to a serializable "bookmark", and vice versa.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>BookmarkServiceDefault</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-metamodel</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">related services:
<code>BookmarkHolder-</code><br>
<code>ActionContributions</code>,
<code>BookmarkHolder-</code><br>
<code>Association-</code><br>
<code>Contributions</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_DeepLinkService"><code>o.a.i.applib</code><br>
<code>services.deeplink</code><br>
<code>DeepLinkService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Obtain a URL to a domain object (eg for use within an email or report)</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>DeepLinkServiceWicket</code><br>
<code>o.a.i.viewer</code><br>
<code>isis-viewer-wicket-impl</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Implementation only usable within Wicket viewer</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_EmailService"><code>o.a.i.applib.</code><br>
<code>services.email</code><br>
<code>EmailService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Send a HTML email, optionally with attachments.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>EmailServiceDefault</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-runtime</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_GuiceBeanProvider"><code>o.a.i.applib.</code><br>
<code>services.guice</code><br>
<code>GuiceBeanProvider</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Access to internal framework services initialized using Guice DI.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>GuiceBeanProviderWicket</code><br>
<code>o.a.i.core</code><br>
<code>isis-viewer-wicket-impl</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_JaxbService"><code>o.a.i.applib.</code><br>
<code>services.jaxb</code><br>
<code>JaxbService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Marshal and unmarshal JAXB-annotated view models to/from XML.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>JaxbServiceDefault</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-schema</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_MementoService"><code>o.a.i.applib.</code><br>
<code>services.memento</code><br>
<code>MementoService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Capture a serializable memento of a set of primitives or <a href="#_rgsvc_api_BookmarkService">bookmarks</a>. Primarily used internally, eg in support of commands/auditing.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>MementoServiceDefault</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-runtime</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_XmlSnapshotService"><code>o.a.i.applib.</code><br>
<code>services.xmlsnapshot</code><br>
<code>XmlSnapshotService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Generate an XML representation of an object and optionally a graph of related objects.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>XmlSnapshotServiceDefault</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-runtime</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Key:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>o.a.i</code> is an abbreviation for <code>org.apache.isis</code></p>
</li>
<li>
<p><code>o.ia.m</code> is an abbreviation for <code>org.isisaddons.module</code></p>
</li>
<li>
<p><code>o.a.i.c.m.s</code> is an abbreviation for <code>org.apache.isis.core.metamodel.services</code></p>
</li>
<li>
<p><code>o.a.i.c.r.s</code> is an abbreviation for <code>org.apache.isis.core.runtime.services</code></p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_BookmarkService">7.1. <code>BookmarkService2</code></h3>
<div class="paragraph">
<p>The <code>BookmarkService2</code> API provides the ability to obtain a serializable <code>o.a.i.applib.bookmarks.Bookmark</code> for any (persisted) domain object, and to lookup domain objects given a <code>Bookmark</code>. This can then in turn be converted to and from a string.</p>
</div>
<div class="paragraph">
<p>For example, a <code>Customer</code> object with:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>an object type of "custmgmt.Customer" (as per <a href="rgant.html#_rgant-DomainObject_objectType"><code>DomainObject#objectType()</code></a> or equivalent) , and</p>
</li>
<li>
<p>an id=123</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>could correspond to a <code>Bookmark</code> with a string representation of <code>custmgmt.Customer|123</code>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>A <code>Bookmark</code> is little more than an API equivalent of Apache Isis' internal <code>Oid</code> (object identifier). Nevertheless, the ability to uniquely address <em>any</em> domain object within an Apache Isis system — to in effect provide a URN — is immensely useful.</p>
</div>
<div class="paragraph">
<p>For example, a <code>Bookmark</code> could be converted into a barcode, and then this used for automated scanning of correspondence from a customer.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p><code>Bookmark</code>s are used by several other domain services as a means of storing areference to an arbitrary object
(a polymorphic relationship). For example, the (non-ASF)
<a href="http://github.com/isisaddons/isis-module-auditing">Isis addons' auditing</a> module’s implementation of
<a href="#_rgsvc_spi_AuditerService"><code>AuditerService</code></a> (<code>1.13.0-SNAPSHOT</code>) uses bookmarks to capture the object
that is being audited.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>One downside of using <code>Bookmark</code>s is that there is no way for the JDO/DataNucleus objectstore to enforce any kind of referental integrity. However, the (non-ASF) <a href="http://github.com/isisaddons/isis-module-poly">Isis addons' poly</a> module describes and supports a design pattern to address this requirement.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_api_implementation_9">7.1.1. API & Implementation</h4>
<div class="paragraph">
<p>The API defined by <code>BookmarkService2</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">BookmarkService2</span> {
<span class="type">enum</span> FieldResetPolicy { <i class="conum" data-value="1"></i><b>(1)</b>
RESET,
DONT_RESET
}
<span class="annotation">@Programmatic</span>
<span class="predefined-type">Object</span> lookup(BookmarkHolder bookmarkHolder, FieldResetPolicy policy);
<span class="annotation">@Programmatic</span>
<span class="predefined-type">Object</span> lookup(Bookmark bookmark, FieldResetPolicy policy);
<span class="annotation">@Programmatic</span>
<T> T lookup(Bookmark bookmark, FieldResetPolicy policy, <span class="predefined-type">Class</span><T> cls); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="annotation">@Programmatic</span>
Bookmark bookmarkFor(<span class="predefined-type">Object</span> domainObject);
<span class="annotation">@Programmatic</span>
Bookmark bookmarkFor(<span class="predefined-type">Class</span><?> cls, <span class="predefined-type">String</span> identifier);
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>if the object has already been loaded from the database, then whether to reset its fields. The default it to <code>RESET</code>.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>same as <code>lookup(Bookmark bookmark)</code>, but downcasts to the specified type.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The core framework provides a default implementation of this API, namely <code>o.a.i.core.metamodel.services.bookmarks.BookmarkServiceDefault</code></p>
</div>
</div>
<div class="sect3">
<h4 id="__code_bookmarkholder_code">7.1.2. <code>BookmarkHolder</code></h4>
<div class="paragraph">
<p>The <code>BookmarkHolder</code> interface is intended to be implemented by domain objects that use a <code>Bookmark</code> to reference a (single) domain object; an example might be a class such as the audit entry, mentioned above. The interface is simply:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">BookmarkHolder</span> {
<span class="annotation">@Programmatic</span>
Bookmark bookmark();
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>There are two services that will contribute to this interface:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>BookmarkHolderActionContributions</code> will provide a <code>lookup(…​)</code> action</p>
</li>
<li>
<p><code>BookmarkHolderAssociationContributions</code> provides an <code>object</code> property.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Either of these can be suppressed, if required, using a vetoing subscriber. For example, to suppress the <code>object</code> property (so that only the <code>lookup(…​)</code> action is ever shown for implementations of <code>BookmarkHolder</code>, define:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>(nature=NatureOfService.DOMAIN)
<span class="directive">public</span> <span class="type">class</span> <span class="class">AlwaysHideBookmarkHolderAssociationsObjectProperty</span> {
<span class="annotation">@Subscribe</span>
<span class="directive">public</span> <span class="type">void</span> on(BookmarkHolderAssociationContributions.ObjectDomainEvent ev) {
ev.hide();
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>A more sophisticated implementation could look inside the passed <code>ev</code> argument and selectively hide or not based on the contributee.</p>
</div>
</div>
<div class="sect3">
<h4 id="_usage_by_other_services">7.1.3. Usage by other services</h4>
<div class="paragraph">
<p>Bookmarks are used by the (non-ASF) <a href="http://github.com/isisaddons/isis-module-command">Isis addons' command</a> module’s
implementation of <a href="#_rgsvc_api_BackgroundCommandService"><code>BackgroundCommandService</code></a>, which uses a
bookmark to capture the target object on which an action will be invoked subsequently.</p>
</div>
<div class="paragraph">
<p>Bookmarks are also used by the (non-ASF) <a href="http://github.com/isisaddons/isis-module-publishing">Isis addons' publishing</a>
module’s implementation of <a href="#_rgsvc_spi_PublishingService"><code>PublishingService</code></a>, and by the
(non-ASF) <a href="http://github.com/isisaddons/isis-module-auditing">Isis addons' auditing</a> module’s implementation of
<a href="#_rgsvc_spi_AuditerService"><code>AuditerService</code></a> (<code>1.13.0-SNAPSHOT</code>).</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_19">7.1.4. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>BookmarkService</code> is automatically registered (it is annotated with <code>@DomainService</code>) so no further
configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_DeepLinkService">7.2. <code>DeepLinkService</code></h3>
<div class="paragraph">
<p>The <code>DeepLinkService</code> provides the ability to obtain a <code>java.net.URI</code> that links to a representation of any (persisted) domain entity or
view model.</p>
</div>
<div class="paragraph">
<p>A typical use case is to generate a clickable link for rendering in an email, PDF, tweet or other communication.</p>
</div>
<div class="sect3">
<h4 id="_api_implementation_10">7.2.1. API & Implementation</h4>
<div class="paragraph">
<p>The API defined by <code>DeepLinkService</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">DeepLinkService</span> {
<span class="predefined-type">URI</span> deepLinkFor(<span class="predefined-type">Object</span> domainObject); <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>Creates a URI that can be used to obtain a representation of the provided domain object in one of the Apache Isis viewers.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The <a href="ugvw.html">Wicket viewer</a> this provides an implementation for accessing the representation through this viewer. (For the <a href="ugvro.html">RestfulObjects viewer</a>, a URL can be constructed according to the <a href="http://www.restfulobjects.org">Restful Objects spec</a> in conjunction with a <code>Bookmark</code> obtained via the <a href="#_rgsvc_api_BookmarkService"><code>BookmarkService</code></a>).</p>
</div>
</div>
<div class="sect3">
<h4 id="_usage_within_the_framework">7.2.2. Usage within the framework</h4>
<div class="paragraph">
<p>The <a href="#_rgsvc_spi_EmailNotificationService"><code>EmailNotificationService</code></a> uses this service in order to generate emails as part of <a href="ugvw.html#_ugvw_features_user-registration">user registration</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_implementations_2">7.2.3. Implementations</h4>
<div class="paragraph">
<p>The Wicket viewer core framework provides a default implementation of this API:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>org.apache.isis.viewer.wicket.viewer.services.DeepLinkServiceWicket</code></p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_14">7.2.4. Registering the Services</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#<em>rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>), _and</em> that the
<a href="ugvw.html">Wicket viewer</a> is being used, then an implementation of <code>DeepLinkService</code> is
automatically registered and injected (it is annotated with <code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_EmailService">7.3. <code>EmailService</code></h3>
<div class="paragraph">
<p>The <code>EmailService</code> provides the ability to send HTML emails, with attachments, to one or more recipients.</p>
</div>
<div class="paragraph">
<p>Apache Isis provides a default implementation to send emails using an external SMTP provider. Note that this must be configured (using a number of configuration properties) before it can be used. The that sends email as an HTML message, using an external SMTP provider.</p>
</div>
<div class="sect3">
<h4 id="_api_implementation_11">7.3.1. API & Implementation</h4>
<div class="paragraph">
<p>The API for the service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">EmailService</span> {
<span class="annotation">@Programmatic</span>
<span class="type">boolean</span> send( <i class="conum" data-value="1"></i><b>(1)</b>
<span class="predefined-type">List</span><<span class="predefined-type">String</span>> to, <span class="predefined-type">List</span><<span class="predefined-type">String</span>> cc, <span class="predefined-type">List</span><<span class="predefined-type">String</span>> bcc, <i class="conum" data-value="2"></i><b>(2)</b>
<span class="predefined-type">String</span> subject,
<span class="predefined-type">String</span> body, <i class="conum" data-value="3"></i><b>(3)</b>
<span class="predefined-type">DataSource</span>... attachments);
<span class="annotation">@Programmatic</span>
<span class="type">boolean</span> isConfigured(); <i class="conum" data-value="4"></i><b>(4)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>is the main API to send the email (and optional attachments). Will return <code>false</code> if failed to send</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>pass either <code>null</code> or <code>Collections.emptyList()</code> if not required</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>should be HTML text</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>indicates whether the implementation was configured and initialized correctly. If this returns <code>false</code> then any attempt to call <code>send(…​)</code> will fail.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>As noted in the introduction, the core framework provides a default implementation (<code>EmailServiceDefault</code>) that sends email as an HTML message, using an external SMTP provider.</p>
</div>
</div>
<div class="sect3">
<h4 id="_configuration">7.3.2. Configuration</h4>
<div class="paragraph">
<p>To use this service the following properties must be configured:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>isis.service.email.sender.address</code></p>
</li>
<li>
<p><code>isis.service.email.sender.password</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>and these properties may optionally be configured (each has a default to use gmail, documented <a href="rgcfg.html#_rgcfg_configuring-core">here</a>):</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>isis.service.email.sender.hostname</code></p>
</li>
<li>
<p><code>isis.service.email.port</code></p>
</li>
<li>
<p><code>isis.service.email.tls.enabled</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>These configuration properties can be specified either in <code>isis.properties</code> or in an <a href="ugbtb.html#_ugbtb_deployment_externalized-configuration">external configuration file</a>.</p>
</div>
<div class="paragraph">
<p>If prototyping (that is, running the app using <code>org.apache.isis.WebServer</code>), the configuration properties can also be specified as system properties. For example, if you create a test email account on gmail, you can configure the service using:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="ini">-Disis.service.email.sender.address=xxx@gmail.com -Disis.service.email.sender.password=yyy</code></pre>
</div>
</div>
<div class="paragraph">
<p>where "xxx" is the gmail user account and "yyy" is its password</p>
</div>
</div>
<div class="sect3">
<h4 id="_alternative_implementations_3">7.3.3. Alternative Implementations</h4>
<div class="paragraph">
<p>If you wish to write an alternative implementation, be aware that it should process the message body as HTML (as opposed to plain text or any other format).</p>
</div>
<div class="paragraph">
<p>Also, note that (unlike most Apache Isis domain services) the implementation is also instantiated and injected by Google Guice. This is because <code>EmailService</code> is used as part of the <a href="ugvw.html#_ugvw_features_user-registration">user registration</a> functionality and is used by Wicket pages that are accessed outside of the usual Apache Isis runtime. This implies a couple of additional constraints:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>first, implementation class should also be annotated with <code>@com.google.inject.Singleton</code></p>
</li>
<li>
<p>second, there may not be any Apache Isis session running. (If necessary, one can be created on the fly using <code>IsisContext.doInSession(…​)</code>)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>To ensure that your alternative implementation takes the place of the default implementation, register it explicitly in <code>isis.properties</code>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_15">7.3.4. Registering the Services</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>EmailService</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_19">7.3.5. Related Services</h4>
<div class="paragraph">
<p>The email service is used by the <a href="#_rgsvc_spi_EmailNotificationService"><code>EmailNotificationService</code></a> which is, in turn, used by <a href="#_rgsvc_spi_UserRegistrationService"><code>UserRegistrationService</code></a>.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_GuiceBeanProvider">7.4. <code>GuiceBeanProvider</code></h3>
<div class="paragraph">
<p>The <code>GuiceBeanProvider</code> domain service acts as a bridge between Apache Isis' <a href="ugvw.html">Wicket viewer</a> internal bootstrapping using <a href="https://github.com/google/guice">Google Guice</a>.</p>
</div>
<div class="paragraph">
<p>This service operates at a very low-level, and you are unlikely to have a need for it. It is used internally by the framework, in the default implementation of the <a href="#_rgsvc_api_DeepLinkService"><code>DeepLinkService</code></a>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Currently Apache Isis uses a combination of Guice (within the Wicket viewer only) and a home-grown dependency injection framework. In future versions we intended to refactor the framework to use CDI throughout. At that time this service is likely to become redundant because we will allow any of the internal components of Apache Isis to be injected into your domain object code.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_api_implementation_12">7.4.1. API & Implementation</h4>
<div class="paragraph">
<p>The API defined by this service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">GuiceBeanProvider</span> {
<span class="annotation">@Programmatic</span>
<T> T lookup(<span class="predefined-type">Class</span><T> beanType);
<span class="annotation">@Programmatic</span>
<T> T lookup(<span class="predefined-type">Class</span><T> beanType, <span class="directive">final</span> <span class="predefined-type">Annotation</span> qualifier);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <a href="ugvw.html">Wicket viewer</a> this provides an implementation of this service.</p>
</div>
</div>
<div class="sect3">
<h4 id="_usage_11">7.4.2. Usage</h4>
<div class="paragraph">
<p>Using the <a href="ugvw.html">Wicket viewer</a> requires subclassing of <code>IsisWicketApplication</code>. In the subclass it is commonplace to override <code>newIsisWicketModule()</code>, for example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Override</span>
<span class="directive">protected</span> Module newIsisWicketModule() {
<span class="directive">final</span> Module isisDefaults = <span class="local-variable">super</span>.newIsisWicketModule();
<span class="directive">final</span> Module overrides = <span class="keyword">new</span> AbstractModule() {
<span class="annotation">@Override</span>
<span class="directive">protected</span> <span class="type">void</span> configure() {
bind(<span class="predefined-type">String</span>.class).annotatedWith(Names.named(<span class="string"><span class="delimiter">"</span><span class="content">applicationName</span><span class="delimiter">"</span></span>))
.toInstance(<span class="string"><span class="delimiter">"</span><span class="content">ToDo App</span><span class="delimiter">"</span></span>);
bind(<span class="predefined-type">String</span>.class).annotatedWith(Names.named(<span class="string"><span class="delimiter">"</span><span class="content">applicationCss</span><span class="delimiter">"</span></span>))
.toInstance(<span class="string"><span class="delimiter">"</span><span class="content">css/application.css</span><span class="delimiter">"</span></span>);
bind(<span class="predefined-type">String</span>.class).annotatedWith(Names.named(<span class="string"><span class="delimiter">"</span><span class="content">applicationJs</span><span class="delimiter">"</span></span>))
.toInstance(<span class="string"><span class="delimiter">"</span><span class="content">scripts/application.js</span><span class="delimiter">"</span></span>);
...
}
};
<span class="keyword">return</span> Modules.override(isisDefaults).with(overrides);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This "module" is in fact a Guice module, and so the <code>GuiceBeanProvider</code> service can be used to lookup any of the components bound into it.</p>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">SomeDomainObject</span> {
<span class="directive">private</span> <span class="predefined-type">String</span> lookupApplicationName() {
<span class="keyword">return</span> guiceBeanProvider.lookup(<span class="predefined-type">String</span>.class, Names.named(<span class="string"><span class="delimiter">"</span><span class="content">applicationName</span><span class="delimiter">"</span></span>));
}
<span class="annotation">@Inject</span>
GuiceBeanProvider guiceBeanProvider;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>should return "ToDo App".</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_16">7.4.3. Registering the Services</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#<em>rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>), _and</em> that the
<a href="ugvw.html">Wicket viewer</a> is being used, then an implementation of <code>GuiceBeanProvider</code> is
automatically registered and injected (it is annotated with <code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_JaxbService">7.5. <code>JaxbService</code></h3>
<div class="paragraph">
<p>The <code>JaxbService</code> allows instances of JAXB-annotated classes to be marshalled to XML and
unmarshalled from XML back into domain objects.</p>
</div>
<div class="sect3">
<h4 id="_rgsvc_api_JaxbService_api-and-implementation">7.5.1. API & Implementation</h4>
<div class="paragraph">
<p>The API defined by <code>JaxbService</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">JaxbService</span> {
<span class="annotation">@Programmatic</span>
<T> T fromXml(<span class="predefined-type">Class</span><T> domainClass, <span class="predefined-type">String</span> xml); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <span class="predefined-type">String</span> toXml(<span class="directive">final</span> <span class="predefined-type">Object</span> domainObject); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="directive">public</span> <span class="type">enum</span> IsisSchemas { <i class="conum" data-value="3"></i><b>(3)</b>
INCLUDE, IGNORE
}
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <span class="predefined-type">Map</span><<span class="predefined-type">String</span>, <span class="predefined-type">String</span>> toXsd(<span class="directive">final</span> <span class="predefined-type">Object</span> domainObject, <span class="directive">final</span> IsisSchemas isSchemas);} <i class="conum" data-value="4"></i><b>(4)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>unmarshalls the XML into an instance of the class.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>marshalls the domain object into XML</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>whether to include or exclude the Isis schemas in the generated map of XSDs. Discussed further below.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>generates a map of each of the schemas referenced; the key is the schema namespace, the value is the XML of the schema itself.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>With respect to the <code>IsisSchemas</code> enum: a JAXB-annotated domain object will live in its own XSD namespace and may
reference multiple other XSD schemas. In particular, many JAXB domain objects will reference the
<a href="rgcms.html#_rgcms_schema">common Isis schemas</a> (for example the <code>OidDto</code> class that represents a reference to
a persistent entity). The enum indicates whether these schemas should be included or excluded from the map.</p>
</div>
<div class="paragraph">
<p>Isis provides a default implementation of the service, <code>o.a.i.schema.services.jaxb.JaxbServiceDefault</code>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_usage_within_the_framework_2">7.5.2. Usage within the framework</h4>
<div class="paragraph">
<p>This service is provided as a convenience for applications, but is also used internally by the framework to
<a href="rgant.html#_rgant-XmlRootElement"><code>@XmlRootElement</code></a>-annotated
<a href="ugbtb.html#_ugbtb_view-models">view models</a>. The functionality to download XML and XSD schemas is also
exposed in the UI through mixins to <a href="rgcms.html#_rgcms_classes_mixins_Dto"><code>Dto</code></a> interface.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_20">7.5.3. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>JaxbService</code> service is automatically registered and injected (it is annotated with <code>@DomainService</code>)
so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_MementoService">7.6. <code>MementoService</code></h3>
<div class="paragraph">
<p>The <code>MementoService</code> was originally introduced to simplify the implementation of
<a href="ugbtb.html#_ugbtb_view-models">ViewModel</a>s which are required by the framework to return string representation of
all of their backing state, moreover which is safe for use within a URL.</p>
</div>
<div class="paragraph">
<p>However, it can also be used to create a memento of arbitrary objects. (Prior to <code>1.13.0-SNAPSHOT) it is used
internally by the core implementation of <a href="#_rgsvc_api_BackgroundService">`BackgroundService</code></a> to capture
the state of action invocations so that they can be executed by a background process.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>As of <code>1.13.0-SNAPSHOT</code> this service is deprecated.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_api_implementation_13">7.6.1. API & Implementation</h4>
<div class="paragraph">
<p>The API defined by <code>MementoService</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Deprecated</span>
<span class="directive">public</span> <span class="type">interface</span> <span class="class">MementoService</span> {
<span class="annotation">@Deprecated</span>
<span class="directive">public</span> <span class="directive">static</span> <span class="type">interface</span> <span class="class">Memento</span> {
<span class="directive">public</span> Memento set(<span class="predefined-type">String</span> name, <span class="predefined-type">Object</span> value);
<span class="directive">public</span> <T> T get(<span class="predefined-type">String</span> name, <span class="predefined-type">Class</span><T> cls);
<span class="directive">public</span> <span class="predefined-type">String</span> asString();
<span class="directive">public</span> <span class="predefined-type">Set</span><<span class="predefined-type">String</span>> keySet();
}
<span class="directive">public</span> Memento create();
<span class="directive">public</span> Memento parse(<span class="directive">final</span> <span class="predefined-type">String</span> str);
<span class="directive">public</span> <span class="type">boolean</span> canSet(<span class="predefined-type">Object</span> input);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The core framework provides a default implementation of this API, namely
<code>o.a.i.c.r.services.memento.MementoServiceDefault</code>. The string returned (from <code>Memento#asString()</code>) is a base-64 URL
encoded representation of the underlying format (an XML string).</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>In fact, the <code>MementoServiceDefault</code> implementation does provide a mechanism to disable the URL encoding, but this is
not part of the <code>MementoService</code> public API. Note also that the encoding method is not pluggable.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The types of objects that are supported by the <code>MementoService</code> are implementation-specific, but would typically
include all the usual value types as well as Apache Isis' <code>Bookmark</code> class (to represent references to arbitrary
entities). Nulls can also be set.</p>
</div>
<div class="paragraph">
<p>In the case of the default implementation provided by the core framework, the types supported are:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>java.lang.String</code></p>
</li>
<li>
<p><code>java.lang.Boolean</code>, <code>boolean</code></p>
</li>
<li>
<p><code>java.lang.Byte</code>, <code>byte</code></p>
</li>
<li>
<p><code>java.lang.Short</code>, <code>short</code></p>
</li>
<li>
<p><code>java.lang.Integer</code>, <code>int</code></p>
</li>
<li>
<p><code>java.lang.Long</code>, <code>long</code></p>
</li>
<li>
<p><code>java.lang.Float</code>, <code>float</code></p>
</li>
<li>
<p><code>java.lang.Double</code>, <code>double</code></p>
</li>
<li>
<p><code>java.lang.Character</code>, <code>char</code></p>
</li>
<li>
<p><code>java.math.BigDecimal</code></p>
</li>
<li>
<p><code>java.math.BigInteger</code></p>
</li>
<li>
<p><code>org.joda.time.LocalDate</code></p>
</li>
<li>
<p><code>org.apache.isis.applib.services.bookmark.Bookmark</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>If using another implementation, the <code>canSet(…​)</code> method can be used to check if the candidate object’s type is supported.</p>
</div>
</div>
<div class="sect3">
<h4 id="_usage_12">7.6.2. Usage</h4>
<div class="paragraph">
<p>As noted in the introduction, a common use case for this service is in the implementation of the <a href="rgcms.html#_rgcms_classes_super_AbstractViewModel"><code>ViewModel</code></a> interface.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Rather than implementing <code>ViewModel</code>, it’s usually easier to annotate your view models with <a href="rgant.html#_rgant-ViewModel"><code>@ViewModel</code></a> (or equivalently <a href="rgant.html#_rgant-DomainObject_nature"><code>@DomainObject#nature=EXTERNAL_ENTITY</code></a> or <a href="rgant.html#_rgant-DomainObject_nature"><code>@DomainObject#nature=INMEMORY_ENTITY</code></a>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>For example, suppose you were implementing a view model that represents an external entity in a SOAP web service. To access this service the view model needs to store (say) the hostname, port number and an id to the object.</p>
</div>
<div class="paragraph">
<p>Using an injected <code>MementoService</code> the view model can roundtrip to and from this string, thus implementing the <code>ViewModel</code> API:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">ExternalEntity</span> <span class="directive">implements</span> ViewModel {
<span class="directive">private</span> <span class="predefined-type">String</span> hostname;
<span class="directive">private</span> <span class="type">int</span> port;
<span class="directive">private</span> <span class="predefined-type">String</span> id;
<span class="directive">public</span> <span class="predefined-type">String</span> viewModelMemento() { <i class="conum" data-value="1"></i><b>(1)</b>
<span class="keyword">return</span> mementoService.create()
.set(<span class="string"><span class="delimiter">"</span><span class="content">hostname</span><span class="delimiter">"</span></span>, hostname)
.set(<span class="string"><span class="delimiter">"</span><span class="content">port</span><span class="delimiter">"</span></span>, port)
.set(<span class="string"><span class="delimiter">"</span><span class="content">id</span><span class="delimiter">"</span></span>, id)
.asString();
}
<span class="directive">public</span> <span class="type">void</span> viewModelInit(<span class="predefined-type">String</span> mementoStr) { <i class="conum" data-value="2"></i><b>(2)</b>
Memento memento = mementoService.parse(mementoStr);
hostname = memento.get(<span class="string"><span class="delimiter">"</span><span class="content">hostname</span><span class="delimiter">"</span></span>, <span class="predefined-type">String</span>.class);
port = memento.get(<span class="string"><span class="delimiter">"</span><span class="content">port</span><span class="delimiter">"</span></span>, <span class="type">int</span>.class);
id = memento.get(<span class="string"><span class="delimiter">"</span><span class="content">id</span><span class="delimiter">"</span></span>, <span class="predefined-type">String</span>.class);
...
<span class="annotation">@Inject</span>
MementoService mementoService;
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>part of the <code>ViewModel</code> API</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>part of the <code>ViewModel</code> API</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_20">7.6.3. Related Services</h4>
<div class="paragraph">
<p>(Prior to <code>1.13.0-SNAPSHOT</code>), the memento service is used by the
<a href="#_rgsvc_api_CommandContext"><code>CommandContext</code></a> service and also
<a href="#_rgsvc_spi_BackgroundCommandService"><code>BackgroundCommandService</code></a>. These both use a memento to capture a
representation of an action invocation.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_21">7.6.4. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>MementoService</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_XmlSnapshotService">7.7. <code>XmlSnapshotService</code></h3>
<div class="paragraph">
<p>The <code>XmlSnapshotService</code> provides the capability to generate XML snapshots (and if required corresponding XSD schemas) based on graphs of domain objects.</p>
</div>
<div class="paragraph">
<p>Typical use cases include creating mementos for business-focused auditing, such that a report could be generated as to which end-user performed a business action (perhaps for legal reasons). For one system that we know of, a digest of this snapshot of data is signed with the public encryption key so as to enforce non-repudiation.</p>
</div>
<div class="paragraph">
<p>Another use case is to grab raw data such that it could be merged into a report template or communication.</p>
</div>
<div class="paragraph">
<p>The service offers a basic API to create a snapshot of a single object, and an more flexible API that allows the size of the graph to be customized.</p>
</div>
<div class="paragraph">
<p>The core framework provides an implementation of this service (<code>o.a.i.core.runtime.services.xmlsnapshot.XmlSnapshotServiceDefault</code>).</p>
</div>
<div class="sect3">
<h4 id="_standard_api">7.7.1. Standard API</h4>
<div class="paragraph">
<p>The (basic) API of <code>XmlSnapshotService</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code>public interface XmlSnapshotService {
public interface Snapshot {
Document getXmlDocument();
Document getXsdDocument();
String getXmlDocumentAsString();
String getXsdDocumentAsString();
}
@Programmatic
public XmlSnapshotService.Snapshot snapshotFor(Object domainObject);
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The most straight-forward usage of this service is simply:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">XmlSnapshot snapshot = xmlsnapshotService.snapshotFor(customer);
<span class="predefined-type">Element</span> customerAsXml = snapshot.getXmlElement();</code></pre>
</div>
</div>
<div class="paragraph">
<p>This will return an XML (document) element that contains the names and values of each of the customer’s value properties, along with the titles of reference properties, and also the number of items in collections.</p>
</div>
<div class="paragraph">
<p>As well as obtaining the XML snapshot, it is also possible to obtain an XSD schema that the XML snapshot conforms to.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code>XmlSnapshot snapshot = ...;
Element customerAsXml = snapshot.getXmlElement();
Element customerXsd = snapshot.getXsdElement();</code></pre>
</div>
</div>
<div class="paragraph">
<p>This can be useful for some tools. For example, <a href="http://www.altova.com/stylevision.html">Altova Stylevision</a> can use the XML and XSD to transform into reports. Please note that this link does not imply endorsement (nor even a recommendation that this is a good design).</p>
</div>
</div>
<div class="sect3">
<h4 id="_builder_api">7.7.2. Builder API</h4>
<div class="paragraph">
<p>The contents of the snapshot can be adjusted by including "paths" to other references or collections. To do this, the
builder is used. The API for this is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">XmlSnapshotService</span> {
...
public <span class="type">interface</span> <span class="class">Builder</span> {
<span class="type">void</span> includePath(<span class="directive">final</span> <span class="predefined-type">String</span> path);
<span class="type">void</span> includePathAndAnnotation(<span class="predefined-type">String</span> path, <span class="predefined-type">String</span> annotation);
XmlSnapshotService.Snapshot build();
}
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> XmlSnapshotService.Builder builderFor(<span class="predefined-type">Object</span> domainObject);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>We start by obtaining a builder:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">XmlSnapshot.Builder builder = xmlsnapshotService.builderFor(customer);</code></pre>
</div>
</div>
<div class="paragraph">
<p>Suppose now that we want the snapshot to also include details of the customer’s address, where <code>address</code> in this case is a reference property to an instance of the <code>Address</code> class. We can "walk-the-graph" by including these references within the builder.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">builder.includePath(<span class="string"><span class="delimiter">"</span><span class="content">address</span><span class="delimiter">"</span></span>);</code></pre>
</div>
</div>
<div class="paragraph">
<p>We could then go further and include details of every order in the customer’s <code>orders</code> collection, and details of every
product of every order:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">builder.includePath(<span class="string"><span class="delimiter">"</span><span class="content">orders/product</span><span class="delimiter">"</span></span>);</code></pre>
</div>
</div>
<div class="paragraph">
<p>When all paths are included, then the builder can build the snapshot:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">XmlSnapshot snapshot = builder.build();
<span class="predefined-type">Element</span> customerAsXml = snapshot.getXmlElement();</code></pre>
</div>
</div>
<div class="paragraph">
<p>All of this can be strung together in a fluent API:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="predefined-type">Element</span> customerAsXml = xmlsnapshotService.builderFor(customer)
.includePath(<span class="string"><span class="delimiter">"</span><span class="content">address</span><span class="delimiter">"</span></span>)
.includePath(<span class="string"><span class="delimiter">"</span><span class="content">orders/product</span><span class="delimiter">"</span></span>)
.build()
.getXmlElement();</code></pre>
</div>
</div>
<div class="paragraph">
<p>As you might imagine, the resultant XML document can get quite large very quickly with only a few "include"s.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>If an XSD schema is beng generated (using <code>snapshot.getXsdElement()</code> then note that for the XSD to be correct, the object being snapshotted must have non-null values for the paths that are `include()’d. If this isn’t done then the XSD will not be correct reflect for another snapshotted object that does have non-null values.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_automatic_inclusions">7.7.3. Automatic inclusions</h4>
<div class="paragraph">
<p>If the domain object being snapshotted implements the <code>SnapshottableWithInclusions</code> interace, then this moves the
responsibility for determining what is included within the snapshot from the caller to the snapshottable object itself:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code>public interface SnapshottableWithInclusions extends Snapshottable {
List<String> snapshotInclusions();
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>If necessary, both approaches can be combined.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>As an alternative to using <code>include()</code>, you might consider building a view model domain object which can reference only the relevant information required for the snapshot. For example, if only the 5 most recent Orders for a Customer were required, a <code>CustomerAndRecentOrders</code> view model could hold a collection of just those 5 <code>Order</code>s. Typically such view models would implement <code>SnapshottableWithInclusions</code>.</p>
</div>
<div class="paragraph">
<p>One reason for doing this is to provide a stable API between the domain model and whatever it is that might be consuming the XML. With a view model you can refactor the domain entities but still preserve a view model such that the XML is the same.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_convenience_api">7.7.4. Convenience API</h4>
<div class="paragraph">
<p>The <code>XmlSnapshotService</code> also provides some API for simply manipulating XML:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code>public interface XmlSnapshotService {
...
@Programmatic
public Document asDocument(String xmlStr); <i class="conum" data-value="1"></i><b>(1)</b>
@Programmatic
public <T> T getChildElementValue( <i class="conum" data-value="2"></i><b>(2)</b>
Element el, String tagname, Class<T> expectedCls);
@Programmatic
public Element getChildElement( <i class="conum" data-value="3"></i><b>(3)</b>
Element el, String tagname);
@Programmatic
public String getChildTextValue(Element el); <i class="conum" data-value="4"></i><b>(4)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>is a convenience method to convert xml string back into a W3C Document</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>is a convenience method to extract the value of an XML element, based on its type.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>is a convenience method to walk XML document.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>is a convenience method to obtain value of child text node.</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_22">7.7.5. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>XmlSnapshotService</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_21">7.7.6. Related Services</h4>
<div class="paragraph">
<p>The <a href="#_rgsvc_api_BookmarkService"><code>BookmarkService</code></a> provides a mechanism for obtaining a string representations of a single domain object.</p>
</div>
<div class="paragraph">
<p>The <a href="#_rgsvc_api_MementoService"><code>MementoService</code></a> also provides a mechanism for generating string representations of domain objects.</p>
</div>
<div class="paragraph">
<p>The <a href="#_rgsvc_api_JaxbService"><code>JaxbService</code></a> is a simple wrapper around
standard JAXB functionality for generating both XMLs and XSDs from JAXB-annotated classes. Note that there is built-in support for JAXB classes (ie annotated with
<a href="rgant.html#_rgant-XmlRootElement"><code>@XmlRootElement</code></a>) to be used as view models.</p>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_rgsvc_metadata-api">8. Metadata API</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The metadata APIs provide access to the framework’s internal metamodel. These are generally of use to support development-time activities, for example creating custom UIs through Swagger.</p>
</div>
<div class="paragraph">
<p>The table below summarizes the metadata APIs defined by Apache Isis. It also lists their corresponding implementation, either a default implementation provided by Apache Isis itself, or provided by one of the in (non-ASF) <a href="http://www.isisaddons.org">Isis Addons</a> modules.</p>
</div>
<table class="tableblock frame-all grid-all spread">
<caption class="title">Table 7. Metadata API</caption>
<colgroup>
<col style="width: 25%;">
<col style="width: 50%;">
<col style="width: 12.5%;">
<col style="width: 12.5%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">API</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Implementation</th>
<th class="tableblock halign-left valign-top">Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_ApplicationFeatureRepository"><code>o.a.i.applib.</code><br>
<code>services.appfeat</code><br>
<code>ApplicationFeatureRepository</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Provides access to string representations of the features (package, class, class members) of the domain classes
within the metamodel.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>ApplicationFeatureDefault</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-metamodel</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">(not visible in UI)</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_LayoutService"><code>o.a.i.applib.</code><br>
<code>services.layout</code><br>
<code>LayoutService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Provides the ability to download dynamic layout XML files, in various styles.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>LayoutServiceDefault</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-metamodel</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Functionality surfaced in the UI through related mixin and menu.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_MetaModelService"><code>o.a.i.applib.</code><br>
<code>services.metamodel</code><br>
<code>MetaModelService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Access to certain information from the Apache Isis metamodel.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>MetaModelServiceDefault</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-metamodel</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Functionality surfaced in the UI through related menu.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_ServiceRegistry"><code>o.a.i.applib.</code><br>
<code>services.registry</code><br>
<code>ServiceRegistry</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Methods to access and use other domain services.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>ServiceRegistry-</code><br>
<code>Default</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-metamodel</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Supercedes methods in <a href="#_rgsvc_api_DomainObjectContainer"><code>DomainObjectContainer</code></a>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_SwaggerService"><code>o.a.i.applib.</code><br>
<code>services.swagger</code><br>
<code>SwaggerService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Generates <a href="http://swagger.io/">Swagger</a> spec files to describe the public and/or private RESTful APIs exposed by the <a href="ugvro.html">RestfulObjects viewer</a>. These can then be used with the <a href="http://swagger.io/swagger-ui/">Swagger UI</a> page to explore the REST API, or used to generate client-side stubs using the <a href="http://swagger.io/swagger-codegen/">Swagger codegen</a> tool, eg for use in a custom REST client app.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>SwaggerServiceDefault</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-metamodel</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">A <code>SwaggerServiceMenu</code> domain service is also provided which enables the swagger spec to be downloaded. Apache Isis' <a href="#rgmvn.adoc">Maven plugin</a> also provides a <a href="rgmvn.html#_rgmvn_swagger">swagger goal</a> which allows the spec file(s) to be generated at build time (eg so that client-side stubs can then be generated in turn).</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Key:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>o.a.i</code> is an abbreviation for <code>org.apache.isis</code></p>
</li>
<li>
<p><code>o.ia.m</code> is an abbreviation for <code>org.isisaddons.module</code></p>
</li>
<li>
<p><code>o.a.i.c.m.s</code> is an abbreviation for <code>org.apache.isis.core.metamodel.services</code></p>
</li>
<li>
<p><code>o.a.i.c.r.s</code> is an abbreviation for <code>org.apache.isis.core.runtime.services</code></p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_ApplicationFeatureRepository">8.1. <code>ApplicationFeatureRepository</code></h3>
<div class="paragraph">
<p>The <code>ApplicationFeatureRepository</code> provides the access to string representations of the packages, classes and
class members (collectively: "application features") of the domain classes within the Apache Isis' internal metamodel.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>This functionality was originally implemented as part of (non-ASF) <a href="http://isisaddons.org">Isis Addons</a> security
module, where the string representations of the various features are used to represent permissions.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_api_implementation_14">8.1.1. API & Implementation</h4>
<div class="paragraph">
<p>The API defined by the service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">ApplicationFeatureRepository</span> {
<span class="predefined-type">List</span><<span class="predefined-type">String</span>> packageNames();
<span class="predefined-type">List</span><<span class="predefined-type">String</span>> packageNamesContainingClasses(ApplicationMemberType memberType);
<span class="predefined-type">List</span><<span class="predefined-type">String</span>> classNamesContainedIn(<span class="predefined-type">String</span> packageFqn, ApplicationMemberType memberType);
<span class="predefined-type">List</span><<span class="predefined-type">String</span>> classNamesRecursivelyContainedIn(<span class="predefined-type">String</span> packageFqn);
<span class="predefined-type">List</span><<span class="predefined-type">String</span>> memberNamesOf(<span class="predefined-type">String</span> packageFqn, <span class="predefined-type">String</span> className, ApplicationMemberType memberType);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>where <code>ApplicationMemberType</code> in turn is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">enum</span> ApplicationMemberType {
PROPERTY,
COLLECTION,
ACTION;
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>These methods are designed primarily to return lists of strings for use in drop-downs.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_23">8.1.2. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>ApplicationFeatureRepository</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_LayoutService">8.2. <code>LayoutService</code></h3>
<div class="paragraph">
<p>The <code>LayoutService</code> provides the ability to obtain the XML layout for a single domain object or for all domain
objects. This functionality is surfaced through the user interface through a related <a href="#_rgsvc_api_LayoutService_related-mixins-and-menus">mixin and menu action</a>.</p>
</div>
<div class="sect3">
<h4 id="_rgsvc_api_LayoutService_api-and-implementation">8.2.1. API & Implementation</h4>
<div class="paragraph">
<p>The API defined by <code>LayoutService</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">LayoutService</span> {
<span class="predefined-type">String</span> toXml(<span class="predefined-type">Class</span><?> domainClass, <span class="predefined-type">Style</span> style); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="type">byte</span><span class="type">[]</span> toZip(<span class="predefined-type">Style</span> style); <i class="conum" data-value="2"></i><b>(2)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Returns the serialized XML form of the layout (grid) for the specified domain class, in specified style (discussed below).</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Returns (a byte array) of a zip of the serialized XML of the layouts (grids), for all domain entities and view models.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The <code>Style</code> enum is defined as:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">enum</span> <span class="predefined-type">Style</span> {
CURRENT,
COMPLETE,
NORMALIZED,
MINIMAL
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>CURRENT</code> style corresponds to the layout already loaded for the domain class, typically from an already persisted
<code>layout.xml</code> file. The other three styles allow the developer to choose how much metadata is to be specified in the
XML, and how much (if any) will be obtained elsewhere, typically from annotations in the metamodel (but also from
<code>.layout.json</code> file if present). The table below summarises the choices:</p>
</div>
<table class="tableblock frame-all grid-all spread">
<caption class="title">Table 8. Table caption</caption>
<colgroup>
<col style="width: 25%;">
<col style="width: 25%;">
<col style="width: 25%;">
<col style="width: 25%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-bottom">Style</th>
<th class="tableblock halign-center valign-bottom"><a href="rgant.html#_rgant-MemberGroupLayout"><code>@MemberGroupLayout</code></a></th>
<th class="tableblock halign-center valign-bottom"><a href="rgant.html#_rgant-MemberOrder"><code>@MemberOrder</code></a></th>
<th class="tableblock halign-center valign-bottom"><a href="rgant.html#_rgant-ActionLayout"><code>@ActionLayout</code></a>, <a href="rgant.html#_rgant-PropertyLayout"><code>@PropertyLayout</code></a>, <a href="rgant.html#_rgant-CollectionLayout"><code>@CollectionLayout</code></a></th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-bottom"><p class="tableblock"><code>COMPLETE</code></p></td>
<td class="tableblock halign-center valign-bottom"><p class="tableblock">serialized as XML</p></td>
<td class="tableblock halign-center valign-bottom"><p class="tableblock">serialized as XML</p></td>
<td class="tableblock halign-center valign-bottom"><p class="tableblock">serialized as XML</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-bottom"><p class="tableblock"><code>NORMALIZED</code></p></td>
<td class="tableblock halign-center valign-bottom"><p class="tableblock">serialized as XML</p></td>
<td class="tableblock halign-center valign-bottom"><p class="tableblock">serialized as XML</p></td>
<td class="tableblock halign-center valign-bottom"><p class="tableblock">not in the XML</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-bottom"><p class="tableblock"><code>MINIMAL</code></p></td>
<td class="tableblock halign-center valign-bottom"><p class="tableblock">serialized as XML</p></td>
<td class="tableblock halign-center valign-bottom"><p class="tableblock">not in the XML</p></td>
<td class="tableblock halign-center valign-bottom"><p class="tableblock">not in the XML</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>As a developer, you therefore have a choice as to how you provide the metadata required for customised layouts:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>if you want all layout metadata to be read from the <code>.layout.xml</code> file, then download the "complete" version, and copy the file alongside the domain class. You can then remove all <code>@MemberGroupLayout</code>, <code>@MemberOrder</code>, <code>@ActionLayout</code>, <code>@PropertyLayout</code> and <code>@CollectionLayout</code> annotations from the source code of the domain class.</p>
</li>
<li>
<p>if you want to use layout XML file to describe the grid (columns, tabs etc) and specify which object members are associated with those regions of the grid, then download the "normalized" version. You can then remove the <code>@MemberGroupLayout</code> and <code>@MemberOrder</code> annotations from the source code of the domain class, but retain the <code>@ActionLayout</code>, <code>@PropertyLayout</code> and <code>@CollectionLayout</code> annotations.</p>
</li>
<li>
<p>if you want to use layout XML file ONLY to describe the grid, then download the "minimal" version. The grid regions will be empty in this version, and the framework will use the <code>@MemberOrder</code> annotation to bind object members to those regions. The only annotation that can be safely removed from the source code with this style is the <code>@MemberGroupLayout</code> annotation.</p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="_rgsvc_api_LayoutService_related-mixins-and-menus">8.2.2. Related Mixins and Menus</h4>
<div class="paragraph">
<p>The service’s functionality is exposed in the UI through a mixin (per object) and a menu action (for all objects):</p>
</div>
<div class="ulist">
<ul>
<li>
<p>the <a href="rgant.html#_rgcms_classes_mixins_Object"><code>Object</code> mixin</a> provides the ability to download the XML layout for
any domain object (entity or view model).</p>
</li>
<li>
<p>the <code>LayoutServiceMenu</code> provides the ability to download all XML layouts as a single ZIP file (in any of the
three styles).</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The XML can then be copied into the codebase of the application, and annotations in the domain classes removed as
desired.</p>
</div>
</div>
<div class="sect3">
<h4 id="_rgsvc_api_LayoutService_related-domain-services">8.2.3. Related Domain Services</h4>
<div class="paragraph">
<p>The <a href="#_rgsvc_spi_GridService"><code>GridService</code></a> is responsible for loading and normalizing layout XML for
a domain class. It in turn uses the <a href="#_rgsvc_spi_GridLoaderService"><code>GridLoaderService</code></a> and <a href="#_rgsvc_spi_GridSystemService"><code>GridSystemService</code></a>
services.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_MetaModelService">8.3. <code>MetaModelService</code></h3>
<div class="paragraph">
<p>The <code>MetaModelService2</code> (<code>MetaModelService2</code> sub-interface introduced in <code>1.13.0-SNAPSHOT</code>) provides access to
a number of aspects of Apache Isis' internal metamodel.</p>
</div>
<div class="sect3">
<h4 id="_api_6">8.3.1. API</h4>
<div class="paragraph">
<p>The API defined by the service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">MetaModelService2</span> {
<span class="predefined-type">Class</span><?> fromObjectType(<span class="directive">final</span> <span class="predefined-type">String</span> objectType); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="predefined-type">String</span> toObjectType(<span class="directive">final</span> <span class="predefined-type">Class</span><?> domainType); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="type">void</span> rebuild(<span class="directive">final</span> <span class="predefined-type">Class</span><?> domainType); <i class="conum" data-value="3"></i><b>(3)</b>
<span class="predefined-type">List</span><DomainMember> <span class="keyword">export</span>(); <i class="conum" data-value="4"></i><b>(4)</b>
<span class="type">enum</span> Sort { <i class="conum" data-value="5"></i><b>(5)</b>
VIEW_MODEL, JDO_ENTITY, DOMAIN_SERVICE,
MIXIN, VALUE, COLLECTION;
}
Sort sortOf(<span class="directive">final</span> <span class="predefined-type">Class</span><?> domainType);
Sort sortOf(<span class="directive">final</span> Bookmark bookmark);
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>reverse lookup of a domain class' object type</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>lookup of a domain class' object type</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>invalidate and rebuild the internal metadata (an <code>ObjectSpecification</code>) for the specified domain type.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>returns a list of representations of each of member of each domain class.</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>(<code>1.13.0-SNAPSHOT</code>) what sort of object a domain type is (or bookmark represents)</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_24">8.3.2. Implementation</h4>
<div class="paragraph">
<p>The framework provides a default implementation of this service, <code>o.a.i.c.m.services.metamodel.MetaModelServiceDefault</code>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_24">8.3.3. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>MetamodelService</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_22">8.3.4. Related Services</h4>
<div class="paragraph">
<p>The <code>MetaModelServiceMenu</code> provides a method to download all domain members as a CSV. Internally
this calls <code>MetaModelService#export()</code>. Under the covers this uses the API provided by the
<a href="#_rgsvc_api_ApplicationFeatureRepository"><code>ApplicationFeatureRepository</code></a> domain service.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_ServiceRegistry">8.4. <code>ServiceRegistry2</code></h3>
<div class="paragraph">
<p>The <code>ServiceRegistry2</code> service collects together methods for accessing other domain services. (The <code>ServiceRegistry2</code> extension to the original <code>ServiceRegistry</code> API has been introduced in <code>1.13.0-SNAPSHOT</code>).</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The methods in this service replace similar methods (now deprecated) in <a href="#_rgsvc_api_DomainObjectContainer"><code>DomainObjectContainer</code></a>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_api_7">8.4.1. API</h4>
<div class="paragraph">
<p>The API of <code>ServiceRegistry</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">ServiceRegistry2</span> {
<T> T injectServicesInto(<span class="directive">final</span> T domainObject); <i class="conum" data-value="1"></i><b>(1)</b>
<T> T lookupService(<span class="predefined-type">Class</span><T> service); <i class="conum" data-value="2"></i><b>(2)</b>
<T> <span class="predefined-type">Iterable</span><T> lookupServices(<span class="predefined-type">Class</span><T> service); <i class="conum" data-value="3"></i><b>(3)</b>
<span class="predefined-type">List</span><<span class="predefined-type">Object</span>> getRegisteredServices(); <i class="conum" data-value="4"></i><b>(4)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>injects services into domain object; used extensively internally by the framework (eg to inject to other services, or to entities, or integration test instances, or fixture scripts).</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>returns the first registered service that implements the specified class</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>returns an <code>Iterable</code> in order to iterate over all registered services that implement the specified class</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>(<code>1.13.0-SNAPSHOT</code>) returns the list of all domain services that constitute the running application (including internal domain services).</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Service injection is done automatically if objects are created using the .adoc#_rgsvc_api_FactoryService[<code>FactoryService</code>]</p>
</div>
</div>
<div class="sect3">
<h4 id="_usage_13">8.4.2. Usage</h4>
<div class="paragraph">
<p>The primary use case is to instantiate domain objects using a regular constructor ("new is the new new"), and then using the <code>#injectServicesInto(…​)</code> API to set up any dependencies.</p>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Customer cust = serviceRegistry.injectServicesInto( <span class="keyword">new</span> Customer());
cust.setFirstName(<span class="string"><span class="delimiter">"</span><span class="content">Freddie</span><span class="delimiter">"</span></span>);
cust.setLastName(<span class="string"><span class="delimiter">"</span><span class="content">Mercury</span><span class="delimiter">"</span></span>);
repositoryService.persist(cust);</code></pre>
</div>
</div>
<div class="paragraph">
<p>The alternative is to use the <a href="#_rgsvc_api_FactoryService"><code>FactoryService</code></a> API which performs both steps in a single factory method.</p>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_25">8.4.3. Implementation</h4>
<div class="paragraph">
<p>The core framework provides a default implementation of this service (<code>o.a.i.core.runtime.services.registry.ServiceRegistryDefault</code>).</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_25">8.4.4. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>ServiceRegistry</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_SwaggerService">8.5. <code>SwaggerService</code></h3>
<div class="paragraph">
<p>The <code>SwaggerService</code> generates <a href="http://swagger.io/">Swagger</a> spec files to describe the public and/or private RESTful APIs exposed by the <a href="ugvro.html">RestfulObjects viewer</a>.</p>
</div>
<div class="paragraph">
<p>These spec files can then be used with the <a href="http://swagger.io/swagger-ui/">Swagger UI</a> page to explore the REST API, or used to generate client-side stubs using the <a href="http://swagger.io/swagger-codegen/">Swagger codegen</a> tool, eg for use in a custom REST client app.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Not all of the REST API exposed by the <a href="ugvro.html">Restful Objects viewer</a> is included in the Swagger spec files; the emphasis is those REST resources that are used to develop custom apps: domain objects, domain object collections and action invocations. When combined with Apache Isis' own <a href="ugvro.html#_ugvro_simplified-representations">simplified representations</a>, these are pretty much all that is needed for this use case.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_rgsvc_api_SwaggerService_api-and-implementation">8.5.1. API & Implementation</h4>
<div class="paragraph">
<p>The API defined by <code>SwaggerService</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">SwaggerService</span> {
<span class="type">enum</span> <span class="predefined-type">Visibility</span> {
PUBLIC, <i class="conum" data-value="1"></i><b>(1)</b>
PRIVATE, <i class="conum" data-value="2"></i><b>(2)</b>
PRIVATE_WITH_PROTOTYPING; <i class="conum" data-value="3"></i><b>(3)</b>
}
<span class="type">enum</span> <span class="predefined-type">Format</span> { <i class="conum" data-value="4"></i><b>(4)</b>
JSON,
YAML
}
<span class="predefined-type">String</span> generateSwaggerSpec(<span class="directive">final</span> <span class="predefined-type">Visibility</span> visibility, <span class="directive">final</span> <span class="predefined-type">Format</span> format);
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Generate a Swagger spec for use by third-party clients, ie public use. This specification is restricted only to
<a href="ugbtb.html#_ugbtb_view-models">view model</a>s and to domain services with a <a href="rgant.html#_rgant-DomainService_nature">nature</a> of <code>VIEW_REST_ONLY</code>.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Generate a Swagger spec for use only by internally-managed clients, ie private internal use. This specification includes domain entities and all menu domain services (as well as any view models).</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Generate a Swagger spec that is the same as private case (above), but also including any <a href="rgant.html#_rgant-Action_restrictTo">prototype</a> actions.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>Swagger specs can be written either in JSON or YAML format.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Isis provides a default implementation of the service, <code>o.a.i.core.metamodel.services.swagger.SwaggerServiceDefault</code>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_usage_within_the_framework_3">8.5.2. Usage within the framework</h4>
<div class="paragraph">
<p>This service is provided as a convenience for applications, it is not (currently) used by the framework itself.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_26">8.5.3. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>SwaggerService</code> service is automatically registered and injected (it is annotated with <code>@DomainService</code>) so no further configuration is required.</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_23">8.5.4. Related Services</h4>
<div class="paragraph">
<p>A <code>SwaggerServiceMenu</code> domain service provides a prototype action that enables the swagger spec to be downloaded from the Wicket viewer’s UI.</p>
</div>
<div class="paragraph">
<p>Apache Isis' <a href="#rgmvn.aod">Maven plugin</a> also provides a <a href="rgmvn.html#_rgmvn_swagger">swagger goal</a> which allows the spec file(s) to be generated at build time. this then allows client-side stubs can then be generated in turn as part of a build pipeline.</p>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_rgsvc_testing">9. Testing</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The testing APIs provide functionality to domain objects for use when testing or demoing an application.</p>
</div>
<div class="paragraph">
<p>The testing SPIs allow the framework to provide supporting functionality for use when testing or demoing an application.</p>
</div>
<div class="paragraph">
<p>The table below summarizes the testing APIs defined by Apache Isis. It also lists their corresponding implementation, either a default implementation provided by Apache Isis itself, or provided by one of the in (non-ASF) <a href="http://www.isisaddons.org">Isis Addons</a> modules.</p>
</div>
<table class="tableblock frame-all grid-all spread">
<caption class="title">Table 9. Testing API</caption>
<colgroup>
<col style="width: 25%;">
<col style="width: 50%;">
<col style="width: 12.5%;">
<col style="width: 12.5%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">API</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Implementation</th>
<th class="tableblock halign-left valign-top">Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_FixtureScriptsDefault"><code>o.a.i.applib.</code><br>
<code>services.</code><br>
<code>fixturespec</code><br>
<code>FixtureScriptsDefault</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Fallback implementation of <a href="rgcms.html#_rgcms_classes_super_FixtureScripts"><code>FixtureScripts</code></a>, providing the ability to execute fixture scripts.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>FixtureScriptsDefault</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-applib</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Interacts with <a href="#_rgsvc_spi_FixtureScriptsSpecificationProvider"><code>FixtureScripts-
SpecificationProvider</code></a>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_FixtureScriptsSpecificationProvider"><code>o.a.i.applib.</code><br>
<code>services.fixturespec</code><br>
<code>FixtureScripts-</code><br>
<code>SpecificationProvider</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Provides settings for <a href="#_rgsvc_api_FixtureScriptsDefault"><code>FixtureScriptsDefault</code></a> fallback domain service for executing fixture scripts.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_SudoService"><code>o.a.i.applib.</code><br>
<code>services.sudo</code><br>
<code>SudoService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>For use in testing while running <a href="rgcms.html#_rgcms_classes_super_FixtureScripts">fixture scripts</a>, allows a block of code to run as a specified user account.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>SudoServiceDefault</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-runtime</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">API is also a concrete class</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>The table below summarizes the testing SPIs defined by Apache Isis. It also lists their corresponding implementation, either a default implementation provided by Apache Isis itself, or provided by one of the in (non-ASF) <a href="http://www.isisaddons.org">Isis Addons</a> modules.</p>
</div>
<table class="tableblock frame-all grid-all spread">
<caption class="title">Table 10. Testing SPI</caption>
<colgroup>
<col style="width: 25%;">
<col style="width: 50%;">
<col style="width: 12.5%;">
<col style="width: 12.5%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">SPI</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Implementation</th>
<th class="tableblock halign-left valign-top">Notes</th>
</tr>
</thead>
</table>
<div class="sect2">
<h3 id="_rgsvc_api_FixtureScriptsDefault">9.1. <code>FixtureScriptsDefault</code></h3>
<div class="paragraph">
<p>The <code>FixtureScriptsDefault</code> service provides the ability to execute <a href="ugtst.html#_ugtst_fixture-scripts_api-and-usage">fixture scripts</a> .</p>
</div>
<div class="paragraph">
<p>The service extends from the <a href="rgcms.html#_rgcms_classes_super_FixtureScripts"><code>FixtureScripts</code></a>, and is only instantiated by the framework if there no custom implementation of <code>FixtureScripts</code> has been otherwise provided; in other words it is a fallback.</p>
</div>
<div class="paragraph">
<p>If this service is instantiated (as a fallback) then it uses the <a href="#_rgsvc_spi_FixtureScriptsSpecificationProvider"><code>FixtureScriptsSpecificationProvider</code></a> to obtain a <code>FixtureScriptsSpecification</code>. This configures this service, telling it which package to search for <code>FixtureScript</code> classes, how to execute those classes, and hints that influence the UI.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>We recommend using <a href="#_rgsvc_spi_FixtureScriptsSpecificationProvider"><code>FixtureScriptsSpecificationProvider</code></a> rather than subclassing <a href="rgcms.html#_rgcms_classes_super_FixtureScripts"><code>FixtureScripts</code></a>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_api_implementation_15">9.1.1. API & Implementation</h4>
<div class="paragraph">
<p>The API for the service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">FixtureScriptsDefault</span> ... {
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <span class="predefined-type">List</span><FixtureResult> runFixtureScript(
FixtureScript fixtureScript,
<span class="predefined-type">String</span> parameters) { ... }
}</code></pre>
</div>
</div>
<div class="olist lowerroman">
<ol class="lowerroman" type="i">
<li>
<p>in other words the same as <a href="rgcms.html#_rgcms_classes_super_FixtureScripts"><code>FixtureScripts</code></a> superclass that it inherits from.</p>
</li>
</ol>
</div>
</div>
<div class="sect3">
<h4 id="_configuration_2">9.1.2. Configuration</h4>
<div class="paragraph">
<p>As noted in the introduction, this service is only instantiated if there is no other implementation of <code>FixtureScripts</code> available on the classpath.</p>
</div>
<div class="paragraph">
<p>If an instance of <code>FixtureScriptsSpecificationProvider</code> is available on the classpath, then the service will be visible in the UI (assuming <a href="rgcfg.html#_rgcfg_deployment-types">prototype mode</a>). Otherwise the service will be available only to be injected and invoked programmatically.</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_24">9.1.3. Related Services</h4>
<div class="paragraph">
<p>The service interacts with <a href="#_rgsvc_spi_FixtureScriptsSpecificationProvider"><code>FixtureScriptsSpecificationProvider</code></a>.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_SudoService">9.2. <code>SudoService</code></h3>
<div class="paragraph">
<p>The <code>SudoService</code> allows the current user reported by the <code>DomainObjectContainer</code> to be temporarily changed to some
other user. This is useful both for <a href="ugtst.html#_ugtst_integ-test-support">integration testing</a> (eg if testing a workflow system whereby objects are moved from one user to another) and while running <a href="ugtst.html#_ugtst_fixture-scripts">fixture scripts</a> (eg setting up objects that would normally require several users to have acted upon the objects).</p>
</div>
<div class="sect3">
<h4 id="_api_implementation_16">9.2.1. API & Implementation</h4>
<div class="paragraph">
<p>The API provided by the service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">SudoService</span> {
<span class="annotation">@Programmatic</span>
<span class="type">void</span> sudo(<span class="predefined-type">String</span> username, <span class="directive">final</span> <span class="predefined-type">Runnable</span> runnable);
<span class="annotation">@Programmatic</span>
<T> T sudo(<span class="predefined-type">String</span> username, <span class="directive">final</span> <span class="predefined-type">Callable</span><T> callable);
<span class="annotation">@Programmatic</span>
<span class="type">void</span> sudo(<span class="predefined-type">String</span> username, <span class="predefined-type">List</span><<span class="predefined-type">String</span>> roles, <span class="directive">final</span> <span class="predefined-type">Runnable</span> runnable);
<span class="annotation">@Programmatic</span>
<T> T sudo(<span class="predefined-type">String</span> username, <span class="predefined-type">List</span><<span class="predefined-type">String</span>> roles, <span class="directive">final</span> <span class="predefined-type">Callable</span><T> callable);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>which will run the provided block of code (a <code>Runnable</code> or a <code>Callable</code>) in a way such that calls to
<code>DomainObjectContainer#getUser()</code> will return the specified user (and roles, if specified)</p>
</div>
<div class="paragraph">
<p>The core framework provides a default implementation of this service (<code>o.a.i.core.runtime.services.sudo.SudoServiceDefault</code>).</p>
</div>
</div>
<div class="sect3">
<h4 id="_usage_14">9.2.2. Usage</h4>
<div class="paragraph">
<p>A good example can be found in the (non-ASF) <a href="http://github.com/isisaddons/isis-app-todoapp">Isis addons' todoapp</a> which uses the <code>SudoService</code> in a fixture script to set up <code>ToDoItem</code> objects:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">protected</span> <span class="type">void</span> execute(<span class="directive">final</span> ExecutionContext ec) {
...
sudoService.sudo(getUsername(),
<span class="keyword">new</span> <span class="predefined-type">Runnable</span>() {
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="type">void</span> run() {
wrap(toDoItem).completed();
}
});
...
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_27">9.2.3. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>SudoService</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_FixtureScriptsSpecificationProvider">9.3. <code>FixtureScriptsSpec’nProvider</code></h3>
<div class="paragraph">
<p>The <code>FixtureScriptsSpecificationProvider</code> configures the
<a href="#_rgsvc_api_FixtureScriptsDefault"><code>FixtureScriptsDefault</code></a> domain service, providing the
location to search for fixture scripts and other settings.</p>
</div>
<div class="paragraph">
<p>The service is only used if the <code>FixtureScriptsDefault</code> service is instantiated as a fallback by the framework. If
the application provides its own subclass of <a href="rgcms.html#_rgcms_classes_super_FixtureScripts"><code>FixtureScripts</code></a>
superclass, then this provider service is not used.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Of the two designs, we encourage you to implement this "provider" SPI rather than subclass <code>FixtureScripts</code>. The
primary benefit (apart from decoupling responsibilities) is that it ensures that there is always an instance of
<code>FixtureScripts</code> available for use.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_spi_17">9.3.1. SPI</h4>
<div class="paragraph">
<p>The SPI defined by the service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">FixtureScriptsSpecificationProvider</span> {
<span class="annotation">@Programmatic</span>
FixtureScriptsSpecification getSpecification();
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>where <code>FixtureScriptsSpecification</code> exposes these values:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">FixtureScriptsSpecification</span> {
<span class="directive">public</span> <span class="predefined-type">String</span> getPackagePrefix() { ... }
<span class="directive">public</span> FixtureScripts.NonPersistedObjectsStrategy getNonPersistedObjectsStrategy() { ... }
<span class="directive">public</span> FixtureScripts.MultipleExecutionStrategy getMultipleExecutionStrategy() { ... }
<span class="directive">public</span> <span class="predefined-type">Class</span><? <span class="directive">extends</span> FixtureScript> getRunScriptDefaultScriptClass() { ... }
<span class="directive">public</span> DropDownPolicy getRunScriptDropDownPolicy() { ... }
<span class="directive">public</span> <span class="predefined-type">Class</span><? <span class="directive">extends</span> FixtureScript> getRecreateScriptClass() { ... }
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The class is immutable but it has a builder (obtained using <code>FixturescriptsSpecification.builder(…​)</code>) for a fluent API.</p>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_26">9.3.2. Implementation</h4>
<div class="paragraph">
<p>The <a href="ugfun.html#_ugfun_getting-started_simpleapp-archetype">SimpleApp archetype</a> has a simple implementation of this service:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>(nature = NatureOfService.DOMAIN)
<span class="directive">public</span> <span class="type">class</span> <span class="class">DomainAppFixturesProvider</span> <span class="directive">implements</span> FixtureScriptsSpecificationProvider {
<span class="annotation">@Override</span>
<span class="directive">public</span> FixtureScriptsSpecification getSpecification() {
<span class="keyword">return</span> FixtureScriptsSpecification
.builder(DomainAppFixturesProvider.class)
.with(FixtureScripts.MultipleExecutionStrategy.EXECUTE)
.withRunScriptDefault(RecreateSimpleObjects.class)
.withRunScriptDropDown(FixtureScriptsSpecification.DropDownPolicy.CHOICES)
.withRecreate(RecreateSimpleObjects.class)
.build();
}
}</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_rgsvc_persistence-layer-api">10. Persistence Layer API</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The persistence layer APIs provide domain objects with tools to manage the interactions with the persistence layer, for example adding on-the-fly caching to queries that are called many times within a loop.</p>
</div>
<div class="paragraph">
<p>The table below summarizes the persistence layer APIs defined by Apache Isis. It also lists their corresponding implementation, either a default implementation provided by Apache Isis itself, or provided by one of the in (non-ASF) <a href="http://www.isisaddons.org">Isis Addons</a> modules.</p>
</div>
<table class="tableblock frame-all grid-all spread">
<caption class="title">Table 11. Persistence Layer API</caption>
<colgroup>
<col style="width: 25%;">
<col style="width: 50%;">
<col style="width: 12.5%;">
<col style="width: 12.5%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">API</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Implementation</th>
<th class="tableblock halign-left valign-top">Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_IsisJdoSupport"><code>o.a.i.applib.</code><br>
<code>services.jdosupport</code><br>
<code>IsisJdoSupport</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Lower level access to the JDO Persistence API.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>IsisJdoSupportImpl</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-runtime</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_MetricsService"><code>o.a.i.applib.</code><br>
<code>services.metrics</code><br>
<code>MetricsService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Gathers and provides metrics on the numbers of objects used within a transaction.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>MetricsServiceDefault</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-runtime</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_QueryResultsCache"><code>o.a.i.applib.</code><br>
<code>services.</code><br>
<code>queryresultscache</code><br>
<code>QueryResultsCache</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Request-scoped caching of the results of queries (or any data set generated by a given set of input arguments).</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>QueryResultsCache</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-applib</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">API is also a concrete class</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_api_RepositoryService"><code>o.a.i.applib.</code><br>
<code>services.repository</code><br>
<code>RepositoryService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Methods to help implement repositories: query for existing objects, persist new or delete existing objects</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>RepositoryService-</code><br>
<code>Default</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-metamodel</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Supercedes methods in <a href="#_rgsvc_api_DomainObjectContainer"><code>DomainObjectContainer</code></a>.</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Key:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>o.a.i</code> is an abbreviation for <code>org.apache.isis</code></p>
</li>
<li>
<p><code>o.ia.m</code> is an abbreviation for <code>org.isisaddons.module</code></p>
</li>
<li>
<p><code>o.a.i.c.m.s</code> is an abbreviation for <code>org.apache.isis.core.metamodel.services</code></p>
</li>
<li>
<p><code>o.a.i.c.r.s</code> is an abbreviation for <code>org.apache.isis.core.runtime.services</code></p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_IsisJdoSupport">10.1. <code>IsisJdoSupport</code></h3>
<div class="paragraph">
<p>The <code>IsisJdoSupport</code> service provides a number of general purpose methods for working with the JDO/DataNucleus objectstore. In general these act at a lower-level of abstraction than the APIs normally used (specifically, those of <a href="#_rgsvc_api_DomainObjectContainer"><code>DomainObjectContainer</code></a>), but nevertheless deal with some of the most common use cases. For service also provides access to the underlying JDO <code>PersistenceManager</code> for full control.</p>
</div>
<div class="paragraph">
<p>The following sections discuss the functionality provided by the service, broken out into categories.</p>
</div>
<div class="sect3">
<h4 id="_rgsvc_api_IsisJdoSupport_executing-sql">10.1.1. Executing SQL</h4>
<div class="paragraph">
<p>You can use the <code>IsisJdoSupportService</code> to perform arbitrary SQL SELECTs or UPDATEs:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">IsisJdoSupport</span> {
<span class="annotation">@Programmatic</span>
<span class="predefined-type">List</span><<span class="predefined-type">Map</span><<span class="predefined-type">String</span>, <span class="predefined-type">Object</span>>> executeSql(<span class="predefined-type">String</span> sql);
<span class="annotation">@Programmatic</span>
<span class="predefined-type">Integer</span> executeUpdate(<span class="predefined-type">String</span> sql);
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>executeSql(…​)</code> method allows arbitrary SQL <code>SELECT</code> queries to be submitted:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="predefined-type">List</span><<span class="predefined-type">Map</span><<span class="predefined-type">String</span>, <span class="predefined-type">Object</span>>> results = isisJdoSupport.executeSql(<span class="string"><span class="delimiter">"</span><span class="content">select * from custMgmt.customers</span><span class="delimiter">"</span></span>);</code></pre>
</div>
</div>
<div class="paragraph">
<p>The result set is automatically converted into a list of maps, where the map key is the column name.</p>
</div>
<div class="paragraph">
<p>In a similar manner, the <code>executeUpdate(…​)</code> allows arbitrary SQL <code>UPDATE</code>s to be performed.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="type">int</span> count = isisJdoSupport.executeUpdate(<span class="string"><span class="delimiter">"</span><span class="content">select count(*) from custMgmt.customers);</span></span></code></pre>
</div>
</div>
<div class="paragraph">
<p>The returned value is the number of rows updated.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>As an alternative, consider using DataNucleus' <a href="http://www.datanucleus.org/products/accessplatform_4_0/jdo/jdoql_typesafe.html">type-safe JDO query API</a>, discussed <a href="#_rgsvc_api_IsisJdoSupport_type-safe-query-api">below</a>.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_rgsvc_api_IsisJdoSupport_type-safe-jdoql-queries">10.1.2. Type-safe JDOQL Queries</h4>
<div class="paragraph">
<p>DataNucleus provides an <a href="http://www.datanucleus.org/products/accessplatform_4_0/jdo/jdoql_typesafe.html">extension to JDO</a>, so that JDOQL queries can be built up and executed using a set of type-safe classes.</p>
</div>
<div class="paragraph">
<p>The types in question for type safe queries are not the domain entities, but rather are companion "Q…​" query classes. These classes are generated dynamically by an <a href="https://www.jcp.org/en/jsr/detail?id=269">annotation processor</a> as a side-effect of compilation, one "Q…​" class for each of the <a href="rgant.html#_rgant-PersistenceCapable"><code>@PersistenceCapable</code></a> domain entity in your application. For example, a <code>ToDoItem</code> domain entity will give rise to a <code>QToDoItem</code> query class. These "Q…​" classes mirror the structure of domain entity, but expose properties that allow predicates to be built up for querying instances, as well as other functions in support of order by. group by and other clauses.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Most IDEs (including IntelliJ and Eclipse) enable annotation processing by default, as does Maven. The DataNucleus' <a href="http://www.datanucleus.org/products/accessplatform_4_0/jdo/jdoql_typesafe.html">documentation</a> offers some guidance on confirming that APT is enabled.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The <code>IsisJdoSupport</code> service offers two methods at different levels of abstraction:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">IsisJdoSupport</span> {
<span class="annotation">@Programmatic</span>
<T> <span class="predefined-type">List</span><T> executeQuery(<span class="directive">final</span> <span class="predefined-type">Class</span><T> cls, <span class="directive">final</span> BooleanExpression be);
<span class="annotation">@Programmatic</span>
<T> TypesafeQuery<T> newTypesafeQuery(<span class="predefined-type">Class</span><T> cls);
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>executeQuery(…​)</code> method supports the common case of obtaining a set of objects that meet some criteria, filtered using the provided <code>BooleanExpression</code>. To avoid memory leaks, the returned list is cloned and the underlying query closed.</p>
</div>
<div class="paragraph">
<p>For example, in the (non-ASF) <a href="http://github.com/isisaddons/isis-app-todoapp">Isis addons' todoapp</a> there is an implementation of <code>ToDoItemRepository</code> using type-safe queries. The following JDOQL:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="sql"><span class="class">SELECT</span>
<span class="keyword">FROM</span> todoapp.dom.module.todoitem.ToDoItem
<span class="keyword">WHERE</span> atPath.indexOf(:atPath) == <span class="integer">0</span>
&& complete == :complete<span class="string"><span class="delimiter">"</span></span></code></pre>
</div>
</div>
<div class="paragraph">
<p>can be expressed using type-safe queries as follows:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="predefined-type">List</span><ToDoItem> findByAtPathAndCategory(<span class="directive">final</span> <span class="predefined-type">String</span> atPath, <span class="directive">final</span> Category category) {
<span class="directive">final</span> QToDoItem q = QToDoItem.candidate();
<span class="keyword">return</span> isisJdoSupport.executeQuery(ToDoItem.class,
q.atPath.eq(atPath).and(
q.category.eq(category)));
}</code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>You can find the full example of the JDOQL equivalent in the <a href="#_rgsvc_api_DomainObjectContainer_generic-repository-api"><code>DomainObjectContainer</code></a></p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The <code>newTypesafeQuery(…​)</code> method is a lower-level API that allows a type safe query to be instantiated for most sophisticated querying, eg using group by or order by clauses. See the
DataNucleus <a href="http://www.datanucleus.org/products/accessplatform_4_0/jdo/jdoql_typesafe.html">documentation</a> for full details of using this.</p>
</div>
<div class="paragraph">
<p>One thing to be aware of is that after the query has been executed, it should be closed, using <code>query.closeAll()</code>. If calling <code>query.executeList()</code> we also recommend cloning the resultant list first. The following utility method does both of these tasks:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">private</span> <span class="directive">static</span> <T> <span class="predefined-type">List</span><T> executeListAndClose(<span class="directive">final</span> TypesafeQuery<T> query) {
<span class="directive">final</span> <span class="predefined-type">List</span><T> elements = query.executeList();
<span class="directive">final</span> <span class="predefined-type">List</span><T> list = Lists.newArrayList(elements);
query.closeAll();
<span class="keyword">return</span> list;
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_rgsvc_api_IsisJdoSupport_fixture-support">10.1.3. Fixture support</h4>
<div class="paragraph">
<p>When writing <a href="ugtst.html#_ugtst_integ-test-support">integration tests</a> you’ll usually need to tear down some/all mutable transactional data before each test. One way to do that is to use the <code>executeUpdate(…​)</code> method described <a href="#_rgsvc_api_IsisJdoSupport_executing-sql">above</a>.</p>
</div>
<div class="paragraph">
<p>Alternatively, the <code>deleteAll(…​)</code> method will let your test delete all instances of a class without resorting to SQL:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">IsisJdoSupport</span> {
<span class="annotation">@Programmatic</span>
<span class="type">void</span> deleteAll(<span class="predefined-type">Class</span><?>... pcClasses);
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">TearDownAll</span> <span class="directive">extends</span> FixtureScriptAbstract {
<span class="annotation">@Override</span>
<span class="directive">protected</span> <span class="type">void</span> execute(<span class="directive">final</span> ExecutionContext ec) {
isisJdoSupport.deleteAll(Order.class);
isisJdoSupport.deleteAll(CustomerAddress.class);
isisJdoSupport.deleteAll(Customer.class);
}
<span class="annotation">@Inject</span>
IsisJdoSupport isisJdoSupport;
}</code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>It can occasionally be the case that Apache Isis' internal adapter for the domain object is
still in memory. JDO/DataNucleus seems to bump up the version of the object prior to its deletion,
which under normal circumstances would cause Apache Isis to throw a concurrency exception. Therefore
to prevent this from happening (ie to <em>force</em> the deletion of all instances), concurrency checking
is temporarily disabled while this method is performed.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_rgsvc_api_IsisJdoSupport_reloading-entities">10.1.4. Reloading entities</h4>
<div class="paragraph">
<p>An <a href="http://www.datanucleus.org/products/datanucleus/jdo/orm/relationships.html">(intentional) limitation</a> of JDO/DataNucleus is that persisting a child entity (in a 1:n bidirectional relationship) does not cause the parent’s collection to be updated.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">IsisJdoSupport</span> {
<span class="annotation">@Programmatic</span>
<T> T refresh(T domainObject);
<span class="annotation">@Programmatic</span>
<span class="type">void</span> ensureLoaded(<span class="predefined-type">Collection</span><?> collectionOfDomainObjects);
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>refresh(T domainObject)</code> method can be used to reload the parent object (or indeed any object). Under the covers it uses the JDO <code>PersistenceManager#refresh(…​)</code> API.</p>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>(nature=NatureOfService.VIEW_CONTRIBUTIONS_ONLY)
<span class="directive">public</span> <span class="type">class</span> <span class="class">OrderContributions</span> {
<span class="directive">public</span> Order newOrder(<span class="directive">final</span> Customer customer) {
Order order = newTransientInstance(Order.class);
order.setCustomer(customer);
container.persist(customer);
container.flush(); <i class="conum" data-value="1"></i><b>(1)</b>
isisJdoSupport.refresh(customer); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="keyword">return</span> order;
}
<span class="annotation">@Inject</span>
DomainObjectContainer container;
<span class="annotation">@Inject</span>
IsisJdoSupport isisJdoSupport;
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>flush to database, ensuring that the database row corresponding to the <code>Order</code> exists in its <code>order</code> table.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>reload the parent (customer) from the database, so that its collection of <code>Order</code>s is accurate.</td>
</tr>
</table>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The particular example that led to this method being added was a 1:m bidirectional relationship,
analogous to <code>Customer 1←→* Order</code>. Persisting the child <code>Order</code> object did not cause
the parent <code>Customer</code>'s collection of orders to be updated. In fact, JDO does not make any
such guarantee to do so. Options are therefore either to maintain the collection in code, or to
refresh the parent.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The <code>ensureLoaded(…​)</code> method allows a collection of domain objects to be loaded from the database in a single hit. This can be valuable as a performance optimization to avoid multiple roundtrips to the database. Under the covers it uses the <code>PersistenceManager#retrieveAll(…​)</code> API.</p>
</div>
</div>
<div class="sect3">
<h4 id="_rgsvc_api_IsisJdoSupport_jdo-persistencemanager">10.1.5. JDO <code>PersistenceManager</code></h4>
<div class="paragraph">
<p>The functionality provided by <code>IsisJdoSupport</code> focus only on the most common use cases. If you require more flexibility than this, eg for dynamically constructed queries, then you can use the service to access the underlying JDO <code>PersistenceManager</code> API:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">IsisJdoSupport</span> {
<span class="annotation">@Programmatic</span>
PersistenceManager getJdoPersistenceManager();
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="predefined-type">List</span><Order> findOrders(...) {
javax.jdo.PersistenceManager pm = isisJdoSupport.getPersistenceManager();
<span class="comment">// knock yourself out...</span>
<span class="keyword">return</span> someListOfOrders;
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_17">10.1.6. Registering the Services</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>IsisJdoSupport</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_MetricsService">10.2. <code>MetricsService</code> (<code>1.13.0-SNAPSHOT</code>)</h3>
<div class="paragraph">
<p>The <code>MetricsService</code> (<code>1.13.0-SNAPSHOT</code>) is a request-scoped domain service that hooks into the JDO/DataNucleus
ObjectStore to provide a number of counters relating to numbers of object loaded, dirtied etc.</p>
</div>
<div class="paragraph">
<p>The service is used by the <a href="#_rgsvc_api_InteractionContext"><code>InteractionContext</code></a> domain service (to populate the DTO held by the <code>Interaction.Execution</code>) and also by the (internal) <a href="rgfis.html#_rgfis_spi_PublishingServiceInternal"><code>PublishingServiceInternal</code></a> domain service (to populate
the <code>PublishedObjects</code> class.</p>
</div>
<div class="sect3">
<h4 id="_api_implementation_17">10.2.1. API & Implementation</h4>
<div class="paragraph">
<p>The API of the service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@RequestScoped</span>
<span class="directive">public</span> <span class="type">interface</span> <span class="class">MetricsService</span> {
<span class="type">int</span> numberObjectsLoaded(); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="type">int</span> numberObjectsDirtied(); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="type">int</span> numberObjectPropertiesModified(); <i class="conum" data-value="3"></i><b>(3)</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 number of objects that have, so far in this request, been loaded from the database. Corresponds to the number of times that <code>javax.jdo.listener.LoadLifecycleListener#postLoad(InstanceLifecycleEvent)</code> is fired.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>The number of objects that have, so far in this request, been dirtied/will need updating in the database); a good measure of the footprint of the interaction. Corresponds to the number of times that <code>javax.jdo.listener.DirtyLifecycleListener#preDirty(InstanceLifecycleEvent)</code> callback is fired.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>The number of individual properties of objects that were modified; a good measure of the amount of work being done in the interaction. Corresponds to the number of times that the <a href="#_rgsvc_spi_AuditingService"><code>AuditingService</code></a>'s (or
<a href="#_rgsvc_spi_AuditerService"><code>AuditerService</code></a>'s) <code>audit(…​)</code> method will be called as the transaction
completes.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The framework provides a default implementation of this API, namely <code>o.a.i.c.r.s.metrics.MetricsServiceDefault</code>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_28">10.2.2. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' default
implementation of <code>MetricsService</code> class is automatically registered (it is annotated with <code>@DomainService</code>)
so no further configuration is required.</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_25">10.2.3. Related Services</h4>
<div class="paragraph">
<p>The <a href="#_rgsvc_spi_PublisherService"><code>PublisherService</code></a> also captures the metrics gathered by the
<code>MetricsService</code> and publishes them as part of the <code>PublishedObjects</code> class (part of its SPI).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_QueryResultsCache">10.3. <code>QueryResultsCache</code></h3>
<div class="paragraph">
<p>The purpose of the <code>QueryResultsCache</code> is to improve response times to the user, by providing a short-term (<a href="../../more-advanced-topics/how-to-09-020-How-to-write-a-typical-domain-service.html">request-scoped</a>) cache of the value of some (safe or idempotent) method call. This will typically be as the result of running a query, but could be any expensive operation.</p>
</div>
<div class="paragraph">
<p>Caching such values is useful for code that loops "naively" through a bunch of stuff, performing an expensive operation each time. If the data is such that the same expensive operation is made many times, then the query cache is a perfect fit.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>This service was inspired by similar functionality that exists in relational databases, for example Sybase’s <a href="http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.dc20023_1251/html/optimizer/X43480.htm">subquery results cache</a> and Oracle’s <a href="http://www.dba-oracle.com/oracle11g/oracle_11g_result_cache_sql_hint.htm">result_cache</a> hint.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_api_implementation_18">10.3.1. API & Implementation</h4>
<div class="paragraph">
<p>The API defined by <code>QueryResultsCache</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@RequestScoped</span>
<span class="directive">public</span> <span class="type">class</span> <span class="class">QueryResultsCache</span> {
<span class="directive">public</span> <span class="directive">static</span> <span class="type">class</span> <span class="class">Key</span> {
<span class="directive">public</span> <span class="predefined-type">Key</span>(<span class="predefined-type">Class</span><?> callingClass, <span class="predefined-type">String</span> methodName, <span class="predefined-type">Object</span>... keys) {...}
<span class="directive">public</span> <span class="predefined-type">Class</span><?> getCallingClass() { ... }
<span class="directive">public</span> <span class="predefined-type">String</span> getMethodName() { ... }
<span class="directive">public</span> <span class="predefined-type">Object</span><span class="type">[]</span> getKeys() { ... }
}
<span class="directive">public</span> <span class="directive">static</span> <span class="type">class</span> <span class="class">Value</span><T> {
<span class="directive">public</span> Value(T result) { ... }
<span class="directive">private</span> T result;
<span class="directive">public</span> T getResult() {
<span class="keyword">return</span> result;
}
}
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <T> T execute(
<span class="directive">final</span> <span class="predefined-type">Callable</span><T> callable,
<span class="directive">final</span> <span class="predefined-type">Class</span><?> callingClass, <span class="directive">final</span> <span class="predefined-type">String</span> methodName, <span class="directive">final</span> <span class="predefined-type">Object</span>... keys) { ... }
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <T> T execute(<span class="directive">final</span> <span class="predefined-type">Callable</span><T> callable, <span class="directive">final</span> <span class="predefined-type">Key</span> cacheKey) { ... }
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <T> Value<T> get(
<span class="directive">final</span> <span class="predefined-type">Class</span><?> callingClass, <span class="directive">final</span> <span class="predefined-type">String</span> methodName, <span class="directive">final</span> <span class="predefined-type">Object</span>... keys) { ... }
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <T> Value<T> get(<span class="directive">final</span> <span class="predefined-type">Key</span> cacheKey) { ... }
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <T> <span class="type">void</span> put(<span class="directive">final</span> <span class="predefined-type">Key</span> cacheKey, <span class="directive">final</span> T result) { ... }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This class (<code>o.a.i.applib.services.queryresultscache.QueryResultsCache</code>) is also the implementation.</p>
</div>
</div>
<div class="sect3">
<h4 id="_usage_15">10.3.2. Usage</h4>
<div class="paragraph">
<p>Suppose that there’s a <code>TaxService</code> that calculates tax on <code>Taxable</code> items, with respect to some <code>TaxType</code>, and for a given <code>LocalDate</code>. To calculate tax it must run a database query and then perform some additional calculations.</p>
</div>
<div class="paragraph">
<p>Our original implementation is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>
<span class="directive">public</span> <span class="type">class</span> <span class="class">TaxService</span> {
<span class="directive">public</span> <span class="predefined-type">BigDecimal</span> calculateTax(
<span class="directive">final</span> Taxable t, <span class="directive">final</span> TaxType tt, <span class="directive">final</span> LocalDate d) {
<span class="comment">// query against DB using t, tt, d</span>
<span class="comment">// further expensive calculations</span>
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Suppose now that this service is called in a loop, for example iterating over a bunch of orders, where several of those orders are for the same taxable products, say. In this case the result of the calculation would always be the same for any given product.</p>
</div>
<div class="paragraph">
<p>We can therefore refactor the method to use the query cache as follows:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">TaxService</span> {
<span class="directive">public</span> <span class="predefined-type">BigDecimal</span> calculateTax(
<span class="directive">final</span> Taxable t, <span class="directive">final</span> TaxType tt, <span class="directive">final</span> LocalDate d) {
<span class="keyword">return</span> queryResultsCache.execute(
<span class="keyword">new</span> <span class="predefined-type">Callable</span><<span class="predefined-type">BigDecimal</span>>(){ <i class="conum" data-value="1"></i><b>(1)</b>
<span class="directive">public</span> <span class="predefined-type">BigDecimal</span> call() <span class="directive">throws</span> <span class="exception">Exception</span> {
<span class="comment">// query against DB using t, tt, d</span>
<span class="comment">// further expensive calculations</span>
}
},
TaxService.class, <i class="conum" data-value="2"></i><b>(2)</b>
<span class="string"><span class="delimiter">"</span><span class="content">calculateTax</span><span class="delimiter">"</span></span>,
t, tt, d);
}
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>the <code>Callable</code> is the original code</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>the remaining parameters in essence uniquely identify the method call.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>This refactoring will be worthwhile provided that enough of the orders being processed reference the same taxable products. If however every order is for a different product, then no benefit will be gained from the refactoring.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_29">10.3.3. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>QueryResultsCache</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_26">10.3.4. Related Services</h4>
<div class="paragraph">
<p>The <a href="#_rgsvc_api_Scratchpad"><code>Scratchpad</code></a> service is also intended for actions that are called many times, allowing arbitrary information to be shared between them. Those methods could be called from some outer loop in domain code, or by the framework itself if the action invoked has the <a href="rgant.html#_rgant-Action_invokeOn"><code>@Action#invokeOn()</code></a> annotation attribute set to <code>OBJECT_AND_COLLECTION</code> or <code>COLLECTION_ONLY</code>.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_api_RepositoryService">10.4. <code>RepositoryService</code></h3>
<div class="paragraph">
<p>The <code>RepositoryService</code> collects together methods for creating, persisting and searching for entities from the underlying persistence store. It acts as an abstraction over the JDO/DataNucleus objectstore.</p>
</div>
<div class="paragraph">
<p>You can use it during prototyping to write naive queries (find all rows, then filter using the Guava <code>Predicate</code> API, or you can use it to call JDO <a href="http://www.datanucleus.org/products/accessplatform_4_0/jdo/query.html#named">named queries</a> using JDOQL.</p>
</div>
<div class="paragraph">
<p>As an alternative, you could also use <a href="http://www.datanucleus.org/products/accessplatform_4_0/jdo/jdoql_typesafe.html">JDO typesafe queries</a> through the <a href="#_rgsvc_api_IsisJdoSupport"><code>IsisJdoSupport</code></a> service.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The methods in this service replace similar methods (now deprecated) in <a href="#_rgsvc_api_DomainObjectContainer"><code>DomainObjectContainer</code></a>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_api_8">10.4.1. API</h4>
<div class="paragraph">
<p>The API of <code>RepositoryService</code> is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">RepositoryService</span> {
<T> T instantiate(<span class="directive">final</span> <span class="predefined-type">Class</span><T> ofType); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="type">boolean</span> isPersistent(<span class="predefined-type">Object</span> domainObject); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="type">void</span> persist(<span class="predefined-type">Object</span> domainObject); <i class="conum" data-value="3"></i><b>(3)</b>
<span class="type">void</span> persistAndFlush(<span class="predefined-type">Object</span> domainObject); <i class="conum" data-value="4"></i><b>(4)</b>
<span class="type">void</span> remove(<span class="predefined-type">Object</span> persistentDomainObject); <i class="conum" data-value="5"></i><b>(5)</b>
<span class="type">void</span> removeAndFlush(<span class="predefined-type">Object</span> persistentDomainObject); <i class="conum" data-value="6"></i><b>(6)</b>
<T> <span class="predefined-type">List</span><T> allInstances(<span class="predefined-type">Class</span><T> ofType, <span class="type">long</span>... range); <i class="conum" data-value="7"></i><b>(7)</b>
<T> <span class="predefined-type">List</span><T> allMatches(<span class="predefined-type">Query</span><T> query); <i class="conum" data-value="8"></i><b>(8)</b>
<T> <span class="predefined-type">List</span><T> allMatches(<span class="predefined-type">Class</span><T> ofType, <span class="predefined-type">Predicate</span><? <span class="local-variable">super</span> T> predicate, <span class="type">long</span>... range); <i class="conum" data-value="9"></i><b>(9)</b>
<T> T uniqueMatch(<span class="predefined-type">Query</span><T> query); <i class="conum" data-value="10"></i><b>(10)</b>
<T> T uniqueMatch(<span class="directive">final</span> <span class="predefined-type">Class</span><T> ofType, <span class="directive">final</span> <span class="predefined-type">Predicate</span><T> predicate); <i class="conum" data-value="11"></i><b>(11)</b>
<T> T firstMatch(<span class="predefined-type">Query</span><T> query); <i class="conum" data-value="12"></i><b>(12)</b>
<T> T firstMatch(<span class="directive">final</span> <span class="predefined-type">Class</span><T> ofType, <span class="directive">final</span> <span class="predefined-type">Predicate</span><T> predicate); <i class="conum" data-value="13"></i><b>(13)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>create a new non-persisted domain entity. This is identical to
<a href="#_rgsvc_api_FactoryService"><code>FactoryService</code></a>'s <code>instantiate(…​)</code> method, but is provided in the
<code>RepositoryService</code>'s API too because instantiating and persisting objects are often done together.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>test whether a particular domain object is persistent or not</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>persist (ie save) an object to the persistent object store (or do nothing if it is already persistent).</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>(<code>1.13.0-SNAPSHOT</code>) persist (ie save) and flush; same as <code>persist()</code>, but also flushes changes to database and updates managed properties and collections (i.e., 1-1, 1-n, m-n relationships automatically maintained by the DataNucleus persistence mechanism).</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>remove (ie delete) an object from the persistent object store (or do nothing if it has already been deleted).</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>(<code>1.13.0-SNAPSHOT</code>) remove (delete) and flush; same as <code>remove()</code>, but also flushes changes to database and updates managed properties and collections (i.e., 1-1, 1-n, m-n relationships automatically maintained by the DataNucleus persistence mechanism).</td>
</tr>
<tr>
<td><i class="conum" data-value="7"></i><b>7</b></td>
<td>return all persisted instances of specified type. Mostly for prototyping, though can be useful to obtain all instances of domain entities if the number is known to be small. The optional varargs parameters are for paging control; more on this below.</td>
</tr>
<tr>
<td><i class="conum" data-value="8"></i><b>8</b></td>
<td>all persistence instances matching the specified <code>Query</code>. Query itself is an Isis abstraction on top of JDO/DataNucleus' Query API. <strong>This is the primary API used for querying</strong></td>
</tr>
<tr>
<td><i class="conum" data-value="9"></i><b>9</b></td>
<td>As the previous, but with client-side filtering using a <code>Predicate</code>. Only really intended for prototyping.</td>
</tr>
<tr>
<td><i class="conum" data-value="10"></i><b>10</b></td>
<td>Returns the first instance that matches the supplied query. If no instance is found then `null `will be returned, while if there is more that one instances a run-time exception will be thrown. Generally this method is preferred for looking up an object by its (primary or alternate) key.</td>
</tr>
<tr>
<td><i class="conum" data-value="11"></i><b>11</b></td>
<td>As the previous, but with client-side filtering using a <code>Predicate</code>. Only really intended for prototyping.</td>
</tr>
<tr>
<td><i class="conum" data-value="12"></i><b>12</b></td>
<td>Returns the first instance that matches the supplied query. If no instance is found then <code>null `will be returned. No exception is thrown if more than one matches, so this is less strict that `uniqueMatch(…​)</code>.</td>
</tr>
<tr>
<td><i class="conum" data-value="13"></i><b>13</b></td>
<td>As the previous, but with client-side filtering using a <code>Predicate</code>. Only really intended for prototyping.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The <code>uniqueMatch(…​)</code> methods are the recommended way of querying for (precisely) one instance. The <code>firstMatch(…​)</code> methods are for less strict querying.</p>
</div>
</div>
<div class="sect3">
<h4 id="_usage_16">10.4.2. Usage</h4>
<div class="paragraph">
<p>This section briefly discusses how application code can use (some of) these APIs.</p>
</div>
<div class="sect4">
<h5 id="_persist">Persist</h5>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java">Customer cust = repositoryService.instantiate(Customer.class);
cust.setFirstName(<span class="string"><span class="delimiter">"</span><span class="content">Freddie</span><span class="delimiter">"</span></span>);
cust.setLastName(<span class="string"><span class="delimiter">"</span><span class="content">Mercury</span><span class="delimiter">"</span></span>);
repositoryService.persist(cust);</code></pre>
</div>
</div>
<div class="paragraph">
<p>You should be aware that by default Apache Isis queues up calls to <code>#persist()</code> and <code>#remove()</code>. These are then executed either when the request completes (and the transaction commits), or if the queue is flushed. This can be done either implicitly by the framework, or as the result of a direct call to <code>#flush()</code>.</p>
</div>
<div class="paragraph">
<p>By default the framework itself will cause <code>#flush()</code> to be called whenever a query is executed by way of <code>#allMatches(Query)</code>, as documented <a href="#_rgsvc_api_DomainObjectContainer_generic-repository-api">above</a>. However, this behaviour can be disabled using the <a href="rgcfg.html#_rgcfg_configuring-core">configuration property</a> <code>isis.services.container.disableAutoFlush</code>.</p>
</div>
</div>
<div class="sect4">
<h5 id="__code_persistandflush_code_code_removeandflush_code"><code>persistAndFlush(…​)</code>, <code>removeAndFlush(…​)</code></h5>
<div class="paragraph">
<p>In some cases, such as when using managed properties and collections for implementing 1-1, 1-n, or m-n relationships,
the developer needs to invoke <code>flush()</code> to send the changes to the DataNucleus persistence mechanism. These
managed properties and collections and then updated.</p>
</div>
<div class="paragraph">
<p>The <code>persistAndFlush(…​)</code> and <code>removeAndFlush(…​)</code> methods (introduced in <code>1.13.0-SNAPSHOT</code>) save the developer from
having to call the <code>flush(…​)</code> method.</p>
</div>
<div class="paragraph">
<p>For example, the following code requires a flush to occur, so uses these methods:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="directive">abstract</span> <span class="type">class</span> <span class="class">Warehouse</span> <span class="directive">extends</span> SalesVIPEntity<Marketplace> {
<span class="annotation">@Persistent</span>(mappedBy = <span class="string"><span class="delimiter">"</span><span class="content">marketplace</span><span class="delimiter">"</span></span>, dependentElement = <span class="string"><span class="delimiter">"</span><span class="content">true</span><span class="delimiter">"</span></span>)
<span class="annotation">@Getter</span> <span class="annotation">@Setter</span> <i class="conum" data-value="1"></i><b>(1)</b>
<span class="directive">private</span> <span class="predefined-type">SortedSet</span><MarketplaceExcludedProduct> excludedProducts =
<span class="keyword">new</span> <span class="predefined-type">TreeSet</span><MarketplaceExcludedProduct>();
<span class="annotation">@Action</span>(semantics = SemanticsOf.IDEMPOTENT)
<span class="directive">public</span> MarketplaceExcludedProduct addExcludedProduct(<span class="directive">final</span> Product product) {
MarketplaceExcludedProduct marketplaceExcludedProduct = <span class="local-variable">this</span>.findExcludedProduct(product);
<span class="keyword">if</span> (marketplaceExcludedProduct == <span class="predefined-constant">null</span>) {
marketplaceExcludedProduct =
<span class="local-variable">this</span>.factoryService.instantiate(MarketplaceExcludedProduct.class);
}
<span class="local-variable">this</span>.wrap(marketplaceExcludedProduct).setMarketplace(<span class="local-variable">this</span>);
<span class="local-variable">this</span>.wrap(marketplaceExcludedProduct).setProduct(product);
<span class="local-variable">this</span>.repositoryService.persistAndFlush(marketplaceExcludedProduct); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="keyword">return</span> marketplaceExcludedProduct;
}
<span class="annotation">@Action</span>(semantics = SemanticsOf.IDEMPOTENT)
<span class="directive">public</span> <span class="type">void</span> deleteFromExcludedProducts(<span class="directive">final</span> Product product) {
<span class="directive">final</span> MarketplaceExcludedProduct marketplaceExcludedProduct = findExcludedProduct(product);
<span class="keyword">if</span> (marketplaceExcludedProduct != <span class="predefined-constant">null</span>) {
<span class="local-variable">this</span>.repositoryService.removeAndFlush(marketplaceExcludedProduct);
}
}
... <i class="conum" data-value="3"></i><b>(3)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>using lombok for brevity</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Needed for updating the managed properties and collections.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>injected services and other methods ommited</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>On the “addExcludedProduct()�? action, if the user didn’t flush, the following test would fail because the managed
collection would not containing the given product:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Test</span>
<span class="directive">public</span> <span class="type">void</span> addExcludedProduct() {
<span class="comment">// given</span>
<span class="directive">final</span> AmazonMarketplace amazonMarketplace = <span class="local-variable">this</span>.wrapSkipRules(
<span class="local-variable">this</span>.marketplaceRepository).findOrCreateAmazonMarketplace(
AmazonMarketplaceLocation.FRANCE);
<span class="directive">final</span> Product product = <span class="local-variable">this</span>.wrap(<span class="local-variable">this</span>.productRepository)
.createProduct(<span class="predefined-type">UUID</span>.randomUUID().toString(), <span class="predefined-type">UUID</span>.randomUUID().toString());
<span class="comment">// when</span>
<span class="local-variable">this</span>.wrap(amazonMarketplace).addExcludedProduct(product);
<span class="comment">// then</span>
Assertions.assertThat(
<span class="local-variable">this</span>.wrapSkipRules(amazonMarketplace).findAllProductsExcluded()
).contains(product); <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>this would fail.</td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="_query_and_code_xxxmatches_code">Query and <code>xxxMatches(…​)</code></h5>
<div class="paragraph">
<p>There are various implementations of the <code>Query</code> API, but these either duplicate functionality of the other overloads of <code>allMatches(…​)</code> or they are not supported by the JDO/DataNucleus object store. The only significant implementation of <code>Query</code> to be aware of is <code>QueryDefault</code>, which identifies a named query and a set of parameter/argument tuples.</p>
</div>
<div class="paragraph">
<p>For example, in the (non-ASF) <a href="http://github.com/isisaddons/isis-app-todoapp">Isis addons' todoapp</a> the <code>ToDoItem</code> is annotated:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@javax</span>.jdo.annotations.Queries( {
<span class="annotation">@javax</span>.jdo.annotations.Query(
name = <span class="string"><span class="delimiter">"</span><span class="content">findByAtPathAndComplete</span><span class="delimiter">"</span></span>, language = <span class="string"><span class="delimiter">"</span><span class="content">JDOQL</span><span class="delimiter">"</span></span>, <i class="conum" data-value="1"></i><b>(1)</b>
value = <span class="string"><span class="delimiter">"</span><span class="content">SELECT </span><span class="delimiter">"</span></span>
+ <span class="string"><span class="delimiter">"</span><span class="content">FROM todoapp.dom.module.todoitem.ToDoItem </span><span class="delimiter">"</span></span>
+ <span class="string"><span class="delimiter">"</span><span class="content">WHERE atPath.indexOf(:atPath) == 0 </span><span class="delimiter">"</span></span> <i class="conum" data-value="2"></i><b>(2)</b>
+ <span class="string"><span class="delimiter">"</span><span class="content"> && complete == :complete</span><span class="delimiter">"</span></span>), <i class="conum" data-value="3"></i><b>(3)</b>
...
})
<span class="directive">public</span> <span class="type">class</span> <span class="class">ToDoItem</span> ... {
...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>name of the query</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>defines the <code>atPath</code> parameter</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>defines the <code>complete</code> parameter</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>This JDO query definitions are used in the <code>ToDoItemRepositoryImplUsingJdoql</code> service:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>(nature = NatureOfService.DOMAIN)
<span class="directive">public</span> <span class="type">class</span> <span class="class">ToDoItemRepositoryImplUsingJdoql</span> <span class="directive">implements</span> ToDoItemRepositoryImpl {
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <span class="predefined-type">List</span><ToDoItem> findByAtPathAndCategory(<span class="directive">final</span> <span class="predefined-type">String</span> atPath, <span class="directive">final</span> Category category) {
<span class="keyword">return</span> container.allMatches(
<span class="keyword">new</span> QueryDefault<>(ToDoItem.class,
<span class="string"><span class="delimiter">"</span><span class="content">findByAtPathAndCategory</span><span class="delimiter">"</span></span>, <i class="conum" data-value="1"></i><b>(1)</b>
<span class="string"><span class="delimiter">"</span><span class="content">atPath</span><span class="delimiter">"</span></span>, atPath, <i class="conum" data-value="2"></i><b>(2)</b>
<span class="string"><span class="delimiter">"</span><span class="content">category</span><span class="delimiter">"</span></span>, category)); <i class="conum" data-value="3"></i><b>(3)</b>
}
...
<span class="annotation">@javax</span>.inject.Inject
DomainObjectContainer container;
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>corresponds to the "findByAtPathAndCategory" JDO named query</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>provide argument for the <code>atPath</code> parameter. The pattern is parameter, argument, parameter, argument, …​ and so on.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>provide argument for the <code>category</code> parameter. The pattern is parameter, argument, parameter, argument, …​ and so on.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Other JDOQL named queries (not shown) follow the exact same pattern.</p>
</div>
<div class="paragraph">
<p>With respect to the other query APIs, the varargs parameters are optional, but allow for (client-side and managed) paging. The first parameter is the <code>start</code> (0-based, the second is the <code>count</code>.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>It is also possible to query using DataNucleus' type-safe query API. For more details, see <a href="#_rgsvc_api_IsisJdoSupport"><code>IsisJdoSupport</code></a>.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_27">10.4.3. Implementation</h4>
<div class="paragraph">
<p>The core framework provides a default implementation of this service (<code>o.a.i.core.metamodel.services.repository.RepositoryServiceDefault</code>).</p>
</div>
<div class="sect4">
<h5 id="__disabling_auto_flush">(Disabling) Auto-flush</h5>
<div class="paragraph">
<p>Normally any queries are automatically preceded by flushing pending commands to persist or remove objects.</p>
</div>
<div class="paragraph">
<p>This key allows this behaviour to be disabled.</p>
</div>
<div class="literalblock">
<div class="content">
<pre> *
* <p>
* Originally introduced as part of ISIS-1134 (fixing memory leaks in the objectstore)
* where it was found that the autoflush behaviour was causing a (now unrepeatable)
* data integrity error (see <a href="https://issues.apache.org/jira/browse/ISIS-1134?focusedCommentId=14500638&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-14500638">ISIS-1134 comment</a>, in the isis-module-security.
* However, that this could be circumvented by removing the call to flush().
* We don't want to break existing apps that might rely on this behaviour, on the
* other hand we want to fix the memory leak. Adding this configuration property
* seems the most prudent way forward.
* </p>
*/
public static final String KEY_DISABLE_AUTOFLUSH = "isis.services.container.disableAutoFlush";</pre>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_service_30">10.4.4. Registering the Service</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>RepositoryService</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_27">10.4.5. Related Services</h4>
<div class="paragraph">
<p>the <a href="#_rgsvc_api_FactoryService"><code>FactoryService</code></a> is often used in conjunction with the <code>RepositoryService</code>, to instantiate domain objects before persisting.</p>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_rgsvc_persistence-layer-spi">11. Persistence Layer SPI</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The persistence layer SPIs influence how the framework persists domain objects, for example controlling how to create an audit log of changes to domain objects.</p>
</div>
<div class="paragraph">
<p>The table below summarizes the persistence layer SPIs defined by Apache Isis. It also lists their corresponding implementation, either a default implementation provided by Apache Isis itself, or provided by one of the in (non-ASF) <a href="http://www.isisaddons.org">Isis Addons</a> modules.</p>
</div>
<table class="tableblock frame-all grid-all spread">
<caption class="title">Table 12. Persistence Layer SPI</caption>
<colgroup>
<col style="width: 25%;">
<col style="width: 50%;">
<col style="width: 12.5%;">
<col style="width: 12.5%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">SPI</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Implementation</th>
<th class="tableblock halign-left valign-top">Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_AuditingService"><code>o.a.i.applib.</code><br>
<code>services.audit</code><br>
<code>AuditerService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>(<code>1.13.0-SNAPSHOT</code>) Create an audit record for every changed property of every changed object within a transaction.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>AuditerServiceLogging</code><br>
also<br>
<code>AuditerServiceUsingJdo</code><br>
<code>o.ia.m.audit</code><br>
<code>isis-module-audit</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_AuditingService"><code>o.a.i.applib.</code><br>
<code>services.audit</code><br>
<code>AuditingService3</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>(deprecated in <code>1.13.0-SNAPSHOT</code>, replaced by <a href="#_rgsvc_spi_AuditerService"><code>AuditerService</code></a>); creates
an audit record for every changed property of every changed object within a transaction.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_EventSerializer"><code>o.a.i.applib.</code><br>
<code>services.publish</code><br>
<code>EventSerializer</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>(deprecated in <code>1.13.0-SNAPSHOT</code>) Creates a representation of either an action invocation or a changed object being published through the <a href="#_rgsvc_spi_PublishingService"><code>PublishingService</code></a>.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>RestfulObjects-</code><br>
<code>SpecEventSerializer</code><br>
<code>o.ia.m.publishing</code><br>
<code>isis-module-publishing</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_PublisherService"><code>o.a.i.applib.</code><br>
<code>services.publish</code><br>
<code>PublisherService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>(<code>1.13.0-SNAPSHOT</code>) Publish any action invocations/property edits and changed objects, typically for interchange with an external system in a different bounded context.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>PublisherServiceLogging</code><br>
also<br>
<code>PublisherService-</code><br>
<code>UsingActiveMq</code><br>
<code>o.ia.m.publishmq</code><br>
<code>isis-module-publishmq</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_PublishingService"><code>o.a.i.applib.</code><br>
<code>services.publish</code><br>
<code>PublishingService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>(deprecated in <code>1.13.0-SNAPSHOT</code>) Publish any action invocations and changed objects, typically for interchange with an external system in a different bounded context.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>PublishingService</code><br>
<code>o.ia.m.publishing</code><br>
<code>isis-module-publishing</code></p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_UserRegistrationService"><code>o.a.i.applib.</code><br>
<code>services.userreg</code><br>
<code>UserRegistrationService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Create a new user account with the configured security mechanism.</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>SecurityModule-</code><br>
<code>AppUserRegistrationService</code><br>
<code>o.ia.m.security</code><br>
<code>isis-module-security</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">depends (implicitly) on:<br>
a configured <code>EmailService</code></p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Key:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>o.a.i</code> is an abbreviation for <code>org.apache.isis</code></p>
</li>
<li>
<p><code>o.ia.m</code> is an abbreviation for <code>org.isisaddons.module</code></p>
</li>
<li>
<p><code>o.a.i.c.m.s</code> is an abbreviation for <code>org.apache.isis.core.metamodel.services</code></p>
</li>
<li>
<p><code>o.a.i.c.r.s</code> is an abbreviation for <code>org.apache.isis.core.runtime.services</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Where an implementation is available (on the classpath) then it is always registered automatically (that is, they are all (with one exception) annotated with <a href="rgant.html#_rgant-DomainService"><code>@DomainService</code></a>.</p>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_AuditerService">11.1. <code>AuditerService</code> (<code>1.13.0-SNAPSHOT</code>)</h3>
<div class="paragraph">
<p>The <code>AuditerService</code> auditing service provides a simple mechanism to capture changes to data. It is called for each property that has changed on any domain object, as a set of pre- and post-values.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>This service is intended to replace the now-deprecated <a href="#_rgsvc_spi_AuditingService"><code>AuditingService3</code></a>.
The difference between the two is that this service recognises that the <code>transactionId</code> is now (in <code>1.13.0-SNAPSHOT</code>)
actually a request/interaction Id, and that an additional `sequence</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_spi_18">11.1.1. SPI</h4>
<div class="paragraph">
<p>The SPI for the service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">AuditerService</span> {
<span class="type">boolean</span> isEnabled(); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="directive">public</span> <span class="type">void</span> audit(
<span class="predefined-type">UUID</span> transactionId, <span class="type">int</span> sequence, <i class="conum" data-value="2"></i><b>(2)</b>
<span class="predefined-type">String</span> targetClassName,
Bookmark target, <i class="conum" data-value="3"></i><b>(3)</b>
<span class="predefined-type">String</span> memberIdentifier,
<span class="predefined-type">String</span> propertyName, <i class="conum" data-value="4"></i><b>(4)</b>
<span class="predefined-type">String</span> preValue, <span class="predefined-type">String</span> postValue, <i class="conum" data-value="5"></i><b>(5)</b>
<span class="predefined-type">String</span> user, java.sql.Timestamp timestamp); <i class="conum" data-value="6"></i><b>(6)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>whether this implementation is enabled. If all configured implementations are disabled, then auditing is
suppressed (a minor performance optimization).</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>together the <code>transactionId</code> (misnamed; really is the request/interaction Id) and the <code>sequence</code> uniquely identify
the transaction in which the object was changed.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>identifies the object that has changed</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>the property of the object that has changed. The combination of the <code>transactionId</code>, <code>sequence</code>, <code>target</code> and
<code>propertyName</code> is unique.</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>the before and after values of the property (in string format). If the object was created then "[NEW]" is used
as the pre-value; if the object was deleted then "[DELETED]" is used as the post-value.</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>the user that changed the object, and the date/time that this occurred.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The framework will call this for each and every domain object property that is modified within a transaction.</p>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_28">11.1.2. Implementation</h4>
<div class="paragraph">
<p>The framework allows multiple implementations of this service to be registered; all will be called. The framework
provides one implementation of its own, <code>AuditerServiceLogging</code> (in <code>o.a.i.applib.services.audit</code> package); this
logs simple messages to an SLF4J logger.</p>
</div>
<div class="paragraph">
<p>The (non-ASF) <a href="http://github.com/isisaddons/isis-module-audit">Isis addons' Audit module</a> also provides an
implementation, <code>org.isisaddons.module.audit.dom.AuditerServiceUsingJdo</code>. This creates an audit record for each
changed property (ie every time that <code>AuditerService#audit(…​)</code> is called.</p>
</div>
<div class="paragraph">
<p>The module also provides:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>AuditingServiceMenu</code> service which provides actions to search for <code>AuditEntry</code>s, underneath an 'Activity' menu on
the secondary menu bar.</p>
</li>
<li>
<p><code>AuditingServiceRepository</code> service to to search for persisted <code>AuditEntry``s. None of its actions are visible in
the user interface (they are all `@Programmatic</code>).</p>
</li>
<li>
<p><code>AuditingServiceContributions</code> which contrbutes collections to the
<a href="rgcms.html#_rgcms_classes_mixins_HasTransactionId"> <code>HasTransactionId</code></a> interface. This will therefore display all
audit entries that occurred in a given request/transaction, in other words whenever a command, a published event or
another audit entry is displayed.</p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="_usage_17">11.1.3. Usage</h4>
<div class="paragraph">
<p>The typical way to indicate that an object should be audited is to annotate it with the <a href="rgant.html#_rgant-DomainObject_auditing"><code>@DomainObject#auditing()</code></a> annotation.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_18">11.1.4. Registering the Services</h4>
<div class="paragraph">
<p>The (non-ASF) <a href="http://github.com/isisaddons/isis-module-audit">Isis addons' audit</a> module provides an implementation of
this service (<code>AuditerService</code>), and also provides a number of related domain services (<code>AuditingServiceMenu</code>,
<code>AuditingServiceRepository</code> and <code>AuditingServiceContributions</code>).</p>
</div>
<div class="paragraph">
<p>Assuming that an <code>AppManifest</code> is being used to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>)
then this can be activated by updating the <code>pom.xml</code> and updating the <code>AppManifest#getModules()</code> method.</p>
</div>
<div class="paragraph">
<p>If menu items or contributions are not required in the UI, these can be suppressed either using security or by
implementing a <a href="ugbtb.html#_ugbtb_decoupling_vetoing-visibility">vetoing subscriber</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_28">11.1.5. Related Services</h4>
<div class="paragraph">
<p>The auditing service works very well with implementations of
<a href="#<em>rgsvc_spi_PublisherService"><code>PublisherService</code></a> that persist the <code>Interaction.Execution</code> objects
obtained from the <a href="#_rgsvc_api_InteractionContext"><code>InteractionContext</code></a> service. The interaction
execution captures the _cause</em> of an interaction (an action was invoked, a property was edited), while the
<code>AuditerService</code> audit entries capture the <em>effect</em> of that interaction in terms of changed state.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Prior to <code>1.13.0-SNAPSHOT</code> the <a href="#<em>rgsvc_spi_CommandService"><code>CommandService</code></a> performed a similar role,
of capturing the cause. As of <code>1.13.0-SNAPSHOT</code>, <code>Command</code>s are now primarily to capture the _intent</em> of an action,
not the actual action invocation itself.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The <code>AuditerService</code> is intended to replace the (now-deprecated)
<a href="#_rgsvc_spi_AuditingService3"><code>AuditingService3</code></a>, as the latter does not support the concept of multiple
transactions within a single interaction.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_AuditingService">11.2. <code>AuditingService3</code></h3>
<div class="paragraph">
<p>The <code>AuditingService3</code> auditing service provides a simple mechanism to capture changes to data. It is called for each property that has changed on any domain object, as a set of pre- and post-values.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>In case you are wondering what happened to <code>AuditingService</code> and <code>AuditingService2</code>, these were earlier versions of the SPI that have since been deprecated and removed.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_spi_19">11.2.1. SPI</h4>
<div class="paragraph">
<p>The SPI for the service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">AuditingService3</span> {
<span class="annotation">@Programmatic</span>
<span class="directive">public</span> <span class="type">void</span> audit(
<span class="directive">final</span> <span class="predefined-type">UUID</span> transactionId, <span class="predefined-type">String</span> targetClassName, <span class="directive">final</span> Bookmark target,
<span class="predefined-type">String</span> memberIdentifier, <span class="directive">final</span> <span class="predefined-type">String</span> propertyName,
<span class="directive">final</span> <span class="predefined-type">String</span> preValue, <span class="directive">final</span> <span class="predefined-type">String</span> postValue,
<span class="directive">final</span> <span class="predefined-type">String</span> user, <span class="directive">final</span> java.sql.Timestamp timestamp);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The framework will call this for each and every domain object property that is modified within a transaction.</p>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_29">11.2.2. Implementation</h4>
<div class="paragraph">
<p>The most full-featured available implementation is the (non-ASF) <a href="http://github.com/isisaddons/isis-module-audit">Isis addons' Audit module</a>. This creates an audit records for each changed property (ie every time that <code>AuditingService3#audit(…​)</code> is called. The implementation is <code>org.isisaddons.module.audit.dom.AuditingService</code>.</p>
</div>
<div class="paragraph">
<p>The module also provides:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>AuditingServiceMenu</code> service which provides actions to search for <code>AuditEntry</code>s, underneath an 'Activity' menu on the secondary menu bar.</p>
</li>
<li>
<p><code>AuditingServiceRepository</code> service to to search for persisted <code>AuditEntry``s. None of its actions are visible in the user interface (they are all `@Programmatic</code>).</p>
</li>
<li>
<p><code>AuditingServiceContributions</code> which contrbutes collections to the <a href="rgcms.html#_rgcms_classes_mixins_HasTransactionId"> <code>HasTransactionId</code></a> interface. This will therefore display all audit entries that occurred in a given transaction, in other words whenever a command, a published event or another audit entry is displayed.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>If you just want to debug (writing to stderr), you can instead configure <code>o.a.i.applib.services.audit.AuditingService3$Stderr</code></p>
</div>
</div>
<div class="sect3">
<h4 id="_usage_18">11.2.3. Usage</h4>
<div class="paragraph">
<p>The typical way to indicate that an object should be audited is to annotate it with the <a href="rgant.html#_rgant-DomainObject_auditing"><code>@DomainObject#auditing()</code></a> annotation.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_19">11.2.4. Registering the Services</h4>
<div class="paragraph">
<p>The (non-ASF) <a href="http://github.com/isisaddons/isis-module-audit">Isis addons' audit</a> module provides an implementation of
this service (<code>AuditingService</code>), and also provides a number of related domain services (<code>AuditingServiceMenu</code>,
<code>AuditingServiceRepository</code> and <code>AuditingServiceContributions</code>).</p>
</div>
<div class="paragraph">
<p>Assuming that an <code>AppManifest</code> is being used to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>)
then this can be activated by updating the <code>pom.xml</code> and updating the <code>AppManifest#getModules()</code> method.</p>
</div>
<div class="paragraph">
<p>If menu items or contributions are not required in the UI, these can be suppressed either using security or by
implementing a <a href="ugbtb.html#_ugbtb_decoupling_vetoing-visibility">vetoing subscriber</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_29">11.2.5. Related Services</h4>
<div class="paragraph">
<p>This service has been deprecated and replaced by the equivalent
<a href="#_rgsvc_spi_AuditerService"><code>AuditerService</code></a> (<code>1.13.0-SNAPSHOT</code>).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_EventSerializer">11.3. <code>EventSerializer</code></h3>
<div class="paragraph">
<p>The <code>EmailSerializer</code> service is a supporting service intended for use by (any implementation of) <a href="#_rgsvc_spi_PublishingService"><code>PublishingService</code></a>. Its responsibility is to combine the <code>EventMetadata</code> and the <code>EventPayload</code> into some serialized form (such as JSON, XML or a string) that can then be published.</p>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<i class="fa icon-warning" title="Warning"></i>
</td>
<td class="content">
<div class="paragraph">
<p>This service is deprecated, replaced with <a href="#_rgsvc_spi_PublisherService"><code>PublisherService</code></a>
(<code>1.13.0-SNAPSHOT</code>).</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>See <a href="#_rgsvc_spi_PublishingService"><code>PublishingService</code></a> for further discussion.</p>
</div>
<div class="sect3">
<h4 id="_spi_20">11.3.1. SPI</h4>
<div class="paragraph">
<p>The SPI defined by this service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Deprecated</span>
<span class="directive">public</span> <span class="type">interface</span> <span class="class">EventSerializer</span> {
<span class="predefined-type">Object</span> serialize( <i class="conum" data-value="1"></i><b>(1)</b>
EventMetadata metadata, <i class="conum" data-value="2"></i><b>(2)</b>
EventPayload payload); <i class="conum" data-value="3"></i><b>(3)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>returns an object for maximum flexibility, which is then handed off to the <code>PublishingService</code>.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>standard metadata about the event, such as the user, the <a href="rgcms.html#_rgcms_classes_mixins_HasTransactionId"><code>transactionId</code></a>, date/time etc</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>for published actions, will generally be an <code>EventPayloadForActionInvocation</code> (or subclass thereof); for published objects, will generally be an <code>EventPayloadForObjectChanged</code> (or subclass thereof)</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>It’s important to make sure that the publishing service implementation is able to handle the serialized form. Strings are a good lowest common denominator, but in some cases a type-safe equivalent, such as a w3c DOM <code>Document</code> or JSON node might be passed instead.</p>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_30">11.3.2. Implementation</h4>
<div class="paragraph">
<p>The (non-ASF) <a href="http://github.com/isisaddons/isis-module-publishing">Isis addons' publishing</a> module provides an implementation (<code>org.isisaddons.module.publishing.dom.eventserializer.RestfulObjectsSpecEventSerializer</code>) that represents the event payload using the representation defined by the <a href="http://restfulobjects.org">Restful Objects spec</a> of (transient) objects, grafting on the metadata as additional JSON nodes.</p>
</div>
<div class="paragraph">
<p>For example, this is the JSON generated on an action invocation:</p>
</div>
<div class="imageblock">
<div class="content">
<a class="image" href="images/reference-services-spi/EventSerializer/action-invocation-published-to-stderr.png"><img src="images/reference-services-spi/EventSerializer/action-invocation-published-to-stderr.png" alt="action invocation published to stderr" width="750px"></a>
</div>
<div class="title">Figure 1. JSON representation of a published action invocation</div>
</div>
<div class="paragraph">
<p>while this is the object change JSON:</p>
</div>
<div class="imageblock">
<div class="content">
<a class="image" href="images/reference-services-spi/EventSerializer/changed-object-published-to-stderr.png"><img src="images/reference-services-spi/EventSerializer/changed-object-published-to-stderr.png" alt="changed object published to stderr" width="750px"></a>
</div>
<div class="title">Figure 2. JSON representation of a published changed object</div>
</div>
<div class="paragraph">
<p>You could if you wish change the representation by registering your own implementation of this API in <code>isis.properties</code>:</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_20">11.3.3. Registering the Services</h4>
<div class="paragraph">
<p>There is no default implementation of this service provided by the core Apache Isis framework.</p>
</div>
<div class="paragraph">
<p>The (non-ASF) <a href="http://github.com/isisaddons/isis-module-publishing">Isis addons' publishing</a> module provides an
implementation of this service (<code>RestfulObjectsSpecEventSerializer</code>) that serializes action invocations and published
objects into a format based on the Restful Objects specification. It also (as you might imagine) provides an
implementation of the <a href="#_rgsvc_spi_PublishingService"><code>PublishingService</code></a>.</p>
</div>
<div class="paragraph">
<p>Assuming that an <code>AppManifest</code> is being used to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>)
then this can be activated by updating the <code>pom.xml</code> and updating the <code>AppManifest#getModules()</code> method.</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_30">11.3.4. Related Services</h4>
<div class="paragraph">
<p>This service is intended (though not mandated) to be used by implementations of <a href="#_rgsvc_spi_PublishingService"><code>PublishingService</code></a>. The (non-ASF) <a href="http://github.com/isisaddons/isis-module-publishing">Isis addons' publishing</a> module does use it (though the (non-ASF)
<a href="http://github.com/isisaddons/isis-module-publishmq">Isis addons' publishmq</a> module does not).</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_PublisherService">11.4. <code>PublisherService</code> (<code>1.13.0-SNAPSHOT</code>)</h3>
<div class="paragraph">
<p>The <code>PublisherService</code> API (<code>1.13.0-SNAPSHOT</code>) is intended for coarse-grained publish/subscribe for system-to-system interactions, from Apache Isis to some other system. Events that can be published are action invocations/property
edits, and changed objects. A typical use case is to publish onto a pub/sub bus such as
<a href="http://activemq.apache.org/">ActiveMQ</a> with <a href="http://camel.apache.org">Camel</a> to keep other systems up to date.</p>
</div>
<div class="paragraph">
<p>An alternative use is for profiling: for each execution (action invocation/property edit) the framework captures
metrics of the number of objects loaded or dirtied as the result of that execution. If the
<a href="#_rgsvc_api_WrapperFactory"><code>WrapperFactory</code></a> is used to call other objects then the metrics are captured
for each sub-execution. The framework provides a default implementation, <code>PublisherServiceLogging</code>, that will log
these execution graphs (in XML form, per the <a href="rgcms.html#_rgcms_schema-ixn">"ixn" schema</a>) to an SLF4J logger.</p>
</div>
<div class="paragraph">
<p>Only actions/properties/domain objects annotated for publishing (using
<a href="rgant.html#_rgant-Action_publishing"><code>@Action#publishing()</code></a>,
<a href="rgant.html#_rgant-Property_publishing"><code>@Property#publishing()</code></a> or
<a href="rgant.html#_rgant-DomainObject_publishing"><code>@DomainObject#publishing()</code></a>) are published.</p>
</div>
<div class="sect3">
<h4 id="_spi_21">11.4.1. SPI</h4>
<div class="paragraph">
<p>The SPI defined by the service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">PublisherService</span> {
<span class="type">void</span> publish(<span class="directive">final</span> Interaction.Execution<?, ?> execution); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="type">void</span> publish(<span class="directive">final</span> PublishedObjects publishedObjects); <i class="conum" data-value="2"></i><b>(2)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>to publish an individual action invocation or property edit, as captured within an <code>Interaction.Execution</code>.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>to publish a set of changed objects.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Each <code>Interaction.Execution</code> has an owning <code>Interaction</code>; this is the same object obtainable from
<a href="#_rgsvc_spi_InteractionContext"><code>InteractionContext</code></a>. Implementations that publish member executions
can use <code>Interaction.Execution#getDto()</code> method to return a DTO (as per the
<a href="rgcms.html#_rgcms_schema-ixn">"ixn" schema</a>) which can be converted into a serializable XML representation using
the <code>InteractionDtoUtils</code> utility class. The XML can either serialize a single execution, or can be a "deep"
serialization of an execution and all sub-executions.</p>
</div>
<div class="paragraph">
<p>The full API of <code>PublishedObjects</code> itself is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">PublishedObjects</span> <span class="directive">extends</span> HasTransactionId, HasUsername {
<span class="predefined-type">UUID</span> getTransactionId(); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="predefined-type">String</span> getUsername(); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="predefined-type">Timestamp</span> getCompletedAt(); <i class="conum" data-value="3"></i><b>(3)</b>
ChangesDto getDto(); <i class="conum" data-value="4"></i><b>(4)</b>
<span class="type">int</span> getNumberLoaded(); <i class="conum" data-value="5"></i><b>(5)</b>
<span class="type">int</span> getNumberCreated();
<span class="type">int</span> getNumberUpdated();
<span class="type">int</span> getNumberDeleted();
<span class="type">int</span> getNumberPropertiesModified();
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>inherited from <code>HasTransactionId</code>, correlates back to the unique identifier of the transaction in which these
objects were changed.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>inherited from <code>HasUsername</code>, is the user that initiated the transaction causing these objects to change</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>the time that this set of objects was collated (just before the completion of the transaction completes)..</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>returns a DTO (as per the <a href="rgcms.html#_rgcms_schema-chg">"chg" schema</a>) which can be converted into a
serializable XML representation can be obtained using the <code>ChangesDtoUtils</code> utility class.</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>metrics as to the number of objects loaded, created, updated or deleted and the number of object properties modified (in other words the "size" or "weight" of the transaction).</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_31">11.4.2. Implementation</h4>
<div class="paragraph">
<p>The framework allows multiple implementations of this service to be registered; all will be called. The framework
provides one implementation of its own, <code>PublisherServiceLogging</code> (in <code>o.a.i.applib.services.publish</code> package); this
logs "deep" serializations to an SLF4J logger.</p>
</div>
<div class="paragraph">
<p>The (non-ASF) <a href="http://github.com/isisaddons/isis-module-publishmq">Isis addons' publishmq</a> module also provides an
implementation (<code>o.ia.m.publishmq.dom.servicespi.PublishingServiceUsingActiveMq</code>). This implementation publishes each
member execution as an event on an <a href="http://activemq.apache.org">ActiveMQ</a> message queue. It also persists each
execution as a <code>PublishedEvent</code> entity, allowing the event to be republished if necessary. The implementation also
provides the ability to log additional <code>StatusMessage</code> entities, correlated on the transactionId, useful for diagnosing
and monitoring the activity of subscribers of said message queues.</p>
</div>
</div>
<div class="sect3">
<h4 id="_usage_19">11.4.3. Usage</h4>
<div class="paragraph">
<p>To indicate that an action invocation should be published, annotate it with the
<a href="rgant.html#_rgant-Action_publishing"><code>@Action#publishing()</code></a> annotation.</p>
</div>
<div class="paragraph">
<p>To indicate that an property edit should be published, annotate it with the
<a href="rgant.html#_rgant-Property_publishing"><code>@Property#publishing()</code></a> annotation.</p>
</div>
<div class="paragraph">
<p>To indicate that a changed object should be published is to annotate it with the
<a href="rgant.html#_rgant-DomainObject_publishing"><code>@DomainObject#publishing()</code></a> annotation.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_21">11.4.4. Registering the Services</h4>
<div class="paragraph">
<p>The (non-ASF) Isis addons' <a href="http://github.com/isisaddons/isis-module-publishmq">publishmq</a> module provides an
implementation of this service. Assuming that an <code>AppManifest</code> is being used to
<a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then this can be activated by updating
the <code>pom.xml</code> and updating the <code>AppManifest#getModules()</code> method.</p>
</div>
<div class="paragraph">
<p>The module also provide services that contribute to the UI. If contributions are not required in the UI, these can be
suppressed either using security or by implementing a
<a href="ugbtb.html#_ugbtb_decoupling_vetoing-visibility">vetoing subscriber</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_31">11.4.5. Related Services</h4>
<div class="paragraph">
<p>This service supports two main use cases:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>coarse-grained publish/subscribe for system-to-system interactions, from Apache Isis to some other system.<br></p>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The <a href="#_rgsvc_spi_PublishingService"><code>PublishingService</code></a> also supports this use case, but
is deprecated: the <code>PublisherService</code> is intended as a replacement for <code>PublishingService</code>.</p>
</div>
</td>
</tr>
</table>
</div>
</li>
<li>
<p>profiling of interactions/transactions, eg to diagnose response/throughput issues.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>To support these use cases several other services are involved:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>the <a href="#_rgsvc_api_InteractionContext"><code>InteractionContext</code></a> is used to obtain the <code>Interaction</code> from which
the member executions are published.</p>
</li>
<li>
<p>the (internal) <a href="rgfis.html#_rgfis_spi_ChangedObjectsServiceInternal"><code>ChangedObjectsServiceInternal</code></a> domain
service is used to obtain the set of objects modified throughout the transaction</p>
</li>
<li>
<p>the (internal) <a href="rgfis.html#_rgfis_spi_PublisherServiceInternal"><code>PublisherServiceInternal</code></a> domain service filters
these down to those changed objects that are also published (as per
<a href="rgant.html#_rgant-DomainObject_publishing"><code>@DomainObject#publishing()</code></a>) and delegates to the <code>PublisherService</code>.</p>
</li>
<li>
<p>the <a href="#_rgsvc_api_MetricsService"><code>MetricsService</code></a> is used to obtain the objects that are loaded
throughout the transaction; this info is used in order to instantiate the <code>PublishedObjects</code> object passed through to
the <code>PublisherService</code>.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The <a href="#_rgsvc_api_EventBusService"><code>EventBusService</code></a> differs from the <code>PublisherService</code> in that it is
intended for fine-grained publish/subscribe for object-to-object interactions within an Apache Isis domain object
model. The event propagation is strictly in-memory, and there are no restrictions on the object acting as the event;
it need not be serializable, for example. That said, it is possible to obtain a serialization of the action
invocation/property edit causing the current event to be raised using
<a href="#_rgsvc_api_InteractionContext"><code>InteractionContext</code></a> domain service.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_PublishingService">11.5. <code>PublishingService</code></h3>
<div class="paragraph">
<p>The <code>PublishingService</code> API is intended for coarse-grained publish/subscribe for system-to-system interactions, from Apache Isis to some other system. Here the only events published are those that action invocations and of changed objects. A typical use case is to publish onto a pub/sub bus such as <a href="http://activemq.apache.org/">ActiveMQ</a> with <a href="http://camel.apache.org">Camel</a> to keep other systems up to date.</p>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<i class="fa icon-warning" title="Warning"></i>
</td>
<td class="content">
<div class="paragraph">
<p>This service is deprecated, replaced with <a href="#_rgsvc_spi_PublisherService"><code>PublisherService</code></a> (<code>1.13.0-SNAPSHOT</code>).</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_spi_22">11.5.1. SPI</h4>
<div class="paragraph">
<p>The SPI defined by the service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Deprecated</span>
<span class="directive">public</span> <span class="type">interface</span> <span class="class">PublishingService</span> {
<span class="directive">public</span> <span class="type">void</span> publish(
EventMetadata metadata, <i class="conum" data-value="1"></i><b>(1)</b>
EventPayload payload); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="type">void</span> setEventSerializer(EventSerializer eventSerializer); <i class="conum" data-value="3"></i><b>(3)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>standard metadata about the event, such as the user, the <a href="rgcms.html#_rgcms_classes_mixins_HasTransactionId"><code>transactionId</code></a>, date/time etc</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>for published actions, an <code>EventPayloadForActionInvocation</code> (or subclass thereof); for published objects, an <code>EventPayloadForObjectChanged</code> (or subclass thereof)</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>injects in the <a href="#_rgsvc_spi_EventSerializer"><code>EventSerializer</code></a> service. This is deprecated because not every implementation is required to use an <code>EventSerializer</code> so its inclusion within the SPI of <code>PublishingService</code> was in retrospect a mistake.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Typically implementations will use the injected <code>EventSerializer</code> to convert the metadata and payload into a form to be published:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">EventSerializer</span> {
<span class="directive">public</span> <span class="predefined-type">Object</span> serialize(EventMetadata metadata, EventPayload payload);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The serialized form returned by <code>EventSerializer</code> must be in a form that the <code>PublishingService</code> implementation is able to handle. Strings are a good lowest common denominator, but (if custom implementations of both <code>EventSerializer</code> and <code>PublishingService</code> were in use) then it might also be some other type, for example an <code>org.w3c.dom.Document</code> or an <code>org.json.JSONObject</code> might be returned instead.</p>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_32">11.5.2. Implementation</h4>
<div class="paragraph">
<p>The (non-ASF) <a href="http://github.com/isisaddons/isis-module-publishing">Isis addons' publishing</a> module provides an
implementation (<code>org.isisaddons.module.publishing.dom.PublishingService</code>) that persists each
event as a <code>PublishedEvent</code> entity. This holds the serialized form of the event metadata and payload as translated
into a string by the injected <code>EventSerializer</code>. The module also provides its own implementation of <code>EventSerializer</code>,
namely <code>RestfulObjectsSpecEventSerializer</code>, which represents the event payload using the representation defined by the
<a href="http://restfulobjects.org">Restful Objects spec</a> of (transient) objects, grafting on the metadata as additional
JSON nodes.</p>
</div>
<div class="paragraph">
<p>The <code>PublishedEvent</code> entity also has a <code>state</code> field taking the values either "QUEUED" or "PROCESSED". The intention
here is that an event bus can poll this table to grab pending events and dispatch them to downstream systems. When
<code>PublishedEvent</code>s are persisted initially they always take the value "QUEUED".</p>
</div>
<div class="paragraph">
<p>The framework provides no default implementations of this service.</p>
</div>
</div>
<div class="sect3">
<h4 id="_usage_20">11.5.3. Usage</h4>
<div class="paragraph">
<p>To indicate that an action invocation should be published, annotate it with the <a href="rgant.html#_rgant-Action_publishing"><code>@Action#publishing()</code></a> annotation.</p>
</div>
<div class="paragraph">
<p>To indicate that a changed object should be published is to annotate it with the <a href="rgant.html#_rgant-DomainObject_publishing"><code>@DomainObject#publishing()</code></a> annotation.</p>
</div>
<div class="paragraph">
<p>It is also possible to "fine-tune" the <code>EventPayload</code> using the <code>#publishingFactory()</code> attribute (for both annotations). By default the <code>EventPayload</code> that is serialized identifies the object(s) being interacted with or changed, and in the case of the action invocation provides details of the action arguments and result (if any) of that action. However, the payload does not (by default) include any information about the new state of these objects. It is therefore the responsibility of the subscriber to call back to Apache Isis to determine any information that has not been published.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>The replacement <a href="#_rgsvc_spi_PublisherService"><code>PublisherService</code></a> does <em>not</em> support the concept of "payload factories" (but is otherwise more flexible).</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Although the representations (if using the Restful Object serializer and Restful Objects viewer) does include hrefs
for the objects, this nevertheless requires an additional network call to obtain this information).</p>
</div>
<div class="paragraph">
<p>In some circumstances, then, it may make more sense to eagerly "push" information about the change to the subscriber by including that state within the payload.</p>
</div>
<div class="paragraph">
<p>To accomplish this, an implementation of a “PayloadFactory” must be specified in the annotation.</p>
</div>
<div class="paragraph">
<p>For actions, we implement the <code>PublishingPayloadFactoryForAction</code> (in <code>o.a.i.applib.annotation</code>):</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Deprecated</span>
<span class="directive">public</span> <span class="type">interface</span> <span class="class">PublishingPayloadFactoryForAction</span> {
<span class="directive">public</span> EventPayload payloadFor(
Identifier actionIdentifier,
<span class="predefined-type">Object</span> target,
<span class="predefined-type">List</span><<span class="predefined-type">Object</span>> arguments,
<span class="predefined-type">Object</span> result);
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>EventPayloadForActionInvocation</code> abstract class (in the Isis applib) should be used as the base class for the object instance returned from <code>payLoadFor(…​)</code>.</p>
</div>
<div class="paragraph">
<p>For objects, the interface to implement is <code>PublishingPayloadFactoryForObject</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@Deprecated</span>
<span class="directive">public</span> <span class="type">interface</span> <span class="class">PublishingPayloadFactoryForObject</span> {
<span class="directive">public</span> EventPayload payloadFor(
<span class="predefined-type">Object</span> changedObject,
PublishingChangeKind publishingChangeKind); <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>an enum taking the values <code>CREATE</code>, <code>UPDATE</code>, <code>DELETE</code></td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Similarly, the <code>EventPayloadForObjectChanged</code> abstract class should be used as the base class for the object returned from <code>payLoadFor(…​)</code>.</p>
</div>
<div class="paragraph">
<p>For example, the following will eagerly include a <code>ToDoItem’s `description</code> property whenever it is changed:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainObject</span>(publishingPayloadFactory=ToDoItemPayloadFactory.class)
<span class="directive">public</span> <span class="type">class</span> <span class="class">ToDoItem</span> {
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>where <code>ToDoItemPayloadFactory</code> is defined as:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">ToDoItemChangedPayloadFactory</span> <span class="directive">implements</span> PublishingPayloadFactoryForObject {
<span class="directive">public</span> <span class="directive">static</span> <span class="type">class</span> <span class="class">ToDoItemPayload</span>
<span class="directive">extends</span> EventPayloadForObjectChanged<ToDoItem> {
<span class="directive">public</span> ToDoItemPayload(ToDoItem changed) { <span class="local-variable">super</span>(changed); }
<span class="directive">public</span> <span class="predefined-type">String</span> getDescription() { <span class="keyword">return</span> getChanged().getDescription(); }
}
<span class="annotation">@Override</span>
<span class="directive">public</span> EventPayload payloadFor(<span class="predefined-type">Object</span> changedObject, PublishingChangeKind kind) {
<span class="keyword">return</span> <span class="keyword">new</span> ToDoItemPayload((ToDoItem) changedObject);
}
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_22">11.5.4. Registering the Services</h4>
<div class="paragraph">
<p>There is no default implementation of this service provided by the core Apache Isis framework.</p>
</div>
<div class="paragraph">
<p>The (non-ASF) Isis addons' <a href="http://github.com/isisaddons/isis-module-publishing">publishing</a> module provides an
implementation of this service. Assuming that an <code>AppManifest</code> is being used to
<a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then this can be activated by updating
the <code>pom.xml</code> and updating the <code>AppManifest#getModules()</code> method.</p>
</div>
<div class="paragraph">
<p>The module also provides services that contribute to the UI. If contributions are not required in the UI, these can be
suppressed either using security or by implementing a
<a href="ugbtb.html#_ugbtb_decoupling_vetoing-visibility">vetoing subscriber</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_32">11.5.5. Related Services</h4>
<div class="paragraph">
<p>The <code>PublishingService</code> is intended for coarse-grained publish/subscribe for system-to-system interactions, from
Apache Isis to some other system. Here the only events published are those that action invocations (for actions
annotated with <a href="rgant.html#_rgant-Action_publishing"><code>@Action#publishing()</code></a>) and of changed objects (for objects
annotated with <a href="rgant.html#_rgant-DomainObject_publishing"><code>@DomainObject#publishing()</code></a>.</p>
</div>
<div class="paragraph">
<p>The <a href="#_rgsvc_spi_PublisherService"><code>PublisherService</code></a> is intended as a replacement for this service. The
use case for <code>PublisherService</code> is the same: coarse-grained publishing of events for system-to-system interactions. It
is in most respects more flexible though: events are published both for action invocations (annotated with
<a href="rgant.html#_rgant-Action_publishing"><code>@Action#publishing()</code></a>) and also for property edits (annotated with
<a href="rgant.html#_rgant-Property_publishing"><code>@Property#publishing()</code></a>. It also publishes changed objects (for objects
annotated with <a href="rgant.html#_rgant-DomainObject_publishing"><code>@DomainObject#publishing()</code></a>). However, rather than
publishing one event for every changed objects, it publishes a single event that identifies all objects created,
updated or deleted.</p>
</div>
<div class="paragraph">
<p>Another significant difference between <code>PublishingService</code> and <code>PublisherService</code> is in the content of the events
themselves. While the former uses the <a href="#_rgsvc_api_MementoService"><code>MementoService</code></a> to create an
ad-hoc serialization of the action being invoked, the latter uses the <a href="rgcms.html#_rgcms_schema">DTOs/XML schemas</a>
as a formal specification of the nature of the interaction (action invocation, property edit or changed objects).</p>
</div>
<div class="paragraph">
<p>The <a href="#_rgsvc_api_EventBusService"><code>EventBusService</code></a> meanwhile differs from both <code>PublishingService</code> and
<a href="#_rgsvc_spi_PublisherService"><code>PublisherService</code></a> in that it is intended for fine-grained
publish/subscribe for object-to-object interactions within an Apache Isis domain object model. The event propagation
is strictly in-memory, and there are no restrictions on the object acting as the event; it need not be serializable,
for example. (That said, it is possible to obtain a serialization of the action invocation/property edit causing the
current event to be raised using <a href="#_rgsvc_api_InteractionContext"><code>InteractionContext</code></a> domain service).</p>
</div>
</div>
<div class="sect3">
<h4 id="_design_notes">11.5.6. Design Notes</h4>
<div class="paragraph">
<p>The following class diagram shows how the above components fit together:</p>
</div>
<div class="imageblock">
<div class="content">
<a class="image" href="images/reference-services-spi/PublishingService/yuml.me-23db58a4.png"><img src="images/reference-services-spi/PublishingService/yuml.me-23db58a4.png" alt="yuml.me 23db58a4" width="800px"></a>
</div>
</div>
<div class="paragraph">
<p>This yuml.me diagram was generated at <a href="http://yuml.me/edit/23db58a4">yuml.me</a>.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_UserRegistrationService">11.6. <code>UserRegistrationService</code></h3>
<div class="paragraph">
<p>The <code>UserRegistrationService</code> provides the ability for users to sign-up to access an application by providing a valid email address, and also provides the capability for users to reset their password if forgotten.</p>
</div>
<div class="paragraph">
<p>For user sign-up, the <a href="ugvw.html">Wicket viewer</a> will check whether an implementation of this service (and also the <a href="#<em>rgsvc_spi_EmailNotificationService"><code>EmailNotificationService</code></a>) is available, and if so will render a sign-up page where the user enters their email address. A verification email is sent (using the aforementioned <code>EmailNotificationService</code>) which includes a link back to the running application; this allows the user then to complete their registration process (choose user name, password and so on). When the user has provided the additional details, the Wicket viewer calls _this</em> service in order to create an account for them, and then logs the user on.</p>
</div>
<div class="paragraph">
<p>For the password reset feature, the Wicket viewer will render a password reset page, and use the <code>EmailNotificationService</code> to send a "password forgotten" email. This service provides the ability to reset a password based on the user’s email address.</p>
</div>
<div class="paragraph">
<p>It is of course possible for domain objects to use this service; it will be injected into domain object or other domain services in the usual way. That said, we expect that such use cases will be comparatively rare; the primary use case is for the Wicket viewer’s sign-up page.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>For further details on the user registration feature (as supported by the Wicket viewer), see <a href="ugvw.html#_ugvw_features_user-registration">here</a>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="_spi_23">11.6.1. SPI</h4>
<div class="paragraph">
<p>The SPI defined by the service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">UserRegistrationService</span> {
<span class="annotation">@Programmatic</span>
<span class="type">boolean</span> usernameExists(<span class="predefined-type">String</span> username); <i class="conum" data-value="1"></i><b>(1)</b>
<span class="annotation">@Programmatic</span>
<span class="type">boolean</span> emailExists(<span class="predefined-type">String</span> emailAddress); <i class="conum" data-value="2"></i><b>(2)</b>
<span class="annotation">@Programmatic</span>
<span class="type">void</span> registerUser(<span class="predefined-type">String</span> username, <span class="predefined-type">String</span> password, <span class="predefined-type">String</span> emailAddress); <i class="conum" data-value="3"></i><b>(3)</b>
<span class="annotation">@Programmatic</span>
<span class="type">boolean</span> updatePasswordByEmail(<span class="predefined-type">String</span> emailAddress, <span class="predefined-type">String</span> password); <i class="conum" data-value="4"></i><b>(4)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>checks if there is already a user with the specified username</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>checks if there is already a user with the specified email address</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>creates the user, with specified password and email address. The username and email address must both be unique (not being used by an existing user)</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>allows the user to reset their password</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_33">11.6.2. Implementation</h4>
<div class="paragraph">
<p>The core Apache Isis framework itself defines only an API; there is no default implementation. Rather, the implementation will depend on the security mechanism being used.</p>
</div>
<div class="paragraph">
<p>That said, if you have configured your app to use the <a href="http://github.com/isisaddons/isis-module-security">Isis addons security module</a>, then note that the security module does provide an abstract implementation (<code>SecurityModuleAppUserRegistrationServiceAbstract</code>) of the <code>UserRegistrationService</code>. You will need to extend that service and provide implementation for the two abstract methods: <code>getInitialRole()</code> and <code>getAdditionalInitialRoles()</code>.</p>
</div>
<div class="paragraph">
<p>This is needed so that the self-registered users are assigned automatically to your application role(s) and be able to use the application. Without any role such user will be able only to see/use the logout link of the application.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_23">11.6.3. Registering the Services</h4>
<div class="paragraph">
<p>There is no default implementation of this service provided by the core Apache Isis framework.</p>
</div>
<div class="paragraph">
<p>If using the (non-ASF) <a href="http://github.com/isisaddons/isis-module-security">Isis addons' security</a> module) for
authentication and authorization, then note that it provides an adapter class,
<code>SecurityModuleAppUserRegistrationServiceAbstract</code>, that provides most of the implementation. You are still required
to implement a subclass and register.</p>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="annotation">@DomainService</span>(nature=NatureOfService.DOMAIN)
<span class="directive">public</span> <span class="type">class</span> <span class="class">AppUserRegistrationService</span> <span class="directive">extends</span> SecurityModuleAppUserRegistrationServiceAbstract {
<span class="directive">protected</span> ApplicationRole getInitialRole() {
<span class="keyword">return</span> findRole(<span class="string"><span class="delimiter">"</span><span class="content">regular-user</span><span class="delimiter">"</span></span>);
}
<span class="directive">protected</span> <span class="predefined-type">Set</span><ApplicationRole> getAdditionalInitialRoles() {
<span class="keyword">return</span> <span class="predefined-type">Collections</span>.singleton(findRole(<span class="string"><span class="delimiter">"</span><span class="content">self-registered-user</span><span class="delimiter">"</span></span>));
}
<span class="directive">private</span> ApplicationRole findRole(<span class="directive">final</span> <span class="predefined-type">String</span> roleName) {
<span class="keyword">return</span> applicationRoles.findRoleByName(roleName);
}
<span class="annotation">@Inject</span>
<span class="directive">private</span> ApplicationRoles applicationRoles;
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="_related_services_33">11.6.4. Related Services</h4>
<div class="paragraph">
<p>The most common use case is to allow users to sign-up through Apache Isis' Wicket viewer. Because the process requires email to be sent, the following services must be configured:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="#_rgsvc_api_EmailService"><code>EmailService</code></a></p>
</li>
<li>
<p><a href="#_rgsvc_spi_EmailNotificationService"><code>EmailNotificationService</code></a></p>
</li>
<li>
<p><code>UserRegistrationService</code> (this service)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The <code>EmailService</code> in particular requires additional <a href="rgcfg.html#_rgcfg_configuring-core">configuration properties</a> to specify the external SMTP service.</p>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_rgsvc_bootstrapping-spi">12. Bootstrapping SPI</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Bootstrapping SPIs influence how the framework locates the components that make up the running application.</p>
</div>
<div class="paragraph">
<p>The table below summarizes the bootstrapping SPI defined by Apache Isis. It also lists their corresponding implementation, either a default implementation provided by Apache Isis itself, or provided by one of the in (non-ASF) <a href="http://www.isisaddons.org">Isis Addons</a> modules.</p>
</div>
<table class="tableblock frame-all grid-all spread">
<caption class="title">Table 13. Bootstrapping SPI</caption>
<colgroup>
<col style="width: 25%;">
<col style="width: 50%;">
<col style="width: 12.5%;">
<col style="width: 12.5%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">SPI</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Implementation</th>
<th class="tableblock halign-left valign-top">Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="#_rgsvc_spi_ClassDiscoveryService"><code>o.a.i.applib.</code><br>
<code>services.classdiscovery</code><br>
<code>ClassDiscoveryService</code></a></p></td>
<td class="tableblock halign-left valign-top"><div><div class="paragraph">
<p>Mechanism to locate (from the classpath) classes with a specific annotation (eg <a href="rgant.html#_rgant-DomainService"><code>@DomainService</code></a>)</p>
</div>
<div class="paragraph">
<p>Subtypes of a given type (eg <a href="rgcms.html#_rgcms_classes_super_FixtureScript"><code>FixtureScript</code></a>).</p>
</div></div></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>ClassDiscoveryService-</code><br>
<code>UsingReflections</code><br>
<code>o.a.i.core</code><br>
<code>isis-core-applib</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">requires <code>org.reflections:reflections</code> as Maven dependency</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Key:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>o.a.i</code> is an abbreviation for <code>org.apache.isis</code></p>
</li>
<li>
<p><code>o.ia.m</code> is an abbreviation for <code>org.isisaddons.module</code></p>
</li>
<li>
<p><code>o.a.i.c.m.s</code> is an abbreviation for <code>org.apache.isis.core.metamodel.services</code></p>
</li>
<li>
<p><code>o.a.i.c.r.s</code> is an abbreviation for <code>org.apache.isis.core.runtime.services</code></p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="_rgsvc_spi_ClassDiscoveryService">12.1. <code>ClassDiscoveryService</code></h3>
<div class="paragraph">
<p>The <code>ClassDiscovery</code> service is used to automatically discover subclasses of any given type on the classpath. The primary use case is to support "convention-over-configuration" designs that work with a minimum of configuration.</p>
</div>
<div class="paragraph">
<p>This service is used by the <a href="rgcms.html#_rgcms_classes_super_FixtureScripts"><code>FixtureScripts</code></a> service to automatically locate any <a href="rgcms.html#_rgcms_classes_super_FixtureScript"><code>FixtureScript</code></a> implementations.</p>
</div>
<div class="sect3">
<h4 id="_spi_24">12.1.1. SPI</h4>
<div class="paragraph">
<p>The SPI defined by the service is:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">interface</span> <span class="class">ClassDiscoveryService2</span> {
<span class="annotation">@Programmatic</span>
<T> <span class="predefined-type">Set</span><<span class="predefined-type">Class</span><? <span class="directive">extends</span> T>> findSubTypesOfClasses(<span class="predefined-type">Class</span><T> type, <span class="predefined-type">String</span> packagePrefix);
<span class="annotation">@Deprecated</span>
<span class="annotation">@Programmatic</span>
<T> <span class="predefined-type">Set</span><<span class="predefined-type">Class</span><? <span class="directive">extends</span> T>> findSubTypesOfClasses(<span class="predefined-type">Class</span><T> type); <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>no longer used</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_implementation_34">12.1.2. Implementation</h4>
<div class="paragraph">
<p>Isis provides an implementation of this service, namely <code>o.a.i.applib.services.classdiscovery.ClassDiscoveryServiceUsingReflections</code>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>This implementation is also used to discover domain services annotated with <a href="rgant.html#_rgant-DomainService"><code>@DomainService</code></a>. Currently this logic uses the implementation directly, so is not pluggable. However, the entire <code>ServicesInstaller</code></p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="_usage_21">12.1.3. Usage</h4>
<div class="paragraph">
<p>The usage will vary depending upon the conventions of the design. As of 1.9.0, the usage of the service has been
centralized such that the packages to be scanned are located from the <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping"><code>AppManifest</code></a>'s <code>#getModules()</code> method.</p>
</div>
<div class="paragraph">
<p>For example, the <a href="ugfun.html#_ugfun_getting-started_simpleapp-archetype">SimpleApp archetype</a>'s app manifest includes:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="CodeRay highlight"><code data-lang="java"><span class="directive">public</span> <span class="type">class</span> <span class="class">DomainAppAppManifest</span> <span class="directive">implements</span> AppManifest {
<span class="annotation">@Override</span>
<span class="directive">public</span> <span class="predefined-type">List</span><<span class="predefined-type">Class</span><?>> getModules() {
<span class="keyword">return</span> <span class="predefined-type">Arrays</span>.asList(
DomainAppDomainModule.class, <span class="comment">// domain (entities and repositories)</span>
DomainAppFixtureModule.class, <span class="comment">// fixtures</span>
DomainAppAppModule.class <span class="comment">// home page service etc</span>
);
}
...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>where the three module classes in effect define three different package prefixes to search under (for domain services, fixture scripts and persistent entities).</p>
</div>
<div class="paragraph">
<p>Other usages of the <code>ClassDiscoveryService</code> are likely to work in a similar way, requiring some sort of scope to be specified.</p>
</div>
</div>
<div class="sect3">
<h4 id="_registering_the_services_24">12.1.4. Registering the Services</h4>
<div class="paragraph">
<p>Assuming that the <code>configuration-and-annotation</code> services installer is configured (implicit if using the
<code>AppManifest</code> to <a href="rgcms.html#_rgcms_classes_AppManifest-bootstrapping">bootstrap the app</a>) then Apache Isis' core
implementation of <code>ClassDiscoveryService2</code> service is automatically registered and injected (it is annotated with
<code>@DomainService</code>) so no further configuration is required.</p>
</div>
<div class="paragraph">
<p>To use an alternative implementation, use
<a href="rgant.html#_rgant-DomainServiceLayout_menuOrder"><code>@DomainServiceLayout#menuOrder()</code></a> (as explained
in the <a href="#_rgsvc_intro_overriding-the-services">introduction</a> to this guide).</p>
</div>
</div>
</div>
</div>
</div>
</div>
<footer>
<hr>
<p class="small">
Copyright © 2010~2016 The Apache Software Foundation, licensed under the Apache License, v2.0.
<br/>
Apache, the Apache feather logo, Apache Isis, and the Apache Isis project logo are all trademarks of The Apache Software Foundation.
</p>
</footer>
</div>
<div id="doc-content-right" class="large-3 medium-3 xcolumns">
<div id="toc" class="toc2">
<div class="fallback-toc">
<ul class="sectlevel1">
<li><a href="#_rgsvc">1. Domain Services</a>
<ul class="sectlevel2">
<li><a href="#_other_guides">1.1. Other Guides</a></li>
</ul>
</li>
<li><a href="#_rgsvc_intro">2. Introduction</a>
<ul class="sectlevel2">
<li><a href="#_rgsvc_intro_types-of-domain-services">2.1. Types of Domain Service</a></li>
<li><a href="#_rgsvc_intro_public-api">2.2. Public API vs Internal Services</a></li>
<li><a href="#_rgsvc_intro_using-the-services">2.3. Using the services</a></li>
<li><a href="#_rgsvc_intro_overriding-the-services">2.4. Overriding the services</a></li>
<li><a href="#_rgsvc_intro_commands-and-events">2.5. Command and Events (<code>1.13.0-SNAPSHOT</code>)</a></li>
</ul>
</li>
<li><a href="#_rgsvc_presentation-layer-spi">3. Presentation Layer SPI</a>
<ul class="sectlevel2">
<li><a href="#_rgsvc_spi_ContentMappingService">3.1. <code>ContentMappingService</code></a>
<ul class="sectlevel3">
<li><a href="#_spi">3.1.1. SPI</a></li>
<li><a href="#_implementations">3.1.2. Implementations</a></li>
<li><a href="#_related_services">3.1.3. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_spi_EmailNotificationService">3.2. <code>EmailNotificationService</code></a>
<ul class="sectlevel3">
<li><a href="#_spi_2">3.2.1. SPI</a></li>
<li><a href="#_implementation">3.2.2. Implementation</a>
<ul class="sectlevel4">
<li><a href="#_alternative_implementations">Alternative Implementations</a></li>
</ul>
</li>
<li><a href="#_registering_the_service">3.2.3. Registering the Service</a></li>
<li><a href="#_related_services_2">3.2.4. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_spi_ErrorReportingService">3.3. <code>ErrorReportingService</code></a>
<ul class="sectlevel3">
<li><a href="#_spi_3">3.3.1. SPI</a></li>
<li><a href="#_implementation_2">3.3.2. Implementation</a></li>
<li><a href="#_registering_the_services">3.3.3. Registering the Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_spi_ExceptionRecognizer">3.4. <code>ExceptionRecognizer</code></a>
<ul class="sectlevel3">
<li><a href="#_spi_4">3.4.1. SPI</a></li>
<li><a href="#_implementation_3">3.4.2. Implementation</a></li>
<li><a href="#_registering_the_services_2">3.4.3. Registering the Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_spi_GridSystemService">3.5. <code>GridSystemService</code></a>
<ul class="sectlevel3">
<li><a href="#_spi_5">3.5.1. SPI</a></li>
<li><a href="#_implementation_4">3.5.2. Implementation</a></li>
<li><a href="#_registering_the_services_3">3.5.3. Registering the Services</a></li>
<li><a href="#_related_services_3">3.5.4. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_spi_GridLoaderService">3.6. <code>GridLoaderService</code></a>
<ul class="sectlevel3">
<li><a href="#_spi_6">3.6.1. SPI</a></li>
<li><a href="#_implementation_5">3.6.2. Implementation</a></li>
<li><a href="#_registering_the_services_4">3.6.3. Registering the Services</a></li>
<li><a href="#_related_services_4">3.6.4. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_spi_GridService">3.7. <code>GridService</code></a>
<ul class="sectlevel3">
<li><a href="#_spi_7">3.7.1. SPI</a></li>
<li><a href="#_implementation_6">3.7.2. Implementation</a></li>
<li><a href="#_registering_the_services_5">3.7.3. Registering the Services</a></li>
<li><a href="#_related_services_5">3.7.4. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_spi_HintStore">3.8. <code>HintStore</code></a>
<ul class="sectlevel3">
<li><a href="#_spi_8">3.8.1. SPI</a></li>
<li><a href="#_implementation_7">3.8.2. Implementation</a></li>
<li><a href="#_registering_the_service_2">3.8.3. Registering the Service</a></li>
<li><a href="#_related_services_6">3.8.4. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_spi_LocaleProvider">3.9. <code>LocaleProvider</code></a>
<ul class="sectlevel3">
<li><a href="#_spi_9">3.9.1. SPI</a></li>
<li><a href="#_implementation_8">3.9.2. Implementation</a></li>
<li><a href="#_registering_the_services_6">3.9.3. Registering the Services</a></li>
<li><a href="#_related_services_7">3.9.4. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_spi_RoutingService">3.10. <code>RoutingService</code></a>
<ul class="sectlevel3">
<li><a href="#_spi_10">3.10.1. SPI</a></li>
<li><a href="#_implementation_9">3.10.2. Implementation</a></li>
<li><a href="#_registering_the_services_7">3.10.3. Registering the Services</a></li>
<li><a href="#_related_services_8">3.10.4. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_spi_TranslationService">3.11. <code>TranslationService</code></a>
<ul class="sectlevel3">
<li><a href="#_spi_11">3.11.1. SPI</a></li>
<li><a href="#_implementation_10">3.11.2. Implementation</a></li>
<li><a href="#_registering_the_services_8">3.11.3. Registering the Services</a></li>
<li><a href="#_rgsvc_api_LayoutService_related-mixins-and-menus">3.11.4. Related Menus</a></li>
<li><a href="#_related_services_9">3.11.5. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_spi_TranslationsResolver">3.12. <code>TranslationsResolver</code></a>
<ul class="sectlevel3">
<li><a href="#_spi_12">3.12.1. SPI</a></li>
<li><a href="#_implementation_11">3.12.2. Implementation</a></li>
<li><a href="#_registering_the_service_3">3.12.3. Registering the Service</a></li>
<li><a href="#_related_services_10">3.12.4. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_spi_UrlEncodingService">3.13. <code>UrlEncodingService</code></a>
<ul class="sectlevel3">
<li><a href="#_spi_13">3.13.1. SPI</a></li>
<li><a href="#_implementation_12">3.13.2. Implementation</a></li>
</ul>
</li>
<li><a href="#_rgsvc_spi_UserProfileService">3.14. <code>UserProfileService</code></a>
<ul class="sectlevel3">
<li><a href="#_spi_14">3.14.1. SPI</a></li>
<li><a href="#_implementation_13">3.14.2. Implementation</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#_rgsvc_application-layer-api">4. Application Layer API</a>
<ul class="sectlevel2">
<li><a href="#_rgsvc_api_AcceptHeaderService">4.1. <code>AcceptHeaderService</code></a>
<ul class="sectlevel3">
<li><a href="#_api_implementation">4.1.1. API & Implementation</a></li>
<li><a href="#_usage">4.1.2. Usage</a></li>
<li><a href="#_registering_the_service_4">4.1.3. Registering the Service</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_ActionInvocationContext">4.2. <code>ActionInvocationContext</code></a>
<ul class="sectlevel3">
<li><a href="#_api_implementation_2">4.2.1. API & Implementation</a></li>
<li><a href="#_usage_2">4.2.2. Usage</a></li>
<li><a href="#_registering_the_service_5">4.2.3. Registering the Service</a></li>
<li><a href="#_unit_testing_support">4.2.4. Unit testing support</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_BackgroundService">4.3. <code>BackgroundService2</code></a>
<ul class="sectlevel3">
<li><a href="#_api_implementation_3">4.3.1. API & Implementation</a></li>
<li><a href="#_usage_3">4.3.2. Usage</a></li>
<li><a href="#_end_user_experience">4.3.3. End-user experience</a></li>
<li><a href="#_registering_the_services_9">4.3.4. Registering the Services</a></li>
<li><a href="#_related_services_11">4.3.5. Related Services</a></li>
<li><a href="#_rgsvc_api_BackgroundService_BackgroundCommandExecution">4.3.6. <code>BackgroundCommandExec’n</code> abstract class</a></li>
<li><a href="#_rgsvc_api_BackgroundService_Quartz">4.3.7. Quartz Scheduler Configuration</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_CommandContext">4.4. <code>CommandContext</code></a>
<ul class="sectlevel3">
<li><a href="#_rgsvc_api_CommandContext_screencast">4.4.1. Screencast</a></li>
<li><a href="#_api_implementation_4">4.4.2. API & Implementation</a></li>
<li><a href="#_usage_4">4.4.3. Usage</a></li>
<li><a href="#_interacting_with_the_services">4.4.4. Interacting with the services</a></li>
<li><a href="#_registering_the_services_10">4.4.5. Registering the Services</a></li>
<li><a href="#_related_services_12">4.4.6. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_InteractionContext">4.5. <code>InteractionContext</code> (<code>1.13.0-SNAPSHOT</code>)</a>
<ul class="sectlevel3">
<li><a href="#_api_implementation_5">4.5.1. API & Implementation</a>
<ul class="sectlevel4">
<li><a href="#__code_interactioncontext_code"><code>InteractionContext</code></a></li>
<li><a href="#__code_interaction_code"><code>Interaction</code></a></li>
<li><a href="#__code_interaction_execution_code"><code>Interaction.Execution</code></a></li>
</ul>
</li>
<li><a href="#_interacting_with_the_services_2">4.5.2. Interacting with the services</a></li>
<li><a href="#_registering_the_service_6">4.5.3. Registering the Service</a></li>
<li><a href="#_rgsvc_api_InteractionContext_Related-Classes">4.5.4. Related Classes</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_MessageService">4.6. <code>MessageService</code></a>
<ul class="sectlevel3">
<li><a href="#_api_and_usage">4.6.1. API and Usage</a></li>
<li><a href="#_implementation_14">4.6.2. Implementation</a></li>
<li><a href="#_registering_the_service_7">4.6.3. Registering the Service</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_SessionManagementService">4.7. <code>SessionManagementService</code></a>
<ul class="sectlevel3">
<li><a href="#_api">4.7.1. API</a></li>
<li><a href="#_implementation_15">4.7.2. Implementation</a></li>
<li><a href="#_registering_the_service_8">4.7.3. Registering the Service</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_TitleService">4.8. <code>TitleService</code></a>
<ul class="sectlevel3">
<li><a href="#_api_2">4.8.1. API</a></li>
<li><a href="#_usage_5">4.8.2. Usage</a></li>
<li><a href="#_implementation_16">4.8.3. Implementation</a></li>
<li><a href="#_registering_the_service_9">4.8.4. Registering the Service</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_TransactionService">4.9. <code>TransactionService</code></a>
<ul class="sectlevel3">
<li><a href="#_api_3">4.9.1. API</a></li>
<li><a href="#_implementation_17">4.9.2. Implementation</a></li>
<li><a href="#_registering_the_service_10">4.9.3. Registering the Service</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_WrapperFactory">4.10. <code>WrapperFactory</code></a>
<ul class="sectlevel3">
<li><a href="#_api_4">4.10.1. API</a></li>
<li><a href="#_usage_6">4.10.2. Usage</a></li>
<li><a href="#_listener_api">4.10.3. Listener API</a></li>
<li><a href="#_registering_the_service_11">4.10.4. Registering the Service</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#_rgsvc_application-layer-spi">5. Application Layer SPI</a>
<ul class="sectlevel2">
<li><a href="#_rgsvc_spi_BackgroundCommandService">5.1. <code>BackgroundCommandService</code></a>
<ul class="sectlevel3">
<li><a href="#_spi_15">5.1.1. SPI</a></li>
<li><a href="#__internal_spi">5.1.2. "Internal" SPI</a></li>
<li><a href="#_implementation_18">5.1.3. Implementation</a></li>
<li><a href="#_usage_7">5.1.4. Usage</a></li>
<li><a href="#_registering_the_services_11">5.1.5. Registering the Services</a></li>
<li><a href="#_related_services_13">5.1.6. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_spi_CommandService">5.2. <code>CommandService</code></a>
<ul class="sectlevel3">
<li><a href="#_screencast">5.2.1. Screencast</a></li>
<li><a href="#_spi_16">5.2.2. SPI</a></li>
<li><a href="#_implementation_19">5.2.3. Implementation</a></li>
<li><a href="#_usage_8">5.2.4. Usage</a></li>
<li><a href="#_registering_the_services_12">5.2.5. Registering the Services</a></li>
<li><a href="#_related_services_14">5.2.6. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_HomePageProviderService">5.3. <code>HomePageProviderService</code></a>
<ul class="sectlevel3">
<li><a href="#_api_implementation_6">5.3.1. API & Implementation</a></li>
<li><a href="#_registering_the_service_12">5.3.2. Registering the Service</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#_rgsvc_core-domain-api">6. Core/Domain API</a>
<ul class="sectlevel2">
<li><a href="#_rgsvc_api_ClockService">6.1. <code>ClockService</code></a>
<ul class="sectlevel3">
<li><a href="#_api_implementation_7">6.1.1. API & Implementation</a></li>
<li><a href="#_testing_support">6.1.2. Testing Support</a>
<ul class="sectlevel4">
<li><a href="#_alternative_implementations_2">Alternative Implementations</a></li>
</ul>
</li>
<li><a href="#_registering_the_service_13">6.1.3. Registering the Service</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_ConfigurationService">6.2. <code>ConfigurationService</code></a>
<ul class="sectlevel3">
<li><a href="#_api_and_usage_2">6.2.1. API and Usage</a></li>
<li><a href="#_implementation_20">6.2.2. Implementation</a></li>
<li><a href="#_registering_the_service_14">6.2.3. Registering the Service</a></li>
<li><a href="#_related_services_15">6.2.4. Related services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_DomainObjectContainer">6.3. <code>DomainObjectContainer</code></a>
<ul class="sectlevel3">
<li><a href="#_apis">6.3.1. APIs</a>
<ul class="sectlevel4">
<li><a href="#_rgsvc_api_DomainObjectContainer_object-creation-api">Object Creation API</a></li>
<li><a href="#_rgsvc_api_DomainObjectContainer_generic-repository-api">Generic Repository API</a></li>
<li><a href="#_rgsvc_api_DomainObjectContainer_object-persistence-api">Object Persistence API</a></li>
<li><a href="#_rgsvc_api_DomainObjectContainer_messages-api">Messages API</a></li>
<li><a href="#_rgsvc_api_DomainObjectContainer_security-api">Security API</a></li>
<li><a href="#_rgsvc_api_DomainObjectContainer_presentation-api">Presentation API</a></li>
<li><a href="#_rgsvc_api_DomainObjectContainer_properties-api">Properties API</a></li>
<li><a href="#_rgsvc_api_DomainObjectContainer_services-api">Services API</a></li>
<li><a href="#_rgsvc_api_DomainObjectContainer_validation-api">Validation API</a></li>
</ul>
</li>
<li><a href="#_implementation_21">6.3.2. Implementation</a></li>
<li><a href="#_registering_the_service_15">6.3.3. Registering the Service</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_EventBusService">6.4. <code>EventBusService</code></a>
<ul class="sectlevel3">
<li><a href="#_rgsvc_api_EventBusService_api-and-implementation">6.4.1. API & Implementation</a></li>
<li><a href="#_registering_subscribers">6.4.2. Registering Subscribers</a></li>
<li><a href="#_annotating_members">6.4.3. Annotating Members</a></li>
<li><a href="#_rgsvc_api_EventBusService_event-hierarchy">6.4.4. Event hierarchy</a>
<ul class="sectlevel4">
<li><a href="#_variation_for_contributing_services">Variation (for contributing services)</a></li>
</ul>
</li>
<li><a href="#_programmatic_posting">6.4.5. Programmatic posting</a></li>
<li><a href="#_using_code_wrapperfactory_code">6.4.6. Using <code>WrapperFactory</code></a></li>
<li><a href="#_implementation_spi">6.4.7. Implementation SPI</a></li>
<li><a href="#_rgsvc_api_EventBusService_Configuration">6.4.8. Configuration</a></li>
<li><a href="#_registering_the_services_13">6.4.9. Registering the Services</a></li>
<li><a href="#_related_services_16">6.4.10. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_FactoryService">6.5. <code>FactoryService</code></a>
<ul class="sectlevel3">
<li><a href="#_api_5">6.5.1. API</a></li>
<li><a href="#_usage_9">6.5.2. Usage</a></li>
<li><a href="#_implementation_22">6.5.3. Implementation</a></li>
<li><a href="#_registering_the_service_16">6.5.4. Registering the Service</a></li>
<li><a href="#_related_services_17">6.5.5. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_Scratchpad">6.6. <code>Scratchpad</code></a>
<ul class="sectlevel3">
<li><a href="#_api_implementation_8">6.6.1. API & Implementation</a></li>
<li><a href="#_usage_10">6.6.2. Usage</a></li>
<li><a href="#_registering_the_service_17">6.6.3. Registering the Service</a></li>
<li><a href="#_related_services_18">6.6.4. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_UserService">6.7. <code>UserService</code></a>
<ul class="sectlevel3">
<li><a href="#_api_and_usage_3">6.7.1. API and Usage</a></li>
<li><a href="#_implementation_23">6.7.2. Implementation</a></li>
<li><a href="#_registering_the_service_18">6.7.3. Registering the Service</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#_rgsvc_integration-api">7. Integration API</a>
<ul class="sectlevel2">
<li><a href="#_rgsvc_api_BookmarkService">7.1. <code>BookmarkService2</code></a>
<ul class="sectlevel3">
<li><a href="#_api_implementation_9">7.1.1. API & Implementation</a></li>
<li><a href="#__code_bookmarkholder_code">7.1.2. <code>BookmarkHolder</code></a></li>
<li><a href="#_usage_by_other_services">7.1.3. Usage by other services</a></li>
<li><a href="#_registering_the_service_19">7.1.4. Registering the Service</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_DeepLinkService">7.2. <code>DeepLinkService</code></a>
<ul class="sectlevel3">
<li><a href="#_api_implementation_10">7.2.1. API & Implementation</a></li>
<li><a href="#_usage_within_the_framework">7.2.2. Usage within the framework</a></li>
<li><a href="#_implementations_2">7.2.3. Implementations</a></li>
<li><a href="#_registering_the_services_14">7.2.4. Registering the Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_EmailService">7.3. <code>EmailService</code></a>
<ul class="sectlevel3">
<li><a href="#_api_implementation_11">7.3.1. API & Implementation</a></li>
<li><a href="#_configuration">7.3.2. Configuration</a></li>
<li><a href="#_alternative_implementations_3">7.3.3. Alternative Implementations</a></li>
<li><a href="#_registering_the_services_15">7.3.4. Registering the Services</a></li>
<li><a href="#_related_services_19">7.3.5. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_GuiceBeanProvider">7.4. <code>GuiceBeanProvider</code></a>
<ul class="sectlevel3">
<li><a href="#_api_implementation_12">7.4.1. API & Implementation</a></li>
<li><a href="#_usage_11">7.4.2. Usage</a></li>
<li><a href="#_registering_the_services_16">7.4.3. Registering the Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_JaxbService">7.5. <code>JaxbService</code></a>
<ul class="sectlevel3">
<li><a href="#_rgsvc_api_JaxbService_api-and-implementation">7.5.1. API & Implementation</a></li>
<li><a href="#_usage_within_the_framework_2">7.5.2. Usage within the framework</a></li>
<li><a href="#_registering_the_service_20">7.5.3. Registering the Service</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_MementoService">7.6. <code>MementoService</code></a>
<ul class="sectlevel3">
<li><a href="#_api_implementation_13">7.6.1. API & Implementation</a></li>
<li><a href="#_usage_12">7.6.2. Usage</a></li>
<li><a href="#_related_services_20">7.6.3. Related Services</a></li>
<li><a href="#_registering_the_service_21">7.6.4. Registering the Service</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_XmlSnapshotService">7.7. <code>XmlSnapshotService</code></a>
<ul class="sectlevel3">
<li><a href="#_standard_api">7.7.1. Standard API</a></li>
<li><a href="#_builder_api">7.7.2. Builder API</a></li>
<li><a href="#_automatic_inclusions">7.7.3. Automatic inclusions</a></li>
<li><a href="#_convenience_api">7.7.4. Convenience API</a></li>
<li><a href="#_registering_the_service_22">7.7.5. Registering the Service</a></li>
<li><a href="#_related_services_21">7.7.6. Related Services</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#_rgsvc_metadata-api">8. Metadata API</a>
<ul class="sectlevel2">
<li><a href="#_rgsvc_api_ApplicationFeatureRepository">8.1. <code>ApplicationFeatureRepository</code></a>
<ul class="sectlevel3">
<li><a href="#_api_implementation_14">8.1.1. API & Implementation</a></li>
<li><a href="#_registering_the_service_23">8.1.2. Registering the Service</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_LayoutService">8.2. <code>LayoutService</code></a>
<ul class="sectlevel3">
<li><a href="#_rgsvc_api_LayoutService_api-and-implementation">8.2.1. API & Implementation</a></li>
<li><a href="#_rgsvc_api_LayoutService_related-mixins-and-menus">8.2.2. Related Mixins and Menus</a></li>
<li><a href="#_rgsvc_api_LayoutService_related-domain-services">8.2.3. Related Domain Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_MetaModelService">8.3. <code>MetaModelService</code></a>
<ul class="sectlevel3">
<li><a href="#_api_6">8.3.1. API</a></li>
<li><a href="#_implementation_24">8.3.2. Implementation</a></li>
<li><a href="#_registering_the_service_24">8.3.3. Registering the Service</a></li>
<li><a href="#_related_services_22">8.3.4. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_ServiceRegistry">8.4. <code>ServiceRegistry2</code></a>
<ul class="sectlevel3">
<li><a href="#_api_7">8.4.1. API</a></li>
<li><a href="#_usage_13">8.4.2. Usage</a></li>
<li><a href="#_implementation_25">8.4.3. Implementation</a></li>
<li><a href="#_registering_the_service_25">8.4.4. Registering the Service</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_SwaggerService">8.5. <code>SwaggerService</code></a>
<ul class="sectlevel3">
<li><a href="#_rgsvc_api_SwaggerService_api-and-implementation">8.5.1. API & Implementation</a></li>
<li><a href="#_usage_within_the_framework_3">8.5.2. Usage within the framework</a></li>
<li><a href="#_registering_the_service_26">8.5.3. Registering the Service</a></li>
<li><a href="#_related_services_23">8.5.4. Related Services</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#_rgsvc_testing">9. Testing</a>
<ul class="sectlevel2">
<li><a href="#_rgsvc_api_FixtureScriptsDefault">9.1. <code>FixtureScriptsDefault</code></a>
<ul class="sectlevel3">
<li><a href="#_api_implementation_15">9.1.1. API & Implementation</a></li>
<li><a href="#_configuration_2">9.1.2. Configuration</a></li>
<li><a href="#_related_services_24">9.1.3. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_SudoService">9.2. <code>SudoService</code></a>
<ul class="sectlevel3">
<li><a href="#_api_implementation_16">9.2.1. API & Implementation</a></li>
<li><a href="#_usage_14">9.2.2. Usage</a></li>
<li><a href="#_registering_the_service_27">9.2.3. Registering the Service</a></li>
</ul>
</li>
<li><a href="#_rgsvc_spi_FixtureScriptsSpecificationProvider">9.3. <code>FixtureScriptsSpec’nProvider</code></a>
<ul class="sectlevel3">
<li><a href="#_spi_17">9.3.1. SPI</a></li>
<li><a href="#_implementation_26">9.3.2. Implementation</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#_rgsvc_persistence-layer-api">10. Persistence Layer API</a>
<ul class="sectlevel2">
<li><a href="#_rgsvc_api_IsisJdoSupport">10.1. <code>IsisJdoSupport</code></a>
<ul class="sectlevel3">
<li><a href="#_rgsvc_api_IsisJdoSupport_executing-sql">10.1.1. Executing SQL</a></li>
<li><a href="#_rgsvc_api_IsisJdoSupport_type-safe-jdoql-queries">10.1.2. Type-safe JDOQL Queries</a></li>
<li><a href="#_rgsvc_api_IsisJdoSupport_fixture-support">10.1.3. Fixture support</a></li>
<li><a href="#_rgsvc_api_IsisJdoSupport_reloading-entities">10.1.4. Reloading entities</a></li>
<li><a href="#_rgsvc_api_IsisJdoSupport_jdo-persistencemanager">10.1.5. JDO <code>PersistenceManager</code></a></li>
<li><a href="#_registering_the_services_17">10.1.6. Registering the Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_MetricsService">10.2. <code>MetricsService</code> (<code>1.13.0-SNAPSHOT</code>)</a>
<ul class="sectlevel3">
<li><a href="#_api_implementation_17">10.2.1. API & Implementation</a></li>
<li><a href="#_registering_the_service_28">10.2.2. Registering the Service</a></li>
<li><a href="#_related_services_25">10.2.3. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_QueryResultsCache">10.3. <code>QueryResultsCache</code></a>
<ul class="sectlevel3">
<li><a href="#_api_implementation_18">10.3.1. API & Implementation</a></li>
<li><a href="#_usage_15">10.3.2. Usage</a></li>
<li><a href="#_registering_the_service_29">10.3.3. Registering the Service</a></li>
<li><a href="#_related_services_26">10.3.4. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_api_RepositoryService">10.4. <code>RepositoryService</code></a>
<ul class="sectlevel3">
<li><a href="#_api_8">10.4.1. API</a></li>
<li><a href="#_usage_16">10.4.2. Usage</a>
<ul class="sectlevel4">
<li><a href="#_persist">Persist</a></li>
<li><a href="#__code_persistandflush_code_code_removeandflush_code"><code>persistAndFlush(…​)</code>, <code>removeAndFlush(…​)</code></a></li>
<li><a href="#_query_and_code_xxxmatches_code">Query and <code>xxxMatches(…​)</code></a></li>
</ul>
</li>
<li><a href="#_implementation_27">10.4.3. Implementation</a>
<ul class="sectlevel4">
<li><a href="#__disabling_auto_flush">(Disabling) Auto-flush</a></li>
</ul>
</li>
<li><a href="#_registering_the_service_30">10.4.4. Registering the Service</a></li>
<li><a href="#_related_services_27">10.4.5. Related Services</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#_rgsvc_persistence-layer-spi">11. Persistence Layer SPI</a>
<ul class="sectlevel2">
<li><a href="#_rgsvc_spi_AuditerService">11.1. <code>AuditerService</code> (<code>1.13.0-SNAPSHOT</code>)</a>
<ul class="sectlevel3">
<li><a href="#_spi_18">11.1.1. SPI</a></li>
<li><a href="#_implementation_28">11.1.2. Implementation</a></li>
<li><a href="#_usage_17">11.1.3. Usage</a></li>
<li><a href="#_registering_the_services_18">11.1.4. Registering the Services</a></li>
<li><a href="#_related_services_28">11.1.5. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_spi_AuditingService">11.2. <code>AuditingService3</code></a>
<ul class="sectlevel3">
<li><a href="#_spi_19">11.2.1. SPI</a></li>
<li><a href="#_implementation_29">11.2.2. Implementation</a></li>
<li><a href="#_usage_18">11.2.3. Usage</a></li>
<li><a href="#_registering_the_services_19">11.2.4. Registering the Services</a></li>
<li><a href="#_related_services_29">11.2.5. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_spi_EventSerializer">11.3. <code>EventSerializer</code></a>
<ul class="sectlevel3">
<li><a href="#_spi_20">11.3.1. SPI</a></li>
<li><a href="#_implementation_30">11.3.2. Implementation</a></li>
<li><a href="#_registering_the_services_20">11.3.3. Registering the Services</a></li>
<li><a href="#_related_services_30">11.3.4. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_spi_PublisherService">11.4. <code>PublisherService</code> (<code>1.13.0-SNAPSHOT</code>)</a>
<ul class="sectlevel3">
<li><a href="#_spi_21">11.4.1. SPI</a></li>
<li><a href="#_implementation_31">11.4.2. Implementation</a></li>
<li><a href="#_usage_19">11.4.3. Usage</a></li>
<li><a href="#_registering_the_services_21">11.4.4. Registering the Services</a></li>
<li><a href="#_related_services_31">11.4.5. Related Services</a></li>
</ul>
</li>
<li><a href="#_rgsvc_spi_PublishingService">11.5. <code>PublishingService</code></a>
<ul class="sectlevel3">
<li><a href="#_spi_22">11.5.1. SPI</a></li>
<li><a href="#_implementation_32">11.5.2. Implementation</a></li>
<li><a href="#_usage_20">11.5.3. Usage</a></li>
<li><a href="#_registering_the_services_22">11.5.4. Registering the Services</a></li>
<li><a href="#_related_services_32">11.5.5. Related Services</a></li>
<li><a href="#_design_notes">11.5.6. Design Notes</a></li>
</ul>
</li>
<li><a href="#_rgsvc_spi_UserRegistrationService">11.6. <code>UserRegistrationService</code></a>
<ul class="sectlevel3">
<li><a href="#_spi_23">11.6.1. SPI</a></li>
<li><a href="#_implementation_33">11.6.2. Implementation</a></li>
<li><a href="#_registering_the_services_23">11.6.3. Registering the Services</a></li>
<li><a href="#_related_services_33">11.6.4. Related Services</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#_rgsvc_bootstrapping-spi">12. Bootstrapping SPI</a>
<ul class="sectlevel2">
<li><a href="#_rgsvc_spi_ClassDiscoveryService">12.1. <code>ClassDiscoveryService</code></a>
<ul class="sectlevel3">
<li><a href="#_spi_24">12.1.1. SPI</a></li>
<li><a href="#_implementation_34">12.1.2. Implementation</a></li>
<li><a href="#_usage_21">12.1.3. Usage</a></li>
<li><a href="#_registering_the_services_24">12.1.4. Registering the Services</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
</div>
<script src="../js/foundation/5.5.1/vendor/jquery.js"></script>
<script src="../js/foundation/5.5.1/foundation.min.js"></script>
<link href="../css/jquery.tocify/1.9.0/jquery.tocify.css" rel="stylesheet">
<script src="../js/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script src="../js/jquery.tocify/1.9.0/jquery.tocify.js"></script>
<script type="text/javascript">
$(function () {
$("#toc").tocify({
scrollTo: 50,
extendPage: true,
context: "#doc-content",
highlightOnScroll: true,
hashGenerator: "pretty",
hideEffect: "slideUp",
selectors: "h2,h3,h4,h5"
});
$(".fallback-toc").hide();
});
</script>
<script type="text/javascript">
/****
$(document).foundation();
$(document).ready(function(){
// Cache selectors
var lastId,
topMenu = $("div#toc ul"),
topMenuHeight = 100,
menuItems = topMenu.find("a"),
menuItemsHrefs = menuItems.map(function(){
var item = $($(this).attr("href"));
if (item.length) { return item; }
});
// Bind click handler to menu items to scroll animation
menuItems.click(function(e){
var href = $(this).attr("href"),
offsetTop = href === "#" ? 0 : $(href).offset().top-topMenuHeight+1;
$('html, body').stop().animate({
scrollTop: offsetTop
}, 300);
e.preventDefault();
});
// Bind to scroll of window
$( window ).scroll(function(){
// Get container scroll position
var fromTop = $(this).scrollTop()+topMenuHeight;
var cur = menuItemsHrefs.map(function(){
if ($(this).offset().top < fromTop)
return this;
});
// Get the id of the current element
cur = cur[cur.length-1];
var id = cur && cur.length ? cur[0].id : "";
if (lastId !== id && id) {
scrollTo(id);
}
window.history.pushState({}, "", window.location.origin + window.location.pathname + "#" + id);
});
scrollTo = function(id) {
lastId = id;
menuItems
.removeClass("active");
menuItems
.parents()
.removeClass("active-region");
menuItems
.parents("ul").hide();
menuItems
.filter("[href=#"+id+"]")
.addClass("active");
menuItems
.filter("[href=#"+id+"]")
.parents("ul").show();
menuItems
.filter("[href=#"+id+"]")
.parent().children("ul").show();
menuItems
.filter("[href=#"+id+"]")
.parents("li").addClass("active-region");
}
menuItems
.removeClass("active");
menuItems
.parents()
.removeClass("active-region");
var syncMenuItem;
if(window.location.hash!=="") {
var menuItemFor = $.grep(menuItems, function(e) {
return e.hash === window.location.hash;
});
console.log(menuItemFor);
if(menuItemFor.length === 1) {
syncMenuItem = menuItemFor[0];
}
}
if(!syncMenuItem){
syncMenuItem = menuItems[0];
}
$(syncMenuItem).click();
});
***/
</script>
<script type="text/javascript">
$(document).ready(function(){
if("Documentation" === "Domain Services") {
console.log( "processing 'Documentation'" );
$("#doc-content-left").removeClass("large-9").removeClass("medium-9").addClass("large-12").addClass("medium-12");
$("#doc-content-right").removeClass("large-3").removeClass("medium-3").hide();
}
});
</script>
<script>
$( document ).ready(function() {
(function() {
$(function() {
return $("#doc-content h2, #doc-content h3, #doc-content h4, #doc-content h5, #doc-content h6").each(function(i, el) {
var $el, icon, id;
$el = $(el);
id = $el.attr('id');
icon = '<i class="fa fa-link"></i>';
if (id) {
return $el.prepend($("<a />").addClass("header-link").attr("href", "#" + id).html(icon));
}
});
});
}).call(this);
/*
http://osvaldas.info/auto-hide-sticky-header
MIT license
*/
;( function( $, window, document, undefined )
{
'use strict';
var elSelector = '.header',
elClassHidden = 'header--hidden',
throttleTimeout = 500,
$element = $( elSelector );
if( !$element.length ) return true;
var $window = $( window ),
wHeight = 0,
wScrollCurrent = 0,
wScrollBefore = 0,
wScrollDiff = 0,
$document = $( document ),
dHeight = 0,
throttle = function( delay, fn )
{
var last, deferTimer;
return function()
{
var context = this, args = arguments, now = +new Date;
if( last && now < last + delay )
{
clearTimeout( deferTimer );
deferTimer = setTimeout( function(){ last = now; fn.apply( context, args ); }, delay );
}
else
{
last = now;
fn.apply( context, args );
}
};
};
$window.on( 'scroll', throttle( throttleTimeout, function()
{
dHeight = $document.height();
wHeight = $window.height();
wScrollCurrent = $window.scrollTop();
wScrollDiff = wScrollBefore - wScrollCurrent;
if( wScrollCurrent <= 0 ) // scrolled to the very top; element sticks to the top
$element.removeClass( elClassHidden );
else if( wScrollDiff > 0 && $element.hasClass( elClassHidden ) ) // scrolled up; element slides in
$element.removeClass( elClassHidden );
else if( wScrollDiff < 0 ) // scrolled down
{
if( wScrollCurrent + wHeight >= dHeight && $element.hasClass( elClassHidden ) ) // scrolled to the very bottom; element slides in
$element.removeClass( elClassHidden );
else // scrolled down; element slides out
$element.addClass( elClassHidden );
}
wScrollBefore = wScrollCurrent;
}));
})( jQuery, window, document );
});
</script>
</body>
</html>