You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2014/01/31 16:34:07 UTC

[3/3] git commit: ISIS-671, ISIS-672: renames, also @Reified annotation

ISIS-671, ISIS-672: renames, also @Reified annotation

ISIS-671:
- @Reified annotation and facet

ISIS-672:
- renamed InteractionContext to ReifiableActionContext
- renamed InteractionService to ReifiableActionService
- corresponding renames for JDO impls.


Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/2463dc18
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/2463dc18
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/2463dc18

Branch: refs/heads/master
Commit: 2463dc18c53cb13e3a3c1a0c3b6dc2f40b000268
Parents: 49c7c05
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Fri Jan 31 15:33:50 2014 +0000
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Fri Jan 31 15:33:50 2014 +0000

----------------------------------------------------------------------
 .../objectstore/jdo/applib/service/Util.java    |  68 +++
 .../jdo/applib/service/audit/AuditEntryJdo.java |   2 +-
 .../service/background/BackgroundTaskJdo.java   |   2 +-
 .../background/BackgroundTaskServiceJdo.java    |  11 +-
 .../service/interaction/InteractionJdo.java     | 541 ------------------
 .../interaction/InteractionServiceJdo.java      |  90 ---
 .../InteractionServiceJdoRepository.java        |  72 ---
 .../jdo/applib/service/interaction/Util.java    |  68 ---
 .../service/publish/PublishedEventJdo.java      |   2 +-
 .../reifiableaction/ReifiableActionJdo.java     | 562 +++++++++++++++++++
 .../ReifiableActionServiceJdo.java              |  93 +++
 .../ReifiableActionServiceJdoRepository.java    |  75 +++
 .../interaction/InteractionJdoTest_next.java    |  41 --
 .../ReifiableActionJdoTest_next.java            |  43 ++
 .../ui/components/actions/ActionPanel.java      |  12 +-
 .../apache/isis/applib/annotation/Reified.java  |  40 ++
 .../background/BackgroundTaskService.java       |   4 +-
 .../services/interaction/Interaction.java       | 224 --------
 .../interaction/InteractionContext.java         |  50 --
 .../interaction/InteractionDefault.java         | 228 --------
 .../interaction/spi/InteractionService.java     |  55 --
 .../reifiableaction/ReifiableAction.java        | 245 ++++++++
 .../reifiableaction/ReifiableActionContext.java |  50 ++
 .../reifiableaction/ReifiableActionDefault.java | 233 ++++++++
 .../spi/ReifiableActionService.java             |  55 ++
 .../applib/services/scratchpad/Scratchpad.java  |   6 -
 .../InteractionDefaultTest_next.java            |   4 +-
 .../actions/invoke/ActionInvocationFacet.java   |   6 +-
 .../actions/reified/ReifiedActionFacet.java     |  35 ++
 .../invoke/ActionInvocationFacetViaMethod.java  |  34 +-
 .../reified/ReifiedActionFacetAbstract.java     |  37 ++
 .../ReifiedActionAnnotationFacetFactory.java    |  51 ++
 .../ReifiedActionFacetAnnotation.java           |  31 +
 .../dflt/ProgrammingModelFacetsJava5.java       |   2 +
 ...ReifiedActionAnnotationFacetFactoryTest.java |  66 +++
 .../background/BackgroundServiceDefault.java    |  21 +-
 .../system/persistence/PersistenceSession.java  |  36 +-
 .../system/transaction/IsisTransaction.java     |  30 +-
 .../transaction/IsisTransactionManager.java     |   8 +-
 .../BackgroundServiceDefaultTest_execute.java   |  29 +-
 .../system/transaction/IsisTransactionTest.java |   8 +-
 .../dom/src/main/java/dom/todo/ToDoItem.java    |   7 +-
 .../src/main/java/webapp/admin/Admin.java       |  12 +-
 .../src/main/webapp/WEB-INF/isis.properties     |  12 +-
 .../src/main/webapp/WEB-INF/isis.properties     |  12 +-
 45 files changed, 1820 insertions(+), 1493 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/2463dc18/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/Util.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/Util.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/Util.java
