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>&nbsp;&raquo&nbsp;<a href="./../../reference/about.html">Reference</a>&nbsp;&raquo&nbsp;<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>