You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by bu...@apache.org on 2015/03/23 22:07:34 UTC
svn commit: r944795 - in /websites/staging/isis/trunk: cgi-bin/ content/
content/reference/recognized-annotations/Action.html
Author: buildbot
Date: Mon Mar 23 21:07:34 2015
New Revision: 944795
Log:
Staging update by buildbot for isis
Modified:
websites/staging/isis/trunk/cgi-bin/ (props changed)
websites/staging/isis/trunk/content/ (props changed)
websites/staging/isis/trunk/content/reference/recognized-annotations/Action.html
Propchange: websites/staging/isis/trunk/cgi-bin/
------------------------------------------------------------------------------
--- cms:source-revision (original)
+++ cms:source-revision Mon Mar 23 21:07:34 2015
@@ -1 +1 @@
-1666423
+1668735
Propchange: websites/staging/isis/trunk/content/
------------------------------------------------------------------------------
--- cms:source-revision (original)
+++ cms:source-revision Mon Mar 23 21:07:34 2015
@@ -1 +1 @@
-1666423
+1668735
Modified: websites/staging/isis/trunk/content/reference/recognized-annotations/Action.html
==============================================================================
--- websites/staging/isis/trunk/content/reference/recognized-annotations/Action.html (original)
+++ websites/staging/isis/trunk/content/reference/recognized-annotations/Action.html Mon Mar 23 21:07:34 2015
@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
- <title>@Action (1.8.0)
</title>
+ <title>@Action
</title>
<meta name="description" content="">
<meta name="author" content="">
@@ -482,7 +482,7 @@
};
function twshare () {
window.open(
- "https://twitter.com/intent/tweet?url="+document.URL+"&text=@Action (1.8.0)
",
+ "https://twitter.com/intent/tweet?url="+document.URL+"&text=@Action
",
'Share on Twitter',
'width=800,height=526');
};
@@ -602,20 +602,404 @@
<div class="page-header">
<p><a href="./../../documentation.html">Docs</a> » <a href="./../../reference/about.html">Reference</a> » <a href="./../../reference/recognized-annotations/about.html">Recognized Annotations</a></p>
-<h1>@Action (1.8.0)
+<h1>@Action
</h1>
</div>
-<blockquote>
- <p>stub</p>
-</blockquote>
+<p>The <code>Action</code> annotation groups together all domain-specific metadata for an invokable action on a domain object or domain service:</p>
-<p>The <code>@Action</code> annotation applies to actions collecting together all domain semantics within a single annotation.</p>
+<ul>
+<li><code>domainEvent</code> - specifies the subtype of the <code>ActionDomainEvent</code> that should be posted to the <a href="../services/event-bus-service.htm">Event Bus service</a> to broadcast the action's business rule checking (hide, disable, validate) and its invocation (pre-execute and post-execution).</li>
+<li><code>hidden</code> - indicates where (in the UI) the action is not visible to the user.</li>
+<li><code>semantics</code> - the action's semantics, either safe (query-only), idempotent or non-idempotent.</li>
+<li><code>invokeOn</code> - whether an action can be invoked on a single object and/or on many objects in a collection.</li>
+<li><code>command</code> - whether the action invocation should be reified into a <code>org.apache.isis.applib.services.command.Command</code> object.</li>
+<li><code>commandPersistence</code> - how the reified <code>Command</code> (as provided by the <code>CommandContext</code> domain service) should be persisted.</li>
+<li><code>commandExecuteIn</code> - how the command/action should be executed: foreground or background.</li>
+<li><code>publishing</code> - whether changes to the object should be published to the registered <a href="../publishing-service.html">publishing service</a>.</li>
+<li><code>publishingPayloadFactory</code> - specifies that a custom implementation of <code>PublishingPayloadFactoryForAction</code> be used to create the (payload of the) published event</li>
+<li><code>typeOf</code> - if the action returns a collection, specifies the type of the objects within that collection</li>
+<li><code>restrictTo</code> - whether the action is restricted to prototyping</li>
+</ul>
-<h2>Source code</h2>
+<h2>Domain events</h2>
-<p>See <a href="https://issues.apache.org/jira/browse/ISIS-970">ISIS-970</a> and <a href="https://github.com/apache/isis/blob/master/core/applib/src/main/java/org/apache/isis/applib/annotation/Action.java">@Action</a> source code.</p>
+<p>Every interaction with a domain object action causes multiple events to be fired, in the following phases:</p>
+
+<ul>
+<li>Hide phase: to check that the action is visible (has not been hidden)</li>
+<li>Disable phase: to check that the action is usable (has not been disabled)</li>
+<li>Validate phase: to check that the action's arguments are valid</li>
+<li>Pre-execute phase: before the invocation of the action</li>
+<li>Post-execute: after the invocation of the action</li>
+</ul>
+
+<p>Subscribers subscribe through the <a href="../services/event-bus-service.html">Event Bus Service</a>
+using Guava annotations and can influence each of these phases.</p>
+
+<p>By default the event raised is <code>ActionDomainEvent.Default</code>. For example:</p>
+
+<pre><code>public class ToDoItem {
+ ...
+ @Action()
+ public ToDoItem completed() { ... }
+}
+</code></pre>
+
+<p>Optionally a subclass can be declared:</p>
+
+<pre><code>public class ToDoItem {
+
+ public static class CompletedEvent extends AbstractActionDomainEvent {
+ private static final long serialVersionUID = 1L;
+ public CompletedEvent(
+ final ToDoItem source,
+ final Identifier identifier,
+ final Object... arguments) {
+ super("completed", source, identifier, arguments);
+ }
+ }
+
+ @Action(domainEvent=CompletedEvent.class)
+ public ToDoItem completed() { ... }
+
+}
+</code></pre>
+
+<h4>Subscribers</h4>
+
+<p>Subscribers (which must be domain services) subscribe using the Guava API.
+Subscribers can be either coarse-grained (if they subscribe to the top-level event type):</p>
+
+<pre><code>@DomainService
+public class SomeSubscriber {
+
+ @Programmatic
+ @com.google.common.eventbus.Subscribe
+ public void on(ActionInteractionEvent ev) {
+
+ ...
+ }
+
+}
+</code></pre>
+
+<p>or can be fine-grained by subscribing to specific event subtypes:</p>
+
+<pre><code>@DomainService
+public class SomeSubscriber {
+
+ @Programmatic
+ @com.google.common.eventbus.Subscribe
+ public void on(ToDoItem.CompletedEvent ev) {
+
+ ...
+ }
+
+}
+</code></pre>
+
+<p>The subscriber's method is called (up to) 5 times:</p>
+
+<ul>
+<li>whether to veto visibility (hide)</li>
+<li>whether to veto usability (disable)</li>
+<li>whether to veto execution (validate)</li>
+<li>steps to perform prior to the action being invoked.</li>
+<li>steps to perform after the action has been invoked.</li>
+</ul>
+
+<p>The subscriber can distinguish these by calling <code>ev.getEventPhase()</code>. Thus the general form is:</p>
+
+<pre><code>@Programmatic
+@com.google.common.eventbus.Subscribe
+public void on(ActionInteractionEvent ev) {
+
+ switch(ev.getPhase()) {
+ case HIDE:
+ ...
+ break;
+ case DISABLE:
+ ...
+ break;
+ case VALIDATE:
+ ...
+ break;
+ case EXECUTING:
+ ...
+ break;
+ case EXECUTED:
+ ...
+ break;
+ }
+}
+</code></pre>
+
+<p>Vetoing is performed by calling the appropriate method on the event:</p>
+
+<ul>
+<li>To hide:</p>
+
+<p><code>ev.hide()</code></p>
+
+<p>or</p>
+
+<p><code>ev.veto("")</code></li>
+<li>To disable:</p>
+
+<p><code>ev.disable("...");</code></p>
+
+<p>or</p>
+
+<p><code>ev.veto("...");</code></li>
+<li>To invalidate:</p>
+
+<p><code>ev.invalidate("...");</code></p>
+
+<p>or</p>
+
+<p><code>ev.veto("...");</code></li>
+</ul>
+
+<p>It is also possible to abort the transaction during the executing or executed
+phases by throwing an exception. If the exception is a subtype of <code>RecoverableException</code>
+then the exception will be rendered as a user-friendly warning (eg Growl/toast)
+rather than an error.</p>
+
+<h4>Raising events programmatically.</h4>
+
+<p>Normally events are only raised for interactions through the UI. However, events can be raised programmatically by
+wrapping the target object using the <a href="../services/wrapper-factory.html">Wrapper Factory</a> service.</p>
+
+<h4>See also</h4>
+
+<p>Domain events can also be raised for <a href="./Property.html">properties</a> and <a href="./Collection.html">collections</a>.</p>
+
+<h2>Hidden</h2>
+
+<p>Actions can be hidden at the domain-level, indicating that they are not visible to the end-user. For example:</p>
+
+<pre><code>public class Customer {
+
+ @Action(hidden=EVERYWHERE)
+ public void updateStatus() { ... }
+ ...
+}
+</code></pre>
+
+<p>The only value that currently makes sense is <code>EVERYWHERE</code> (or its synonym <code>ANYWHERE</code>).</p>
+
+<h4>See also</h4>
+
+<p>It is also possible to use <code>@ActionLayout</code> or <a href="../../components/viewers/wicket/dynamic-layouts.html">dynamic layouts</a>
+such that the action can be hidden at the view layer. Both options are provided with a view that in the future the
+view-layer semantics may be under the control of (expert) users, whereas domain-layer semantics cannot be overridden
+or modified by the user.</p>
+
+<p>For <code>DomainService</code> actions, the action's visibility is dependent upon its <code>DomainService#nature()</code> and for contributed
+actions on how it is <code>ActionLayout#contributed()</code>.</p>
+
+<h2>Semantics</h2>
+
+<p>This annotation, which applies only to actions, describes whether the
+invocation is safe (as no side-effects), is idempotent (may have
+side-effects but always has the same postconditions), or is neither safe
+nor idempotent. If the annotation is missing then the framework assumes
+non-idempotent.</p>
+
+<p>For example:</p>
+
+<pre><code>public class Customer {
+ @Action(semantics=SemanticsOf.SAFE)
+ public CreditRating checkCredit() { ... }
+
+ @Action(semantics=SemanticsOf.IDEMPOTENT)
+ public void changeOfAddress(Address address) { ... }
+
+ @Action(semantics=SemanticsOf.NON_IDEMPOTENT)
+ public Order placeNewOrder() { ... }
+ ...
+}
+</code></pre>
+
+<p>The annotation was introduced for the restfulobjects viewer in order
+that action invocations could be made available using either HTTP GET,
+PUT or POST (respectively). It is now also used in core runtime's
+in-built concurrency checking; the invocation of a safe action does not
+perform a concurrency check, whereas non-safe actions do perform a
+concurrency check.</p>
+
+<h2>Invoke On</h2>
+
+<p>Indicates whether the an action can be invoked on a single object (the default) and/or on many objects in a collection.</p>
+
+<p>Actions to be invoked on collection (currently) have a number of constraints:</p>
+
+<ul>
+<li>It must take no arguments</li>
+<li>It cannot be hidden (any annotations or supporting methods to that effect will be ignored
+*It cannot be disabled (any annotations or supporting methods to that effect will be ignored).</li>
+</ul>
+
+<p>This attribute has no meaning if annotated on an action of a domain service.</p>
+
+<h2>Command</h2>
+
+<p>Using <code>@Action(command=...)</code> allows an action invocation to be made into a concrete object such that it can be
+inspected and persisted, for various purposes. These include enhanced profiling/auditing, as well as being able to
+defer the execution of the action and have it be invoked in the background.</p>
+
+<p>The annotation works (and influences the behaviour of) the <code>CommandContext</code>, <code>CommandService</code>, <code>BackgroundService</code> and
+<code>BackgroundCommandService</code> domain services (documented <a href="../../../reference/services/command-context.html">here</a> and
+<a href="../../../reference/services/background-service.html">here</a>).</p>
+
+<p>By default, actions are invoked in directly in the thread of the invocation.</p>
+
+<p>If the <code>CommandContext</code> service is configured, then this action invocation is reified into a <code>Command</code> object,
+capturing details of the target object, the action, the parameter arguments, the user, a timestamp and so on.</p>
+
+<p>If an appropriate <code>CommandService</code> service is configured (for example the
+<a href="../../../components/objectstores/jdo/services/command-service-jdo.html">CommandServiceJdo</a> JDO implementation), then
+the <code>Command</code> itself is persisted.</p>
+
+<p>If the <code>BackgroundService</code> is configured, then commands can be invoked by means of a separate background process. If an appropriate <code>BackgroundCommandService</code> service is configured (for example, the <a href="../../../components/objectstores/jdo/services/background-command-service-jdo.html">BackgroundCommandServiceJdo</a> JDO implementation), then the background command is persisted.</p>
+
+<p>The <code>@Action(command=...)</code> annotation can be annotated on action methods, to influence this behaviour:</p>
+
+<pre><code>public class Order {
+
+ @Action(
+ command=CommandReified.ENABLED,
+ commandExecuteIn=ExecuteIn.FOREGROUND,
+ persistence=Persistence.PERSISTED)
+ public Invoice generateInvoice(...) { ... }
+
+}
+</code></pre>
+
+<p>or alternatively just:</p>
+
+<pre><code>public class Order {
+
+ @Command
+ public Invoice generateInvoice(...) { ... }
+
+}
+</code></pre>
+
+<p>corresponds to the behaviour described above; the <code>Command</code> object is persisted (assuming an appropriate <code>CommandService</code> is defined, and executed immediately in the foreground).</p>
+
+<p>As a variation:</p>
+
+<pre><code>public class Order {
+
+ @Command(
+ executeIn=ExecuteIn.FOREGROUND,
+ persistence=Persistence.IF_HINTED)
+ public Invoice generateInvoice(...) { ... }
+
+}
+</code></pre>
+
+<p>will suppress the persistence of the <code>Command</code> object <em>unless</em> a child background <code>Command</code> has been created in the body of the action by way of the <code>BackgroundService</code>.</p>
+
+<p>Next:</p>
+
+<pre><code>public class Order {
+
+ @Command(
+ executeIn=ExecuteIn.FOREGROUND,
+ persistence=Persistence.NOT_PERSISTED)
+ public Invoice generateInvoice(...) { ... }
+
+}
+</code></pre>
+
+<p>will prevent the parent <code>Command</code> object from being persisted, <em>even if</em> a child background <code>Command</code> is created.</p>
+
+<p>Turning to the <code>executeIn</code> attribute:</p>
+
+<pre><code>public class Order {
+
+ @Command(
+ executeIn=ExecuteIn.BACKGROUND)
+ public Invoice generateInvoice(...) { ... }
+
+}
+</code></pre>
+
+<p>will result in the <code>Command</code> being persisted but its execution deferred to a background execution mechanism. The returned object from this action is the persisted <code>Command</code> itself.</p>
+
+<h4><code>command()</code></h4>
+
+<p>The <code>command()</code> attribute determines whether the action invocation should be reified into a <code>Command</code> object.</p>
+
+<p>The default is <code>AS_CONFIGURED</code>, meaning that the configuration property:</p>
+
+<pre><code>isis.services.command.actions
+</code></pre>
+
+<p>is used to determine the whether the action is reified:</p>
+
+<ul>
+<li><code>all</code> - all actions are reified</li>
+<li><code>ignoreSafe</code> (or <code>ignoreQueryOnly</code>) - actions with safe (read-only) semantics are ignored, but actions which may modify data are not ignored</li>
+<li><code>none</code> - no actions are reifired.</li>
+</ul>
+
+<p>This default can be overridden on an action-by-action basis; if <code>command()</code> is set to <code>ENABLED</code> then the action is reified irrespective of the configured value; if set to <code>DISABLED</code> then the action is NOT reified irrespective of the configured value.</p>
+
+<h4><code>commandPersistence()</code></h4>
+
+<p>If the action has been reified, then the <code>commandPersistence()</code> attribute determines whether that <code>Command</code> object
+should then also be persisted (the default) or not persisted.</p>
+
+<h4><code>commandExecuteIn()</code></h4>
+
+<p>For persisted commands, the <code>commandExecuteIn()</code> attribute determines whether the <code>Command</code> should be executed in the
+foreground (the default) or executed in the background.</p>
+
+<p>Background execution means that the command is not executed immediately, but is available for a configured
+<a href="../services/background-service.html">background service</a> to execute, eg by way of an in-memory scheduler such as Quartz.</p>
+
+<h2>Publishing</h2>
+
+<h4><code>publishing()</code></h4>
+
+<p>Indicates whether the action invocation should be published to the <a href="../publishing-service.html">publishing service</a>.</p>
+
+<p>The default is <code>AS_CONFIGURED</code>, meaning that the configuration property:</p>
+
+<pre><code>isis.services.publish.actions
+</code></pre>
+
+<p>is used to determine the whether the action is published:</p>
+
+<ul>
+<li><code>all</code> - all actions are published</li>
+<li><code>ignoreSafe</code> (or <code>ignoreQueryOnly</code>) - actions with safe (read-only) semantics are ignored, but actions which may modify data are not ignored</li>
+<li><code>none</code> - no actions are published</li>
+</ul>
+
+<p>This default can be overridden on an action-by-action basis; if <code>command()</code> is set to <code>ENABLED</code> then the action is reified irrespective of the configured value; if set to <code>DISABLED</code> then the action is NOT reified irrespective of the configured value.</p>
+
+<h4><code>publishingPayloadFactory()</code></h4>
+
+<p>The <code>publishingPayloadFactory()</code> specifies the class to use to create the (payload of the) event to be published by the publishing factory.
+Rather than simply broadcast that the action was invoked, the payload factory allows a "fatter" payload to be isntantiated
+that can eagerly push commonly-required information to all subscribers. For at least some subscribers this should avoid
+the necessity to query back for additional information.</p>
+
+<h2><code>typeOf()</code></h2>
+
+<p>Specifies the type-of the elements returned by the action.</p>
+
+<h2><code>restrictTo()</code></h2>
+
+<p>Whether the action is restricted to prototyping.</p>
+
+<p>By default there are no restrictions, with the action being available in all environments.</p>
<h2>See also</h2>