new file mode 100644
index 0000000..21350d0
--- /dev/null
+++ b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/Util.java
@@ -0,0 +1,68 @@
+/**
+ *  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.
+ */
+package org.apache.isis.objectstore.jdo.applib.service;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.sql.Timestamp;
+
+import org.apache.isis.applib.DomainObjectContainer;
+import org.apache.isis.applib.services.HasTransactionId;
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.applib.services.bookmark.BookmarkService;
+import org.apache.isis.applib.services.reifiableaction.ReifiableAction;
+
+public class Util {
+
+    private Util() {}
+
+    public static Bookmark bookmarkFor(final String str) {
+        return str != null? new Bookmark(str): null;
+    }
+
+    public static String asString(Bookmark bookmark) {
+        return bookmark != null? bookmark.toString(): null;
+    }
+
+    public static Object lookupBookmark(Bookmark bookmark, final BookmarkService bookmarkService, DomainObjectContainer container) {
+        try {
+            return bookmarkService != null
+                    ? bookmarkService.lookup(bookmark)
+                    : null;
+        } catch(RuntimeException ex) {
+            if(ex.getClass().getName().contains("ObjectNotFoundException")) {
+                container.warnUser("Object not found - has it since been deleted?");
+                return null;
+            } 
+            throw ex;
+        }
+    }
+
+    
+    public static String abbreviated(final String str, final int maxLength) {
+        return str != null? (str.length() < maxLength ? str : str.substring(0, maxLength - 3) + "..."): null;
+    }
+
+    public static BigDecimal durationBetween(Timestamp startedAt, Timestamp completedAt) {
+        if(completedAt == null) {
+            return null;
+        }
+        long millis = completedAt.getTime() - startedAt.getTime();
+        return new BigDecimal(millis).divide(new BigDecimal(1000)).setScale(3, RoundingMode.HALF_EVEN);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2463dc18/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditEntryJdo.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditEntryJdo.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditEntryJdo.java
index fa80985..f816997 100644
--- a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditEntryJdo.java
+++ b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditEntryJdo.java
@@ -44,7 +44,7 @@ import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.bookmark.BookmarkService;
 import org.apache.isis.applib.util.TitleBuffer;
 import org.apache.isis.objectstore.jdo.applib.service.JdoColumnLength;
-import org.apache.isis.objectstore.jdo.applib.service.interaction.Util;
+import org.apache.isis.objectstore.jdo.applib.service.Util;
 
 @javax.jdo.annotations.PersistenceCapable(
         identityType=IdentityType.DATASTORE,

http://git-wip-us.apache.org/repos/asf/isis/blob/2463dc18/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskJdo.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskJdo.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskJdo.java
index 105fab1..ffaa45d 100644
--- a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskJdo.java
+++ b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskJdo.java
@@ -46,7 +46,7 @@ import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.bookmark.BookmarkService;
 import org.apache.isis.applib.util.ObjectContracts;
 import org.apache.isis.objectstore.jdo.applib.service.JdoColumnLength;
-import org.apache.isis.objectstore.jdo.applib.service.interaction.Util;
+import org.apache.isis.objectstore.jdo.applib.service.Util;
 
 
 @javax.jdo.annotations.PersistenceCapable(

http://git-wip-us.apache.org/repos/asf/isis/blob/2463dc18/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskServiceJdo.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskServiceJdo.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskServiceJdo.java
index 03eda70..7954fa1 100644
--- a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskServiceJdo.java
+++ b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskServiceJdo.java
@@ -27,6 +27,7 @@ import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.clock.Clock;
 import org.apache.isis.applib.services.background.ActionInvocationMemento;
 import org.apache.isis.applib.services.background.BackgroundTaskService;
+import org.apache.isis.applib.services.reifiableaction.ReifiableAction;
 
 @Named("Background Tasks")
 public class BackgroundTaskServiceJdo extends AbstractService implements BackgroundTaskService {
@@ -36,7 +37,11 @@ public class BackgroundTaskServiceJdo extends AbstractService implements Backgro
 
     @Programmatic
     @Override
-    public void execute(final ActionInvocationMemento aim, final UUID transactionId, final int sequence) {
+    public void execute(final ActionInvocationMemento aim, final ReifiableAction reifiableAction) {
+        
+        final UUID transactionId = reifiableAction.getTransactionId();
+        Integer sequence = reifiableAction.next("backgroundTaskServiceSequence");
+
         final BackgroundTaskJdo backgroundTask = newTransientInstance(BackgroundTaskJdo.class);
 
         backgroundTask.setActionIdentifier(aim.getActionId());
@@ -44,9 +49,11 @@ public class BackgroundTaskServiceJdo extends AbstractService implements Backgro
         backgroundTask.setMemento(aim.asMementoString());
         backgroundTask.setUser(aim.getUser());
         backgroundTask.setTargetStr(aim.getTarget().toString());
-
         backgroundTask.setTransactionId(transactionId);
         backgroundTask.setSequence(sequence);
+        
+        reifiableAction.setReify(true);
+        
         persist(backgroundTask);
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/2463dc18/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/interaction/InteractionJdo.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/interaction/InteractionJdo.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/interaction/InteractionJdo.java
deleted file mode 100644
index 1c82c5a..0000000
--- a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/interaction/InteractionJdo.java
+++ /dev/null
@@ -1,541 +0,0 @@
-/**
- *  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.
- */
-package org.apache.isis.objectstore.jdo.applib.service.interaction;
-
-import java.math.BigDecimal;
-import java.sql.Timestamp;
-import java.util.Map;
-import java.util.UUID;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import javax.jdo.annotations.IdentityType;
-
-import com.google.common.collect.Maps;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.isis.applib.DomainObjectContainer;
-import org.apache.isis.applib.annotation.ActionSemantics;
-import org.apache.isis.applib.annotation.ActionSemantics.Of;
-import org.apache.isis.applib.annotation.Disabled;
-import org.apache.isis.applib.annotation.Hidden;
-import org.apache.isis.applib.annotation.MemberGroupLayout;
-import org.apache.isis.applib.annotation.MemberOrder;
-import org.apache.isis.applib.annotation.MultiLine;
-import org.apache.isis.applib.annotation.Named;
-import org.apache.isis.applib.annotation.ObjectType;
-import org.apache.isis.applib.annotation.Programmatic;
-import org.apache.isis.applib.annotation.Title;
-import org.apache.isis.applib.annotation.TypicalLength;
-import org.apache.isis.applib.annotation.Where;
-import org.apache.isis.applib.services.HasTransactionId;
-import org.apache.isis.applib.services.bookmark.Bookmark;
-import org.apache.isis.applib.services.bookmark.BookmarkService;
-import org.apache.isis.applib.services.interaction.Interaction;
-import org.apache.isis.applib.services.interaction.spi.InteractionService;
-import org.apache.isis.applib.util.ObjectContracts;
-import org.apache.isis.objectstore.jdo.applib.service.JdoColumnLength;
-
-
-@javax.jdo.annotations.PersistenceCapable(
-        identityType=IdentityType.APPLICATION, 
-        table="IsisInteraction")
-@javax.jdo.annotations.Queries( {
-    @javax.jdo.annotations.Query(
-            name="findByTransactionId", language="JDOQL",  
-            value="SELECT "
-                    + "FROM org.apache.isis.objectstore.jdo.applib.service.interaction.InteractionJdo "
-                    + "WHERE transactionId == :transactionId"),
-    @javax.jdo.annotations.Query(
-            name="findCurrent", language="JDOQL",  
-            value="SELECT "
-                    + "FROM org.apache.isis.objectstore.jdo.applib.service.interaction.InteractionJdo "
-                    + "WHERE completedAt == null "
-                    + "ORDER BY timestamp DESC"),
-    @javax.jdo.annotations.Query(
-            name="findCompleted", language="JDOQL",  
-            value="SELECT "
-                    + "FROM org.apache.isis.objectstore.jdo.applib.service.interaction.InteractionJdo "
-                    + "WHERE completedAt != null "
-                    + "ORDER BY timestamp DESC")
-})
-@ObjectType("IsisInteration")
-@MemberGroupLayout(
-        columnSpans={6,0,6}, 
-        left={"Identifiers","Target","Notes"},
-        right={"Detail","Timings","Results"})
-@Named("Interaction")
-public class InteractionJdo implements Interaction {
-
-    @SuppressWarnings("unused")
-    private static final Logger LOG = LoggerFactory.getLogger(InteractionJdo.class);
-
-
-    // //////////////////////////////////////
-    // transactionId (property)
-    // //////////////////////////////////////
-
-        
-    private UUID transactionId;
-
-    /**
-     * The unique identifier (a GUID) of the transaction in which this interaction occurred.
-     */
-    @javax.jdo.annotations.PrimaryKey
-    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.TRANSACTION_ID)
-    @TypicalLength(JdoColumnLength.TRANSACTION_ID)
-    @MemberOrder(name="Identifiers",sequence = "10")
-    @Disabled
-    @Override
-    public UUID getTransactionId() {
-        return transactionId;
-    }
-
-    /**
-     * <b>NOT API</b>: intended to be called only by the framework.
-     * 
-     * <p>
-     * Implementation notes: copied over from the Isis transaction when the interaction is persisted.
-     */
-    @Override
-    public void setTransactionId(final UUID transactionId) {
-        this.transactionId = transactionId;
-    }
-
-    // //////////////////////////////////////
-    // user (property)
-    // //////////////////////////////////////
-
-    private String user;
-
-    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.USER_NAME)
-    @Title(sequence="2", prepend=", ")
-    @MemberOrder(name="Identifiers", sequence = "20")
-    public String getUser() {
-        return user;
-    }
-
-    public void setUser(final String user) {
-        this.user = user;
-    }
-
-
-
-    // //////////////////////////////////////
-    // timestamp (property)
-    // //////////////////////////////////////
-
-    private Timestamp timestamp;
-
-    /**
-     * The date/time at which this interaction started.
-     */
-    @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(allowsNull="false")
-    @MemberOrder(name="Timings", sequence = "30")
-    public Timestamp getTimestamp() {
-        return timestamp;
-    }
-
-    public void setTimestamp(final Timestamp timestamp) {
-        this.timestamp = timestamp;
-    }
-
-    
-    
-
-    // //////////////////////////////////////
-    // targetClass (property)
-    // //////////////////////////////////////
-
-    private String targetClass;
-
-    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.Interaction.TARGET_CLASS)
-    @TypicalLength(30)
-    @MemberOrder(name="Target", sequence = "10")
-    @Named("Class")
-    public String getTargetClass() {
-        return targetClass;
-    }
-
-    public void setTargetClass(final String targetClass) {
-        this.targetClass = Util.abbreviated(targetClass, JdoColumnLength.Interaction.TARGET_CLASS);
-    }
-
-
-    // //////////////////////////////////////
-    // targetAction (property)
-    // //////////////////////////////////////
-    
-    private String targetAction;
-    
-    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.Interaction.TARGET_ACTION)
-    @TypicalLength(30)
-    @MemberOrder(name="Target", sequence = "20")
-    @Named("Action")
-    public String getTargetAction() {
-        return targetAction;
-    }
-    
-    public void setTargetAction(final String targetAction) {
-        this.targetAction = Util.abbreviated(targetAction, JdoColumnLength.Interaction.TARGET_ACTION);
-    }
-    
-
-    // //////////////////////////////////////
-    // target (property)
-    // openTargetObject (action)
-    // //////////////////////////////////////
-
-    @Programmatic
-    @Override
-    public Bookmark getTarget() {
-        return Util.bookmarkFor(getTargetStr());
-    }
-    
-    @Programmatic
-    @Override
-    public void setTarget(Bookmark target) {
-        setTargetStr(Util.asString(target));
-    }
-
-    // //////////////////////////////////////
-    
-    private String targetStr;
-    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.BOOKMARK, name="target")
-    @Named("Target Bookmark")
-    @Hidden(where=Where.ALL_TABLES)
-    @MemberOrder(name="Target", sequence="3")
-    @Disabled
-    public String getTargetStr() {
-        return targetStr;
-    }
-
-    public void setTargetStr(final String targetStr) {
-        this.targetStr = targetStr;
-    }
-
-    // //////////////////////////////////////
-
-    @ActionSemantics(Of.SAFE)
-    @MemberOrder(name="TargetStr", sequence="1")
-    @Named("Open")
-    public Object openTargetObject() {
-        return Util.lookupBookmark(getTarget(), bookmarkService, container);
-    }
-    public boolean hideOpenTargetObject() {
-        return getTarget() == null;
-    }
-
-    
-    // //////////////////////////////////////
-    // actionIdentifier (property)
-    // //////////////////////////////////////
-
-    private String actionIdentifier;
-    
-    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.ACTION_IDENTIFIER)
-    @Title(sequence="1")
-    @TypicalLength(60)
-    @Hidden(where=Where.ALL_TABLES)
-    @MemberOrder(name="Detail",sequence = "1")
-    public String getActionIdentifier() {
-        return actionIdentifier;
-    }
-
-    public void setActionIdentifier(final String actionIdentifier) {
-        this.actionIdentifier = Util.abbreviated(actionIdentifier, JdoColumnLength.ACTION_IDENTIFIER);
-    }
-
-
-
-    // //////////////////////////////////////
-    // arguments (property)
-    // //////////////////////////////////////
-    
-    private String arguments;
-    
-    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.Interaction.ARGUMENTS)
-    @MultiLine(numberOfLines=6)
-    @Hidden(where=Where.ALL_TABLES)
-    @MemberOrder(name="Detail",sequence = "4")
-    @Disabled
-    public String getArguments() {
-        return arguments;
-    }
-    
-    public void setArguments(final String arguments) {
-        this.arguments = Util.abbreviated(arguments, JdoColumnLength.Interaction.ARGUMENTS);
-    }
-
-
-    // //////////////////////////////////////
-    // startedAt (derived property)
-    // //////////////////////////////////////
-    
-    /**
-     * The date/time at which this interaction started.
-     */
-    @javax.jdo.annotations.NotPersistent
-    @MemberOrder(name="Timings", sequence = "3")
-    @Disabled
-    public Timestamp getStartedAt() {
-        return getTimestamp();
-    }
-    
-    
-    
-    // //////////////////////////////////////
-    // completedAt (property)
-    // //////////////////////////////////////
-
-    private Timestamp completedAt;
-
-    /**
-     * The date/time at which this interaction completed.
-     * 
-     * <p>
-     * Not part of the applib API, because the default implementation is not persistent
-     * and so cannot be queried "after the fact".  This JDO-specific class is persistent,
-     * and so we can gather this information.
-     */
-    @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(allowsNull="true")
-    @MemberOrder(name="Timings", sequence = "4")
-    @Disabled
-    public Timestamp getCompletedAt() {
-        return completedAt;
-    }
-
-    public void setCompletedAt(final Timestamp completed) {
-        this.completedAt = completed;
-    }
-
-
-    // //////////////////////////////////////
-    // duration (derived property)
-    // //////////////////////////////////////
-
-    /**
-     * The number of seconds (to 3 decimal places) that this interaction lasted.
-     * 
-     * <p>
-     * Populated only if it has {@link #getCompletedAt() completed}.
-     */
-    @javax.validation.constraints.Digits(integer=5, fraction=3)
-    @Named("Duration")
-    @MemberOrder(name="Timings", sequence = "7")
-    public BigDecimal getDuration() {
-        return Util.durationBetween(getStartedAt(), getCompletedAt());
-    }
-
-
-
-    // //////////////////////////////////////
-    // notes (property)
-    // //////////////////////////////////////
-
-    private String notes;
-
-    /**
-     * Provides the ability for the end-user to annotate a (potentially long-running)
-     * interaction.
-     * 
-     * <p>
-     * Not part of the applib API, because the default implementation is not persistent
-     * and so there's no object that can be accessed to be annotated.
-     */
-    @javax.jdo.annotations.Column(allowsNull="true", length=JdoColumnLength.Interaction.NOTES)
-    @MultiLine(numberOfLines=10)
-    @Hidden(where=Where.ALL_TABLES)
-    @MemberOrder(name="Notes", sequence = "6")
-    public String getNotes() {
-        return notes;
-    }
-
-    public void setNotes(final String notes) {
-        this.notes = notes;
-    }
-
-
-    // //////////////////////////////////////
-    // nature (property)
-    // //////////////////////////////////////
-
-    private Nature nature;
-
-    /**
-     * Not persisted, used as a hint that an action was invoked explicitly by the user
-     * (rather than as a side-effect, eg of rendering an object due to get-after-post).
-     */
-    @javax.jdo.annotations.NotPersistent
-    @Programmatic
-    @Override
-    public Nature getNature() {
-        return nature;
-    }
-    
-    /**
-     * <b>NOT API</b>: intended to be called only by the framework.
-     * 
-     * <p>
-     * Implementation notes: populated by the viewer as hint to {@link InteractionService} implementation.
-     */
-    @Override
-    public void setNature(Nature nature) {
-        this.nature = nature;
-    }
-
-    
-    // //////////////////////////////////////
-    // result (property)
-    // openResultObject (action)
-    // //////////////////////////////////////
-
-    @Programmatic
-    @Override
-    public Bookmark getResult() {
-        return Util.bookmarkFor(getResultStr());
-    }
-
-    @Programmatic
-    @Override
-    public void setResult(Bookmark result) {
-        setResultStr(Util.asString(result));
-    }
-
-    // //////////////////////////////////////
-    
-    private String resultStr;
-
-    @javax.jdo.annotations.Column(allowsNull="true", length=JdoColumnLength.BOOKMARK, name="result")
-    @Hidden(where=Where.ALL_TABLES)
-    @Named("Result Bookmark")
-    @MemberOrder(name="Results", sequence="25")
-    @Disabled
-    public String getResultStr() {
-        return resultStr;
-    }
-
-    public void setResultStr(final String resultStr) {
-        this.resultStr = resultStr;
-    }
-
-    // //////////////////////////////////////
-
-    @ActionSemantics(Of.SAFE)
-    @MemberOrder(name="ResultStr", sequence="1")
-    @Named("Open")
-    public Object openResultObject() {
-        return Util.lookupBookmark(getResult(), bookmarkService, container);
-    }
-    public boolean hideOpenResultObject() {
-        return getResult() == null;
-    }
-
-
-    // //////////////////////////////////////
-    // exception (property)
-    // causedException (derived property)
-    // showException (associated action)
-    // //////////////////////////////////////
-
-    private String exception;
-
-    /**
-     * Stack trace of any exception that might have occurred if this interaction/transaction aborted.
-     * 
-     * <p>
-     * Not visible in the UI, but accessible 
-     * <p>
-     * Not part of the applib API, because the default implementation is not persistent
-     * and so there's no object that can be accessed to be annotated.
-     */
-    @javax.jdo.annotations.Column(allowsNull="true", length=JdoColumnLength.Interaction.EXCEPTION)
-    @Hidden
-    @Override
-    public String getException() {
-        return exception;
-    }
-
-    @Override
-    public void setException(final String exception) {
-        this.exception = Util.abbreviated(exception, JdoColumnLength.Interaction.EXCEPTION);
-    }
-    
-    
-    // //////////////////////////////////////
-    
-    @javax.jdo.annotations.NotPersistent
-    @MemberOrder(name="Results",sequence = "30")
-    @Hidden(where=Where.ALL_TABLES)
-    public boolean isCausedException() {
-        return getException() != null;
-    }
-
-    
-    // //////////////////////////////////////
-    
-    @ActionSemantics(Of.SAFE)
-    @MemberOrder(name="causedException", sequence = "1")
-    public String showException() {
-        return getException();
-    }
-    public boolean hideShowException() {
-        return !isCausedException();
-    }
-
-
-    // //////////////////////////////////////
-    // next(...) impl
-    // //////////////////////////////////////
-
-    private final Map<String, AtomicInteger> sequenceByName = Maps.newHashMap();
-
-    @Programmatic
-    @Override
-    public int next(String sequenceName) {
-        AtomicInteger next = sequenceByName.get(sequenceName);
-        if(next == null) {
-            next = new AtomicInteger(0);
-            sequenceByName.put(sequenceName, next);
-        } else {
-            next.incrementAndGet();
-        }
-        return next.get();
-    }
-
-    // //////////////////////////////////////
-    // toString
-    // //////////////////////////////////////
-
-
-    @Override
-    public String toString() {
-        return ObjectContracts.toString(this, "startedAt,user,actionIdentifier,target,completedAt,duration,transactionId");
-    }
-
-    
-    // //////////////////////////////////////
-    
-    @javax.inject.Inject
-    private BookmarkService bookmarkService;
-    
-    @javax.inject.Inject
-    private DomainObjectContainer container;
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/2463dc18/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/interaction/InteractionServiceJdo.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/interaction/InteractionServiceJdo.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/interaction/InteractionServiceJdo.java
deleted file mode 100644
index 1e58d11..0000000
--- a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/interaction/InteractionServiceJdo.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/**
- *  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.
- */
-package org.apache.isis.objectstore.jdo.applib.service.interaction;
-
-import java.util.UUID;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.isis.applib.AbstractService;
-import org.apache.isis.applib.annotation.Programmatic;
-import org.apache.isis.applib.clock.Clock;
-import org.apache.isis.applib.services.interaction.Interaction;
-import org.apache.isis.applib.services.interaction.spi.InteractionService;
-
-public class InteractionServiceJdo extends AbstractService implements InteractionService {
-
-    @SuppressWarnings("unused")
-    private static final Logger LOG = LoggerFactory.getLogger(InteractionServiceJdo.class);
-
-    /**
-     * Creates an {@link InteractionJdo}, initializing its 
-     * {@link Interaction#setNature(Interaction.Nature) nature} to be
-     * {@link Interaction.Nature#RENDERING rendering}.
-     */
-    @Programmatic
-    @Override
-    public Interaction create() {
-        InteractionJdo interaction = newTransientInstance(InteractionJdo.class);
-        interaction.setNature(Interaction.Nature.RENDERING);
-        return interaction;
-    }
-
-    @Programmatic
-    @Override
-    public void startTransaction(final Interaction interaction, final UUID transactionId) {
-        if(interaction instanceof InteractionJdo) {
-            // should be the case, since this service created the object in the #create() method
-            final InteractionJdo interactionJdo = (InteractionJdo) interaction;
-            final UUID currentTransactionId = interactionJdo.getTransactionId();
-            if(currentTransactionId != null && !currentTransactionId.equals(transactionId)) {
-                // the logic in IsisTransaction means that any subsequent transactions within a given interaction
-                // should reuse the xactnId of the first transaction created within that interaction.
-                throw new IllegalStateException("Attempting to set a different transactionId on interaction");
-            }
-            interactionJdo.setTransactionId(transactionId);
-        }
-    }
-
-    @Programmatic
-    @Override
-    public void complete(final Interaction interaction) {
-        InteractionJdo interactionJdo = asPersistableInteractionJdo(interaction);
-        if(interactionJdo == null) {
-            return;
-        }
-            
-        interactionJdo.setCompletedAt(Clock.getTimeAsJavaSqlTimestamp());
-        
-        persistIfNotAlready(interactionJdo);
-    }
-
-    /**
-     * Not API, factored out from {@link InteractionServiceJdoRepository}.
-     */
-    InteractionJdo asPersistableInteractionJdo(final Interaction interaction) {
-        if(interaction.getNature() == Interaction.Nature.ACTION_INVOCATION) {
-            if(interaction instanceof InteractionJdo) {
-                // should be the case, since this service created the object in the #create() method
-                return (InteractionJdo)interaction;
-            }
-        }
-        // else, don't care
-        return null;
-    }
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/2463dc18/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/interaction/InteractionServiceJdoRepository.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/interaction/InteractionServiceJdoRepository.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/interaction/InteractionServiceJdoRepository.java
deleted file mode 100644
index 8fea1c3..0000000
--- a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/interaction/InteractionServiceJdoRepository.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/**
- *  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.
- */
-package org.apache.isis.objectstore.jdo.applib.service.interaction;
-
-import java.util.List;
-import java.util.UUID;
-
-import org.apache.isis.applib.AbstractFactoryAndRepository;
-import org.apache.isis.applib.annotation.Programmatic;
-import org.apache.isis.applib.query.QueryDefault;
-import org.apache.isis.applib.services.interaction.Interaction;
-import org.apache.isis.applib.services.interaction.InteractionContext;
-
-
-public class InteractionServiceJdoRepository extends AbstractFactoryAndRepository {
-
-    @Programmatic
-    public InteractionJdo findByTransactionId(final UUID transactionId) {
-        persistCurrentInteractionIfRequired();
-        return firstMatch(
-                new QueryDefault<InteractionJdo>(InteractionJdo.class, 
-                        "findByTransactionId", 
-                        "transactionId", transactionId.toString()));
-    }
-
-    private void persistCurrentInteractionIfRequired() {
-        if(interactionContext != null && interactionService != null) {
-            Interaction interaction = interactionContext.getInteraction();
-            final InteractionJdo interactionJdo = interactionService.asPersistableInteractionJdo(interaction);
-            persistIfNotAlready(interactionJdo);
-        }
-    }
-
-    
-    @Programmatic
-    public List<InteractionJdo> findCurrent() {
-        persistCurrentInteractionIfRequired();
-        return allMatches(
-                new QueryDefault<InteractionJdo>(InteractionJdo.class, "findCurrent"));
-    }
-    
-    @Programmatic
-    public List<InteractionJdo> findCompleted() {
-        persistCurrentInteractionIfRequired();
-        return allMatches(
-                new QueryDefault<InteractionJdo>(InteractionJdo.class, "findCompleted"));
-    }
-
-    // //////////////////////////////////////
-
-    
-    @javax.inject.Inject
-    private InteractionServiceJdo interactionService;
-    
-    @javax.inject.Inject
-    private InteractionContext interactionContext;
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/2463dc18/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/interaction/Util.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/interaction/Util.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/interaction/Util.java
deleted file mode 100644
index 031817a..0000000
--- a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/interaction/Util.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/**
- *  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.
- */
-package org.apache.isis.objectstore.jdo.applib.service.interaction;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.sql.Timestamp;
-
-import org.apache.isis.applib.DomainObjectContainer;
-import org.apache.isis.applib.services.HasTransactionId;
-import org.apache.isis.applib.services.bookmark.Bookmark;
-import org.apache.isis.applib.services.bookmark.BookmarkService;
-import org.apache.isis.applib.services.interaction.Interaction;
-
-public class Util {
-
-    private Util() {}
-
-    public static Bookmark bookmarkFor(final String str) {
-        return str != null? new Bookmark(str): null;
-    }
-
-    public static String asString(Bookmark bookmark) {
-        return bookmark != null? bookmark.toString(): null;
-    }
-
-    public static Object lookupBookmark(Bookmark bookmark, final BookmarkService bookmarkService, DomainObjectContainer container) {
-        try {
-            return bookmarkService != null
-                    ? bookmarkService.lookup(bookmark)
-                    : null;
-        } catch(RuntimeException ex) {
-            if(ex.getClass().getName().contains("ObjectNotFoundException")) {
-                container.warnUser("Object not found - has it since been deleted?");
-                return null;
-            } 
-            throw ex;
-        }
-    }
-
-    
-    public static String abbreviated(final String str, final int maxLength) {
-        return str != null? (str.length() < maxLength ? str : str.substring(0, maxLength - 3) + "..."): null;
-    }
-
-    public static BigDecimal durationBetween(Timestamp startedAt, Timestamp completedAt) {
-        if(completedAt == null) {
-            return null;
-        }
-        long millis = completedAt.getTime() - startedAt.getTime();
-        return new BigDecimal(millis).divide(new BigDecimal(1000)).setScale(3, RoundingMode.HALF_EVEN);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/2463dc18/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/publish/PublishedEventJdo.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/publish/PublishedEventJdo.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/publish/PublishedEventJdo.java
index b7a9542..9fde6fc 100644
--- a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/publish/PublishedEventJdo.java
+++ b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/publish/PublishedEventJdo.java
@@ -44,7 +44,7 @@ import org.apache.isis.applib.services.HasTransactionId;
 import org.apache.isis.applib.services.bookmark.BookmarkService;
 import org.apache.isis.applib.services.publish.EventType;
 import org.apache.isis.objectstore.jdo.applib.service.JdoColumnLength;
-import org.apache.isis.objectstore.jdo.applib.service.interaction.Util;
+import org.apache.isis.objectstore.jdo.applib.service.Util;
 
 @javax.jdo.annotations.PersistenceCapable(
         identityType=IdentityType.APPLICATION,

http://git-wip-us.apache.org/repos/asf/isis/blob/2463dc18/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/reifiableaction/ReifiableActionJdo.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/reifiableaction/ReifiableActionJdo.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/reifiableaction/ReifiableActionJdo.java
new file mode 100644
index 0000000..8d92b32
--- /dev/null
+++ b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/reifiableaction/ReifiableActionJdo.java
@@ -0,0 +1,562 @@
+/**
+ *  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.
+ */
+package org.apache.isis.objectstore.jdo.applib.service.reifiableaction;
+
+import java.math.BigDecimal;
+import java.sql.Timestamp;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.jdo.annotations.IdentityType;
+
+import com.google.common.collect.Maps;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.isis.applib.DomainObjectContainer;
+import org.apache.isis.applib.annotation.ActionSemantics;
+import org.apache.isis.applib.annotation.ActionSemantics.Of;
+import org.apache.isis.applib.annotation.Disabled;
+import org.apache.isis.applib.annotation.Hidden;
+import org.apache.isis.applib.annotation.MemberGroupLayout;
+import org.apache.isis.applib.annotation.MemberOrder;
+import org.apache.isis.applib.annotation.MultiLine;
+import org.apache.isis.applib.annotation.Named;
+import org.apache.isis.applib.annotation.ObjectType;
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.annotation.Title;
+import org.apache.isis.applib.annotation.TypicalLength;
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.applib.services.bookmark.BookmarkService;
+import org.apache.isis.applib.services.reifiableaction.ReifiableAction;
+import org.apache.isis.applib.services.reifiableaction.spi.ReifiableActionService;
+import org.apache.isis.applib.util.ObjectContracts;
+import org.apache.isis.objectstore.jdo.applib.service.JdoColumnLength;
+import org.apache.isis.objectstore.jdo.applib.service.Util;
+
+
+@javax.jdo.annotations.PersistenceCapable(
+        identityType=IdentityType.APPLICATION, 
+        table="IsisReifiableAction")
+@javax.jdo.annotations.Queries( {
+    @javax.jdo.annotations.Query(
+            name="findByTransactionId", language="JDOQL",  
+            value="SELECT "
+                    + "FROM org.apache.isis.objectstore.jdo.applib.service.reifiableaction.ReifiableActionJdo "
+                    + "WHERE transactionId == :transactionId"),
+    @javax.jdo.annotations.Query(
+            name="findCurrent", language="JDOQL",  
+            value="SELECT "
+                    + "FROM org.apache.isis.objectstore.jdo.applib.service.reifiableaction.ReifiableActionJdo "
+                    + "WHERE completedAt == null "
+                    + "ORDER BY timestamp DESC"),
+    @javax.jdo.annotations.Query(
+            name="findCompleted", language="JDOQL",  
+            value="SELECT "
+                    + "FROM org.apache.isis.objectstore.jdo.applib.service.reifiableaction.ReifiableActionJdo "
+                    + "WHERE completedAt != null "
+                    + "ORDER BY timestamp DESC")
+})
+@ObjectType("IsisReifiableAction")
+@MemberGroupLayout(
+        columnSpans={6,0,6}, 
+        left={"Identifiers","Target","Notes"},
+        right={"Detail","Timings","Results"})
+@Named("Interaction")
+public class ReifiableActionJdo implements ReifiableAction {
+
+    @SuppressWarnings("unused")
+    private static final Logger LOG = LoggerFactory.getLogger(ReifiableActionJdo.class);
+
+
+    // //////////////////////////////////////
+    // transactionId (property)
+    // //////////////////////////////////////
+
+        
+    private UUID transactionId;
+
+    /**
+     * The unique identifier (a GUID) of the transaction in which this action occurred.
+     */
+    @javax.jdo.annotations.PrimaryKey
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.TRANSACTION_ID)
+    @TypicalLength(JdoColumnLength.TRANSACTION_ID)
+    @MemberOrder(name="Identifiers",sequence = "10")
+    @Disabled
+    @Override
+    public UUID getTransactionId() {
+        return transactionId;
+    }
+
+    /**
+     * <b>NOT API</b>: intended to be called only by the framework.
+     * 
+     * <p>
+     * Implementation notes: copied over from the Isis transaction when the action is persisted.
+     */
+    @Override
+    public void setTransactionId(final UUID transactionId) {
+        this.transactionId = transactionId;
+    }
+
+    // //////////////////////////////////////
+    // user (property)
+    // //////////////////////////////////////
+
+    private String user;
+
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.USER_NAME)
+    @Title(sequence="2", prepend=", ")
+    @MemberOrder(name="Identifiers", sequence = "20")
+    public String getUser() {
+        return user;
+    }
+
+    public void setUser(final String user) {
+        this.user = user;
+    }
+
+
+
+    // //////////////////////////////////////
+    // timestamp (property)
+    // //////////////////////////////////////
+
+    private Timestamp timestamp;
+
+    /**
+     * The date/time at which this interaction started.
+     */
+    @javax.jdo.annotations.Persistent
+    @javax.jdo.annotations.Column(allowsNull="false")
+    @MemberOrder(name="Timings", sequence = "30")
+    public Timestamp getTimestamp() {
+        return timestamp;
+    }
+
+    public void setTimestamp(final Timestamp timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    
+    
+
+    // //////////////////////////////////////
+    // targetClass (property)
+    // //////////////////////////////////////
+
+    private String targetClass;
+
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.Interaction.TARGET_CLASS)
+    @TypicalLength(30)
+    @MemberOrder(name="Target", sequence = "10")
+    @Named("Class")
+    public String getTargetClass() {
+        return targetClass;
+    }
+
+    public void setTargetClass(final String targetClass) {
+        this.targetClass = Util.abbreviated(targetClass, JdoColumnLength.Interaction.TARGET_CLASS);
+    }
+
+
+    // //////////////////////////////////////
+    // targetAction (property)
+    // //////////////////////////////////////
+    
+    private String targetAction;
+    
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.Interaction.TARGET_ACTION)
+    @TypicalLength(30)
+    @MemberOrder(name="Target", sequence = "20")
+    @Named("Action")
+    public String getTargetAction() {
+        return targetAction;
+    }
+    
+    public void setTargetAction(final String targetAction) {
+        this.targetAction = Util.abbreviated(targetAction, JdoColumnLength.Interaction.TARGET_ACTION);
+    }
+    
+
+    // //////////////////////////////////////
+    // target (property)
+    // openTargetObject (action)
+    // //////////////////////////////////////
+
+    @Programmatic
+    @Override
+    public Bookmark getTarget() {
+        return Util.bookmarkFor(getTargetStr());
+    }
+    
+    @Programmatic
+    @Override
+    public void setTarget(Bookmark target) {
+        setTargetStr(Util.asString(target));
+    }
+
+    // //////////////////////////////////////
+    
+    private String targetStr;
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.BOOKMARK, name="target")
+    @Named("Target Bookmark")
+    @Hidden(where=Where.ALL_TABLES)
+    @MemberOrder(name="Target", sequence="3")
+    @Disabled
+    public String getTargetStr() {
+        return targetStr;
+    }
+
+    public void setTargetStr(final String targetStr) {
+        this.targetStr = targetStr;
+    }
+
+    // //////////////////////////////////////
+
+    @ActionSemantics(Of.SAFE)
+    @MemberOrder(name="TargetStr", sequence="1")
+    @Named("Open")
+    public Object openTargetObject() {
+        return Util.lookupBookmark(getTarget(), bookmarkService, container);
+    }
+    public boolean hideOpenTargetObject() {
+        return getTarget() == null;
+    }
+
+    
+    // //////////////////////////////////////
+    // actionIdentifier (property)
+    // //////////////////////////////////////
+
+    private String actionIdentifier;
+    
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.ACTION_IDENTIFIER)
+    @Title(sequence="1")
+    @TypicalLength(60)
+    @Hidden(where=Where.ALL_TABLES)
+    @MemberOrder(name="Detail",sequence = "1")
+    public String getActionIdentifier() {
+        return actionIdentifier;
+    }
+
+    public void setActionIdentifier(final String actionIdentifier) {
+        this.actionIdentifier = Util.abbreviated(actionIdentifier, JdoColumnLength.ACTION_IDENTIFIER);
+    }
+
+
+
+    // //////////////////////////////////////
+    // arguments (property)
+    // //////////////////////////////////////
+    
+    private String arguments;
+    
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.Interaction.ARGUMENTS)
+    @MultiLine(numberOfLines=6)
+    @Hidden(where=Where.ALL_TABLES)
+    @MemberOrder(name="Detail",sequence = "4")
+    @Disabled
+    public String getArguments() {
+        return arguments;
+    }
+    
+    public void setArguments(final String arguments) {
+        this.arguments = Util.abbreviated(arguments, JdoColumnLength.Interaction.ARGUMENTS);
+    }
+
+
+    // //////////////////////////////////////
+    // startedAt (derived property)
+    // //////////////////////////////////////
+    
+    /**
+     * The date/time at which this interaction started.
+     */
+    @javax.jdo.annotations.NotPersistent
+    @MemberOrder(name="Timings", sequence = "3")
+    @Disabled
+    public Timestamp getStartedAt() {
+        return getTimestamp();
+    }
+    
+    
+    
+    // //////////////////////////////////////
+    // completedAt (property)
+    // //////////////////////////////////////
+
+    private Timestamp completedAt;
+
+    /**
+     * The date/time at which this interaction completed.
+     * 
+     * <p>
+     * Not part of the applib API, because the default implementation is not persistent
+     * and so cannot be queried "after the fact".  This JDO-specific class is persistent,
+     * and so we can gather this information.
+     */
+    @javax.jdo.annotations.Persistent
+    @javax.jdo.annotations.Column(allowsNull="true")
+    @MemberOrder(name="Timings", sequence = "4")
+    @Disabled
+    public Timestamp getCompletedAt() {
+        return completedAt;
+    }
+
+    public void setCompletedAt(final Timestamp completed) {
+        this.completedAt = completed;
+    }
+
+
+    // //////////////////////////////////////
+    // duration (derived property)
+    // //////////////////////////////////////
+
+    /**
+     * The number of seconds (to 3 decimal places) that this interaction lasted.
+     * 
+     * <p>
+     * Populated only if it has {@link #getCompletedAt() completed}.
+     */
+    @javax.validation.constraints.Digits(integer=5, fraction=3)
+    @Named("Duration")
+    @MemberOrder(name="Timings", sequence = "7")
+    public BigDecimal getDuration() {
+        return Util.durationBetween(getStartedAt(), getCompletedAt());
+    }
+
+
+
+    // //////////////////////////////////////
+    // notes (property)
+    // //////////////////////////////////////
+
+    private String notes;
+
+    /**
+     * Provides the ability for the end-user to annotate a (potentially long-running)
+     * interaction.
+     * 
+     * <p>
+     * Not part of the applib API, because the default implementation is not persistent
+     * and so there's no object that can be accessed to be annotated.
+     */
+    @javax.jdo.annotations.Column(allowsNull="true", length=JdoColumnLength.Interaction.NOTES)
+    @MultiLine(numberOfLines=10)
+    @Hidden(where=Where.ALL_TABLES)
+    @MemberOrder(name="Notes", sequence = "6")
+    public String getNotes() {
+        return notes;
+    }
+
+    public void setNotes(final String notes) {
+        this.notes = notes;
+    }
+
+
+    // //////////////////////////////////////
+    // nature (property)
+    // //////////////////////////////////////
+
+    private Nature nature;
+
+    /**
+     * Not persisted, used as a hint that an action was invoked explicitly by the user
+     * (rather than as a side-effect, eg of rendering an object due to get-after-post).
+     */
+    @javax.jdo.annotations.NotPersistent
+    @Programmatic
+    @Override
+    public Nature getNature() {
+        return nature;
+    }
+    
+    /**
+     * <b>NOT API</b>: intended to be called only by the framework.
+     * 
+     * <p>
+     * Implementation notes: populated by the viewer as hint to {@link ReifiableActionService} implementation.
+     */
+    @Override
+    public void setNature(Nature nature) {
+        this.nature = nature;
+    }
+
+    
+    // //////////////////////////////////////
+    // result (property)
+    // openResultObject (action)
+    // //////////////////////////////////////
+
+    @Programmatic
+    @Override
+    public Bookmark getResult() {
+        return Util.bookmarkFor(getResultStr());
+    }
+
+    @Programmatic
+    @Override
+    public void setResult(Bookmark result) {
+        setResultStr(Util.asString(result));
+    }
+
+    // //////////////////////////////////////
+    
+    private String resultStr;
+
+    @javax.jdo.annotations.Column(allowsNull="true", length=JdoColumnLength.BOOKMARK, name="result")
+    @Hidden(where=Where.ALL_TABLES)
+    @Named("Result Bookmark")
+    @MemberOrder(name="Results", sequence="25")
+    @Disabled
+    public String getResultStr() {
+        return resultStr;
+    }
+
+    public void setResultStr(final String resultStr) {
+        this.resultStr = resultStr;
+    }
+
+    // //////////////////////////////////////
+
+    @ActionSemantics(Of.SAFE)
+    @MemberOrder(name="ResultStr", sequence="1")
+    @Named("Open")
+    public Object openResultObject() {
+        return Util.lookupBookmark(getResult(), bookmarkService, container);
+    }
+    public boolean hideOpenResultObject() {
+        return getResult() == null;
+    }
+
+
+    // //////////////////////////////////////
+    // exception (property)
+    // causedException (derived property)
+    // showException (associated action)
+    // //////////////////////////////////////
+
+    private String exception;
+
+    /**
+     * Stack trace of any exception that might have occurred if this interaction/transaction aborted.
+     * 
+     * <p>
+     * Not visible in the UI, but accessible 
+     * <p>
+     * Not part of the applib API, because the default implementation is not persistent
+     * and so there's no object that can be accessed to be annotated.
+     */
+    @javax.jdo.annotations.Column(allowsNull="true", length=JdoColumnLength.Interaction.EXCEPTION)
+    @Hidden
+    @Override
+    public String getException() {
+        return exception;
+    }
+
+    @Override
+    public void setException(final String exception) {
+        this.exception = Util.abbreviated(exception, JdoColumnLength.Interaction.EXCEPTION);
+    }
+    
+    
+    // //////////////////////////////////////
+    
+    @javax.jdo.annotations.NotPersistent
+    @MemberOrder(name="Results",sequence = "30")
+    @Hidden(where=Where.ALL_TABLES)
+    public boolean isCausedException() {
+        return getException() != null;
+    }
+
+    
+    // //////////////////////////////////////
+    
+    @ActionSemantics(Of.SAFE)
+    @MemberOrder(name="causedException", sequence = "1")
+    public String showException() {
+        return getException();
+    }
+    public boolean hideShowException() {
+        return !isCausedException();
+    }
+
+
+    // //////////////////////////////////////
+    // next(...) impl
+    // //////////////////////////////////////
+
+    private final Map<String, AtomicInteger> sequenceByName = Maps.newHashMap();
+
+
+
+    @Programmatic
+    @Override
+    public int next(String sequenceName) {
+        AtomicInteger next = sequenceByName.get(sequenceName);
+        if(next == null) {
+            next = new AtomicInteger(0);
+            sequenceByName.put(sequenceName, next);
+        } else {
+            next.incrementAndGet();
+        }
+        return next.get();
+    }
+
+    // //////////////////////////////////////
+    // reifyIfPossible (SPI impl)
+    // //////////////////////////////////////
+    
+    private boolean reify;
+
+    @Programmatic
+    public boolean isReify() {
+        return reify;
+    }
+    
+    @Programmatic
+    @Override
+    public void setReify(boolean reify) {
+        this.reify = reify;
+    }
+
+    // //////////////////////////////////////
+    // toString
+    // //////////////////////////////////////
+
+
+    @Override
+    public String toString() {
+        return ObjectContracts.toString(this, "startedAt,user,actionIdentifier,target,completedAt,duration,transactionId");
+    }
+
+    
+    // //////////////////////////////////////
+    
+    @javax.inject.Inject
+    private BookmarkService bookmarkService;
+    
+    @javax.inject.Inject
+    private DomainObjectContainer container;
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2463dc18/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/reifiableaction/ReifiableActionServiceJdo.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/reifiableaction/ReifiableActionServiceJdo.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/reifiableaction/ReifiableActionServiceJdo.java
new file mode 100644
index 0000000..e64b6eb
--- /dev/null
+++ b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/reifiableaction/ReifiableActionServiceJdo.java
@@ -0,0 +1,93 @@
+/**
+ *  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.
+ */
+package org.apache.isis.objectstore.jdo.applib.service.reifiableaction;
+
+import java.util.UUID;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.isis.applib.AbstractService;
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.clock.Clock;
+import org.apache.isis.applib.services.reifiableaction.ReifiableAction;
+import org.apache.isis.applib.services.reifiableaction.spi.ReifiableActionService;
+
+public class ReifiableActionServiceJdo extends AbstractService implements ReifiableActionService {
+
+    @SuppressWarnings("unused")
+    private static final Logger LOG = LoggerFactory.getLogger(ReifiableActionServiceJdo.class);
+
+    /**
+     * Creates an {@link ReifiableActionJdo}, initializing its 
+     * {@link ReifiableAction#setNature(ReifiableAction.Nature) nature} to be
+     * {@link ReifiableAction.Nature#INDIRECT rendering}.
+     */
+    @Programmatic
+    @Override
+    public ReifiableAction create() {
+        ReifiableActionJdo reifiableAction = newTransientInstance(ReifiableActionJdo.class);
+        reifiableAction.setNature(ReifiableAction.Nature.INDIRECT);
+        return reifiableAction;
+    }
+
+    @Programmatic
+    @Override
+    public void startTransaction(final ReifiableAction reifiableAction, final UUID transactionId) {
+        if(reifiableAction instanceof ReifiableActionJdo) {
+            // should be the case, since this service created the object in the #create() method
+            final ReifiableActionJdo interactionJdo = (ReifiableActionJdo) reifiableAction;
+            final UUID currentTransactionId = interactionJdo.getTransactionId();
+            if(currentTransactionId != null && !currentTransactionId.equals(transactionId)) {
+                // the logic in IsisTransaction means that any subsequent transactions within a given reifiable action
+                // should reuse the xactnId of the first transaction created within that interaction.
+                throw new IllegalStateException("Attempting to set a different transactionId on reifiable action");
+            }
+            interactionJdo.setTransactionId(transactionId);
+        }
+    }
+
+    @Programmatic
+    @Override
+    public void complete(final ReifiableAction reifiableAction) {
+        ReifiableActionJdo reifiableActionJdo = asUserInitiatedReifiedReifiableActionJdo(reifiableAction);
+        if(reifiableActionJdo == null) {
+            return;
+        }
+            
+        reifiableActionJdo.setCompletedAt(Clock.getTimeAsJavaSqlTimestamp());
+        persistIfNotAlready(reifiableActionJdo);
+    }
+
+    /**
+     * Not API, factored out from {@link ReifiableActionServiceJdoRepository}.
+     */
+    ReifiableActionJdo asUserInitiatedReifiedReifiableActionJdo(final ReifiableAction reifiableAction) {
+        if(!(reifiableAction instanceof ReifiableActionJdo)) {
+            // ought not to be the case, since this service created the object in the #create() method
+            return null;
+        }
+        if(reifiableAction.getNature() != ReifiableAction.Nature.USER_INITIATED) {
+            return null;
+        } 
+        final ReifiableActionJdo reifiableActionJdo = (ReifiableActionJdo) reifiableAction;
+        if(!reifiableActionJdo.isReify()) {
+            return null;
+        } 
+        return reifiableActionJdo;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2463dc18/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/reifiableaction/ReifiableActionServiceJdoRepository.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/reifiableaction/ReifiableActionServiceJdoRepository.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/reifiableaction/ReifiableActionServiceJdoRepository.java
new file mode 100644
index 0000000..4c30841
--- /dev/null
+++ b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/reifiableaction/ReifiableActionServiceJdoRepository.java
@@ -0,0 +1,75 @@
+/**
+ *  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.
+ */
+package org.apache.isis.objectstore.jdo.applib.service.reifiableaction;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.isis.applib.AbstractFactoryAndRepository;
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.query.QueryDefault;
+import org.apache.isis.applib.services.reifiableaction.ReifiableAction;
+import org.apache.isis.applib.services.reifiableaction.ReifiableActionContext;
+
+
+public class ReifiableActionServiceJdoRepository extends AbstractFactoryAndRepository {
+
+    @Programmatic
+    public ReifiableActionJdo findByTransactionId(final UUID transactionId) {
+        persistCurrentReifiableActionIfRequired();
+        return firstMatch(
+                new QueryDefault<ReifiableActionJdo>(ReifiableActionJdo.class, 
+                        "findByTransactionId", 
+                        "transactionId", transactionId.toString()));
+    }
+
+    @Programmatic
+    public List<ReifiableActionJdo> findCurrent() {
+        persistCurrentReifiableActionIfRequired();
+        return allMatches(
+                new QueryDefault<ReifiableActionJdo>(ReifiableActionJdo.class, "findCurrent"));
+    }
+    
+    @Programmatic
+    public List<ReifiableActionJdo> findCompleted() {
+        persistCurrentReifiableActionIfRequired();
+        return allMatches(
+                new QueryDefault<ReifiableActionJdo>(ReifiableActionJdo.class, "findCompleted"));
+    }
+
+    private void persistCurrentReifiableActionIfRequired() {
+        if(reifiableActionContext == null || reifiableActionService == null) {
+            return;
+        } 
+        final ReifiableAction reifiableAction = reifiableActionContext.getReifiableAction();
+        final ReifiableActionJdo reifiableActionJdo = reifiableActionService.asUserInitiatedReifiedReifiableActionJdo(reifiableAction);
+        if(reifiableActionJdo == null) {
+            return;
+        } 
+        persistIfNotAlready(reifiableActionJdo);
+    }
+
+    // //////////////////////////////////////
+
+    
+    @javax.inject.Inject
+    private ReifiableActionServiceJdo reifiableActionService;
+    
+    @javax.inject.Inject
+    private ReifiableActionContext reifiableActionContext;
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2463dc18/component/objectstore/jdo/jdo-applib/src/test/java/org/apache/isis/objectstore/jdo/applib/service/interaction/InteractionJdoTest_next.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/test/java/org/apache/isis/objectstore/jdo/applib/service/interaction/InteractionJdoTest_next.java b/component/objectstore/jdo/jdo-applib/src/test/java/org/apache/isis/objectstore/jdo/applib/service/interaction/InteractionJdoTest_next.java
deleted file mode 100644
index 9b7b2ba..0000000
--- a/component/objectstore/jdo/jdo-applib/src/test/java/org/apache/isis/objectstore/jdo/applib/service/interaction/InteractionJdoTest_next.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- *  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.
- */
-
-package org.apache.isis.objectstore.jdo.applib.service.interaction;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-
-import org.junit.Test;
-
-public class InteractionJdoTest_next {
-
-    @Test
-    public void test() {
-        InteractionJdo interaction = new InteractionJdo();
-        assertThat(interaction.next("foo"), is(0));
-        assertThat(interaction.next("foo"), is(1));
-        assertThat(interaction.next("bar"), is(0));
-        assertThat(interaction.next("bar"), is(1));
-        assertThat(interaction.next("foo"), is(2));
-        assertThat(interaction.next("bar"), is(2));
-        assertThat(interaction.next("bar"), is(3));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/2463dc18/component/objectstore/jdo/jdo-applib/src/test/java/org/apache/isis/objectstore/jdo/applib/service/reifiableaction/ReifiableActionJdoTest_next.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/test/java/org/apache/isis/objectstore/jdo/applib/service/reifiableaction/ReifiableActionJdoTest_next.java b/component/objectstore/jdo/jdo-applib/src/test/java/org/apache/isis/objectstore/jdo/applib/service/reifiableaction/ReifiableActionJdoTest_next.java
new file mode 100644
index 0000000..72bd939
--- /dev/null
+++ b/component/objectstore/jdo/jdo-applib/src/test/java/org/apache/isis/objectstore/jdo/applib/service/reifiableaction/ReifiableActionJdoTest_next.java
@@ -0,0 +1,43 @@
+/*
+ *  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.
+ */
+
+package org.apache.isis.objectstore.jdo.applib.service.reifiableaction;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Test;
+
+import org.apache.isis.objectstore.jdo.applib.service.reifiableaction.ReifiableActionJdo;
+
+public class ReifiableActionJdoTest_next {
+
+    @Test
+    public void test() {
+        ReifiableActionJdo raj = new ReifiableActionJdo();
+        assertThat(raj.next("foo"), is(0));
+        assertThat(raj.next("foo"), is(1));
+        assertThat(raj.next("bar"), is(0));
+        assertThat(raj.next("bar"), is(1));
+        assertThat(raj.next("foo"), is(2));
+        assertThat(raj.next("bar"), is(2));
+        assertThat(raj.next("bar"), is(3));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2463dc18/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionPanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionPanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionPanel.java
index 1ba602e..a79649a 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionPanel.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionPanel.java
@@ -33,8 +33,8 @@ import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.bookmark.BookmarkService;
 import org.apache.isis.applib.services.exceprecog.ExceptionRecognizer;
 import org.apache.isis.applib.services.exceprecog.ExceptionRecognizerComposite;
-import org.apache.isis.applib.services.interaction.Interaction;
-import org.apache.isis.applib.services.interaction.InteractionContext;
+import org.apache.isis.applib.services.reifiableaction.ReifiableAction;
+import org.apache.isis.applib.services.reifiableaction.ReifiableActionContext;
 import org.apache.isis.core.commons.authentication.MessageBroker;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.oid.Oid;
@@ -183,11 +183,11 @@ public class ActionPanel extends PanelAbstract<ActionModel> implements ActionExe
             return false;
         }
         
-        final InteractionContext interactionContext = getServicesInjector().lookupService(InteractionContext.class);
-        final Interaction interaction;
+        final ReifiableActionContext interactionContext = getServicesInjector().lookupService(ReifiableActionContext.class);
+        final ReifiableAction interaction;
         if (interactionContext != null) {
-            interaction = interactionContext.getInteraction();
-            interaction.setNature(Interaction.Nature.ACTION_INVOCATION);
+            interaction = interactionContext.getReifiableAction();
+            interaction.setNature(ReifiableAction.Nature.USER_INITIATED);
         } else {
             interaction = null;
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/2463dc18/core/applib/src/main/java/org/apache/isis/applib/annotation/Reified.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/Reified.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/Reified.java
new file mode 100644
index 0000000..c940ae6
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/Reified.java
@@ -0,0 +1,40 @@
+/*
+ *  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.
+ */
+
+package org.apache.isis.applib.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.isis.applib.services.reifiableaction.ReifiableAction;
+import org.apache.isis.applib.services.reifiableaction.spi.ReifiableActionService;
+
+/**
+ * Indicates that an action invocation should be reified as a persisted {@link ReifiableAction},
+ * (if supported by the configured {@link ReifiableActionService}).
+ */
+@Inherited
+@Target({ ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Reified {
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2463dc18/core/applib/src/main/java/org/apache/isis/applib/services/background/BackgroundTaskService.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/background/BackgroundTaskService.java b/core/applib/src/main/java/org/apache/isis/applib/services/background/BackgroundTaskService.java
index 783afc6..e1c6ffe 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/background/BackgroundTaskService.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/background/BackgroundTaskService.java
@@ -1,6 +1,6 @@
 package org.apache.isis.applib.services.background;
 
-import java.util.UUID;
+import org.apache.isis.applib.services.reifiableaction.ReifiableAction;
 
 
 /**
@@ -14,5 +14,5 @@ import java.util.UUID;
  */
 public interface BackgroundTaskService {
 
-    void execute(final ActionInvocationMemento actionInvocationMemento, final UUID transactionId, final int sequence);
+    void execute(final ActionInvocationMemento aim, final ReifiableAction reifiableAction);
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/2463dc18/core/applib/src/main/java/org/apache/isis/applib/services/interaction/Interaction.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/interaction/Interaction.java b/core/applib/src/main/java/org/apache/isis/applib/services/interaction/Interaction.java
deleted file mode 100644
index 00a7fa3..0000000
--- a/core/applib/src/main/java/org/apache/isis/applib/services/interaction/Interaction.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/**
- *  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.
- */
-package org.apache.isis.applib.services.interaction;
-
-import java.sql.Timestamp;
-
-import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.annotation.Disabled;
-import org.apache.isis.applib.clock.Clock;
-import org.apache.isis.applib.services.HasTransactionId;
-import org.apache.isis.applib.services.bookmark.Bookmark;
-import org.apache.isis.applib.services.bookmark.BookmarkService;
-import org.apache.isis.applib.services.interaction.spi.InteractionService;
-
-public interface Interaction extends HasTransactionId {
-
-    /**
-     * The user that initiated the interaction.
-     */
-    @Disabled
-    public abstract String getUser();
-    /**
-     * <b>NOT API</b>: intended to be called only by the framework.
-     * 
-     * <p>
-     * Implementation notes: set when the Isis PersistenceSession is opened.
-     */
-    public abstract void setUser(String user);
-
-    // //////////////////////////////////////
-
-    /**
-     * The date/time at which the interaction started.
-     */
-    @Disabled
-    public abstract Timestamp getTimestamp();
-    /**
-     * <b>NOT API</b>: intended to be called only by the framework.
-     * 
-     * <p>
-     * Implementation notes: set when the Isis PersistenceSession is opened.  Uses the applib {@link Clock}.
-     */
-    public abstract void setTimestamp(Timestamp startedAt);
-    
-    
-    // //////////////////////////////////////
-    
-
-    /**
-     * {@link Bookmark} of the target object (entity or service) on which this interaction was performed.
-     * 
-     * <p>
-     * Will only be populated if a {@link BookmarkService} has been configured.
-     */
-    @Disabled
-    public abstract Bookmark getTarget();
-    /**
-     * <b>NOT API</b>: intended to be called only by the framework.
-     * 
-     * <p>
-     * Implementation notes: set when the action is invoked (in the ActionInvocationFacet).
-     */
-    public abstract void setTarget(Bookmark target);
-    
-    // //////////////////////////////////////
-
-    /**
-     * If this interaction is an action invocation (as opposed to updating an object),
-     * then holds a string representation of that action, equivalent to
-     * {@link Identifier#toClassAndNameIdentityString()}.
-     * 
-     * <p>
-     * Returns <tt>null</tt> otherwise.
-     */
-    @Disabled
-    public abstract String getActionIdentifier();
-
-    /**
-     * <b>NOT API</b>: intended to be called only by the framework.
-     * 
-     * <p>
-     * Implementation notes: set when the action is invoked (in the ActionInvocationFacet).
-     */
-    public abstract void setActionIdentifier(String actionIdentifier);
-    
-    // //////////////////////////////////////
-
-    /**
-     * A human-friendly description of the class of the target object.
-     */
-    @Disabled
-    public abstract String getTargetClass();
-
-    /**
-     * <b>NOT API</b>: intended to be called only by the framework.
-     * 
-     * <p>
-     * Implementation notes: set when the action is invoked (in the ActionInvocationFacet).
-     */
-    public abstract void setTargetClass(String targetClass);
-
-    // //////////////////////////////////////
-    
-    /**
-     * The human-friendly name of the action invoked on the target object.
-     */
-    @Disabled
-    public abstract String getTargetAction();
-    
-    /**
-     * <b>NOT API</b>: intended to be called only by the framework.
-     * 
-     * <p>
-     * Implementation notes: set when the action is invoked (in the ActionInvocationFacet).
-     */
-    public abstract void setTargetAction(String targetAction);
-    
-    // //////////////////////////////////////
-    
-    /**
-     * A human-friendly description of the arguments passed to this interaction (action invocation).
-     */
-    public String getArguments();
-    
-    /**
-     * <b>NOT API</b>: intended to be called only by the framework.
-     * 
-     * <p>
-     * Implementation notes: set when the action is invoked (in the ActionInvocationFacet).
-     */
-    public void setArguments(final String arguments);
-
-    // //////////////////////////////////////
-    
-    /**
-     * The nature of this interaction, for example whether as the result of an 
-     * {@link #ACTION_INVOCATION explicit action invocation} on the part of the user, or merely as
-     * a side-effect of {@link #RENDERING re-rendering} an entity, eg for a viewer (such as the
-     * Wicket viewer) that uses the <a href="http://en.wikipedia.org/wiki/Post/Redirect/Get">post/redirect/get</a>
-     * to avoid duplicate submissions.
-     * 
-     * <p>
-     * The Isis implementations uses this field as to a hint as to whether to populate the interaction's
-     * {@link Interaction#setActionIdentifier(String) action identifier} and related properties.  The expectation 
-     * is that implementations of {@link InteractionService} will only persist interactions that were explicitly started
-     * by the user.
-     */
-    public static enum Nature {
-        /**
-         * Indicates that the {@link Interaction} has occurred as the result of an explicit action invocation
-         * on the part of the user.
-         */
-        ACTION_INVOCATION,
-        RENDERING
-    }
-
-    public Nature getNature();
-    
-    /**
-     * <b>NOT API</b>: intended to be called only by the framework.
-     */
-    public void setNature(final Nature nature);
-
-    
-    // //////////////////////////////////////
-
-    @Disabled
-    public String getException();
-
-    /**
-     * <b>NOT API</b>: intended to be called only by the framework.
-     */
-    public void setException(String stackTrace);
-    
-    // //////////////////////////////////////
-
-    
-    /**
-     * A {@link Bookmark} to the object returned by the action.
-     * 
-     * <p>
-     * If the action returned either a domain entity or a simple value (and did not throw an
-     * exception) then this object is provided here.  
-     * 
-     * <p>
-     * For <tt>void</tt> methods and for actions returning collections, the value
-     * will be <tt>null</tt>.
-     */
-    public Bookmark getResult();
-    
-    /**
-     * <b>NOT API</b>: intended to be called only by the framework.
-     */
-    public void setResult(Bookmark resultBookmark);
-
-    
-    // //////////////////////////////////////
-
-    
-    /**
-     * Generates numbers in a named sequence
-     * 
-     * <p>
-     * Used to support <tt>BackgroundTaskServiceJdo</tt> and <tt>PublishingServiceJdo</tt> implementations whose
-     * persisted entities are uniquely identified by a ({@link #getTransactionId() transactionId}, <tt>sequence</tt>)
-     * tuple.
-     */
-    public int next(final String sequenceName);
-    
-}