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 11:46:18 UTC

[3/3] git commit: ISIS-657, ISIS-660, ISIS-661, ISIS-662, ISIS-663, ISIS-667, ISIS-668, ISIS-670: JDO services

ISIS-657,ISIS-660,ISIS-661,ISIS-662,ISIS-663,ISIS-667,ISIS-668,ISIS-670: JDO services

ISIS-657:
- appsettings / usersettings entities also now use "Isis" as prefix to table names

ISIS-660:
- renamed InteractionFactory to InteractionService
- renamed InteractionRepository to InteractionServiceJdoRepository
- InteractionDefault and InteractionJdo now have a next() method, to create sequences of numbers
  (as used to generate the PKs for PublishedEventJdo and BackgroundTaskJdo, see below)
- Interaction#startedAt renamed to Interaction#timestamp (and #startedAt now a derived property)
- Interaction now defines a #transactionId property
- IsisTransaction now picks up its transactionId from passed-in Interaction object (if available)
  - and defers to Interaction for generation of next pub/sub event sequence if it can (else previous behaviour)
- IsisTransaction#guidId renamed to #transactionId


ISIS-661: (background service mementos, background task service)
- renamed BackgroundTaskContributions to BackgroundTaskServiceJdoContributions
- renamed BackgroundTaskRepository to BackgroundTaskServiceJdoRepository

ISIS-662: published events contributions
- renamed PublishedEventRepository to PublishingServiceJdoRepository
- renamed PublishedEventContributions to PublishingServiceJdoContributions


ISIS-663: audit entry contributions
- rename AuditEntryCountributions to AuditingServiceJdoContributions
- rename AuditEntryRepository to AuditingServiceJdoRepository

ISIS-667:
- added JdoColumnLength as central location for standard column lengths of JDO entities
- renamed AuditEntry to AuditEntryJdo
- renamed PublishedEvent to PublishedEventJdo
- changed PK for PublishedEventJdo entity to be application-defined: (transactionId,sequence)
- change to datatype of some PublishedEventJDO entities
- changed PK for BackgroundTaskJdo entity to be application-defined: (transactionId,sequence)
- factored out Util class for JDO entities
- renamed UserSettingPrimaryKey to UserSettingJdoPK

ISIS-668:
- improvements to ServicesInstallerFromConfiguration
- improved formatting of isis.properties in the todo app & simple app

ISIS-670:
- removed AuditingService, AuditingService2 APIs
- introduced replacement AuditingService3 API


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

Branch: refs/heads/master
Commit: 49c7c05dd57be56f6d272329c3a4693a996d8a09
Parents: 2645b09
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Fri Jan 31 10:45:56 2014 +0000
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Fri Jan 31 10:45:56 2014 +0000

----------------------------------------------------------------------
 .../jdo/applib/service/JdoColumnLength.java     |  78 +++++
 .../service/audit/AuditEntryContributions.java  |  47 ---
 .../jdo/applib/service/audit/AuditEntryJdo.java | 142 ++++----
 .../service/audit/AuditEntryRepository.java     |  44 ---
 .../service/audit/AuditingServiceJdo.java       |  23 +-
 .../audit/AuditingServiceJdoContributions.java  |  46 +++
 .../audit/AuditingServiceJdoRepository.java     |  44 +++
 .../background/BackgroundTaskContributions.java |  46 ---
 .../service/background/BackgroundTaskJdo.java   | 250 ++++++++------
 .../service/background/BackgroundTaskJdoPK.java | 102 ++++++
 .../background/BackgroundTaskRepository.java    |  47 ---
 .../background/BackgroundTaskServiceJdo.java    |   5 +-
 .../BackgroundTaskServiceJdoContributions.java  |  46 +++
 .../BackgroundTaskServiceJdoRepository.java     |  47 +++
 .../service/interaction/InteractionJdo.java     | 344 ++++++++++---------
 .../interaction/InteractionRepository.java      |  72 ----
 .../interaction/InteractionServiceJdo.java      |  18 +-
 .../InteractionServiceJdoRepository.java        |  72 ++++
 .../jdo/applib/service/interaction/Util.java    |  68 ++++
 .../applib/service/publish/PublishedEvent.java  | 270 ---------------
 .../publish/PublishedEventContributions.java    |  47 ---
 .../service/publish/PublishedEventJdo.java      | 310 +++++++++++++++++
 .../service/publish/PublishedEventJdoPK.java    | 102 ++++++
 .../publish/PublishedEventRepository.java       |  71 ----
 .../service/publish/PublishingServiceJdo.java   |   8 +-
 .../PublishingServiceJdoContributions.java      |  47 +++
 .../publish/PublishingServiceJdoRepository.java |  71 ++++
 .../service/settings/ApplicationSettingJdo.java |  12 +-
 .../settings/ApplicationSettingsServiceJdo.java |   1 -
 .../applib/service/settings/UserSettingJdo.java |  18 +-
 .../service/settings/UserSettingJdoPK.java      |  90 +++++
 .../service/settings/UserSettingPrimaryKey.java |  90 -----
 .../interaction/InteractionJdoTest_next.java    |  41 +++
 .../isis/applib/services/HasTransactionId.java  |   2 +
 .../applib/services/audit/AuditingService3.java |   8 +-
 .../background/BackgroundTaskService.java       |   6 +-
 .../services/interaction/Interaction.java       |  28 +-
 .../interaction/InteractionDefault.java         |  46 ++-
 .../interaction/spi/InteractionFactory.java     |  55 ---
 .../interaction/spi/InteractionService.java     |  55 +++
 .../applib/services/publish/EventMetadata.java  |  31 +-
 .../InteractionDefaultTest_next.java            |  41 +++
 .../actions/invoke/ActionInvocationFacet.java   |  17 +-
 ...shingServiceWithDefaultPayloadFactories.java |   6 +-
 .../ServicesInstallerFromConfiguration.java     |  55 +--
 .../background/BackgroundServiceDefault.java    |  14 +-
 .../system/persistence/PersistenceSession.java  |  13 +-
 .../system/transaction/IsisTransaction.java     |  87 +++--
 .../transaction/IsisTransactionManager.java     |  21 +-
 .../BackgroundServiceDefaultTest_execute.java   |  37 +-
 .../system/transaction/IsisTransactionTest.java |   6 +-
 .../src/main/java/webapp/admin/Admin.java       |  26 +-
 .../src/main/webapp/WEB-INF/isis.properties     |  59 ++--
 .../src/main/webapp/WEB-INF/isis.properties     |  63 +++-
 54 files changed, 2054 insertions(+), 1341 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/49c7c05d/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/JdoColumnLength.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/JdoColumnLength.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/JdoColumnLength.java
new file mode 100644
index 0000000..598a431
--- /dev/null
+++ b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/JdoColumnLength.java
@@ -0,0 +1,78 @@
+/*
+ *
+ *  Copyright 2012-2014 Eurocommercial Properties NV
+ *
+ *
+ *  Licensed 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;
+
+public final class JdoColumnLength {
+
+    private JdoColumnLength() {
+    }
+
+    public final static int TRANSACTION_ID = 36;
+    // ie OID str
+    public final static int BOOKMARK = 255; 
+    public static final int ACTION_IDENTIFIER = 255;
+    public static final int USER_NAME = 50;
+    
+    public static final int DESCRIPTION = 254;
+
+    public static final class SettingAbstract {
+        private SettingAbstract(){}
+        
+        public static final int SETTING_KEY = 128;
+        public static final int SETTING_TYPE = 20;
+        public static final int VALUE_RAW = 255;
+    }
+
+    public static final class Interaction {
+        private Interaction() {
+        }
+        public final static int TARGET_CLASS = 50;
+        public final static int TARGET_ACTION = 50;
+        public final static int ARGUMENTS = 1024;
+        public final static int NOTES = 1024;
+        public final static int EXCEPTION = 2000;
+    }
+
+    public static final class BackgroundTask {
+
+        private BackgroundTask() {
+        }
+        
+        public static final int MEMENTO = 1024;
+    }
+    
+    public static final class AuditEntry {
+
+        private AuditEntry() {
+        }
+        public static final int PROPERTY_ID = 50;
+        public static final int PROPERTY_VALUE = 255;
+    }
+    
+    public static final class PublishedEvent {
+
+        private PublishedEvent() {
+        }
+        
+        public static final int TITLE = 50;
+        public static final int EVENT_TYPE = 20;
+        public static final int STATE = 20;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/49c7c05d/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditEntryContributions.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditEntryContributions.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditEntryContributions.java
deleted file mode 100644
index 8db6c42..0000000
--- a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditEntryContributions.java
+++ /dev/null
@@ -1,47 +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.audit;
-
-import java.util.List;
-
-import org.apache.isis.applib.AbstractFactoryAndRepository;
-import org.apache.isis.applib.annotation.ActionSemantics;
-import org.apache.isis.applib.annotation.Render;
-import org.apache.isis.applib.annotation.ActionSemantics.Of;
-import org.apache.isis.applib.annotation.NotContributed;
-import org.apache.isis.applib.annotation.NotContributed.As;
-import org.apache.isis.applib.annotation.Render.Type;
-import org.apache.isis.applib.annotation.NotInServiceMenu;
-import org.apache.isis.applib.services.HasTransactionId;
-
-
-public class AuditEntryContributions extends AbstractFactoryAndRepository {
-
-    @ActionSemantics(Of.SAFE)
-    @NotInServiceMenu
-    @NotContributed(As.ACTION)
-    @Render(Type.EAGERLY)
-    public List<AuditEntryJdo> auditEntries(final HasTransactionId hasTransactionId) {
-        return auditEntryRepository.findByTransactionId(hasTransactionId.getTransactionId());
-    }
-    
-    // //////////////////////////////////////
-
-    @javax.inject.Inject
-    private AuditEntryRepository auditEntryRepository;
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/49c7c05d/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 baa739f..fa80985 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
@@ -23,6 +23,8 @@ import java.text.SimpleDateFormat;
 import java.util.UUID;
 
 import javax.jdo.annotations.IdentityType;
+import javax.jdo.annotations.Index;
+import javax.jdo.annotations.Indices;
 
 import org.apache.isis.applib.DomainObjectContainer;
 import org.apache.isis.applib.annotation.ActionSemantics;
@@ -33,14 +35,16 @@ import org.apache.isis.applib.annotation.Immutable;
 import org.apache.isis.applib.annotation.MemberGroupLayout;
 import org.apache.isis.applib.annotation.MemberOrder;
 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.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.util.TitleBuffer;
+import org.apache.isis.objectstore.jdo.applib.service.JdoColumnLength;
+import org.apache.isis.objectstore.jdo.applib.service.interaction.Util;
 
 @javax.jdo.annotations.PersistenceCapable(
         identityType=IdentityType.DATASTORE,
@@ -52,12 +56,21 @@ import org.apache.isis.applib.util.TitleBuffer;
     @javax.jdo.annotations.Query(
             name="findByTransactionId", language="JDOQL",  
             value="SELECT "
-                    + "FROM org.apache.isis.objectstore.jdo.applib.service.audit.AuditEntry "
+                    + "FROM org.apache.isis.objectstore.jdo.applib.service.audit.AuditEntryJdo "
                     + "WHERE transactionId == :transactionId")
 })
+@Indices({
+    @Index(name="IsisAuditEntry_ak", unique="true", 
+            columns={
+                @javax.jdo.annotations.Column(name="transactionId"),
+                @javax.jdo.annotations.Column(name="target"),
+                @javax.jdo.annotations.Column(name="propertyId")
+                })
+})
 @Immutable
 @Named("Audit Entry")
-@MemberGroupLayout(left={"When/Who","Target","Values"})
+@ObjectType("IsisAuditEntry")
+@MemberGroupLayout(left={"Identifiers","Target","Detail"})
 public class AuditEntryJdo implements HasTransactionId {
 
     
@@ -70,33 +83,21 @@ public class AuditEntryJdo implements HasTransactionId {
         return buf.toString();
     }
     
-    
-    // //////////////////////////////////////
-
-    private Timestamp timestamp;
-
-    @javax.jdo.annotations.Column(allowsNull="false")
-    @MemberOrder(name="When/Who",sequence = "1")
-    public Timestamp getTimestamp() {
-        return timestamp;
-    }
-
-    public void setTimestamp(final Timestamp timestamp) {
-        this.timestamp = timestamp;
-    }
-
-    
     // //////////////////////////////////////
     
     private UUID transactionId;
 
     /**
-     * The unique identifier (a GUID) of the transaction of the {@link Interaction} that gave rise to this
-     * audit entry.
+     * The unique identifier (a GUID) of the transaction in which this audit entry was persisted.
+     * 
+     * <p>
+     * The combination of ({@link #getTransactionId() transactionId}, {@link #getTargetStr() target}, {@link #getPropertyId() propertyId} ) makes up the
+     * (non-enforced) alternative key.
      */
-    @javax.jdo.annotations.Column(allowsNull="true", length=36)
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.TRANSACTION_ID)
     @TypicalLength(36)
-    @MemberOrder(name="When/Who",sequence = "20")
+    @MemberOrder(name="Identifiers",sequence = "10")
+    @Hidden(where=Where.PARENTED_TABLES)
     @Disabled
     @Override
     public UUID getTransactionId() {
@@ -108,129 +109,142 @@ public class AuditEntryJdo implements HasTransactionId {
         this.transactionId = transactionId;
     }
 
+
+    // //////////////////////////////////////
+    // user (property)
     // //////////////////////////////////////
 
-    
     private String user;
 
-    @javax.jdo.annotations.Column(allowsNull="false", length=50)
-    @MemberOrder(name="When/Who",sequence = "2")
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.USER_NAME)
+    @Hidden(where=Where.PARENTED_TABLES)
+    @MemberOrder(name="Identifiers",sequence = "20")
     public String getUser() {
         return user;
     }
 
     public void setUser(final String user) {
-        this.user = abbreviated(user, 50);
+        this.user = user;
     }
     
+
+    // //////////////////////////////////////
+    // timestamp (property)
+    // //////////////////////////////////////
+
+    private Timestamp timestamp;
+
+    @javax.jdo.annotations.Column(allowsNull="false")
+    @Hidden(where=Where.PARENTED_TABLES)
+    @MemberOrder(name="Identifiers",sequence = "30")
+    public Timestamp getTimestamp() {
+        return timestamp;
+    }
+
+    public void setTimestamp(final Timestamp timestamp) {
+        this.timestamp = timestamp;
+    }
+
     
+
+
     // //////////////////////////////////////
     // target (property)
+    // openTargetObject (action)
     // //////////////////////////////////////
 
     @Programmatic
     public Bookmark getTarget() {
-        return new Bookmark(getTargetStr());
+        return Util.bookmarkFor(getTargetStr());
     }
     
     @Programmatic
     public void setTarget(Bookmark target) {
-        setTargetStr(target.toString());
+        setTargetStr(Util.asString(target));
     }
 
+    // //////////////////////////////////////
+    
     private String targetStr;
 
-    @javax.jdo.annotations.Column(allowsNull="false", length=255, name="target")
-    @Named("Target Bookmark")
-    @Hidden(where=Where.ALL_TABLES)
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.BOOKMARK, name="target")
+    @Named("Target")
+    //@Hidden(where=Where.OBJECT_FORMS)
     @MemberOrder(name="Target", sequence="3")
     public String getTargetStr() {
         return targetStr;
     }
 
     public void setTargetStr(final String targetStr) {
-        this.targetStr = abbreviated(targetStr, 255);
+        this.targetStr = targetStr;
     }
 
     
     // //////////////////////////////////////
-    // openTargetObject (action)
-    // //////////////////////////////////////
 
     @ActionSemantics(Of.SAFE)
     @MemberOrder(name="TargetStr", sequence="1")
     @Named("Open")
     public Object openTargetObject() {
-        return lookupBookmark(getTarget());
+        return Util.lookupBookmark(getTarget(), bookmarkService, container);
     }
     public boolean hideOpenTargetObject() {
-        return getTargetStr() == null;
+        return getTarget() == null;
     }
     
 
     // //////////////////////////////////////
+    // propertyId (property)
+    // //////////////////////////////////////
     
     private String propertyId;
     
-    @javax.jdo.annotations.Column(allowsNull="true", length=50)
+    @javax.jdo.annotations.Column(allowsNull="true", length=JdoColumnLength.AuditEntry.PROPERTY_ID)
     @MemberOrder(name="Target",sequence = "5")
     public String getPropertyId() {
         return propertyId;
     }
     
     public void setPropertyId(final String propertyId) {
-        this.propertyId = abbreviated(propertyId,50);
+        this.propertyId = Util.abbreviated(propertyId, JdoColumnLength.AuditEntry.PROPERTY_ID);
     }
     
     
     // //////////////////////////////////////
+    // preValue (property)
+    // //////////////////////////////////////
 
     private String preValue;
 
-    @javax.jdo.annotations.Column(allowsNull="true", length=255)
-    @MemberOrder(name="Values",sequence = "6")
+    @javax.jdo.annotations.Column(allowsNull="true", length=JdoColumnLength.AuditEntry.PROPERTY_VALUE)
+    @MemberOrder(name="Detail",sequence = "6")
     public String getPreValue() {
         return preValue;
     }
 
     public void setPreValue(final String preValue) {
-        this.preValue = abbreviated(preValue,255);
+        this.preValue = Util.abbreviated(preValue, JdoColumnLength.AuditEntry.PROPERTY_VALUE);
     }
     
+    
+    // //////////////////////////////////////
+    // postValue (property)
     // //////////////////////////////////////
 
     private String postValue;
 
-    @javax.jdo.annotations.Column(allowsNull="true", length=255)
-    @MemberOrder(name="Values",sequence = "7")
+    @javax.jdo.annotations.Column(allowsNull="true", length=JdoColumnLength.AuditEntry.PROPERTY_VALUE)
+    @MemberOrder(name="Detail",sequence = "7")
     public String getPostValue() {
         return postValue;
     }
 
     public void setPostValue(final String postValue) {
-        this.postValue = abbreviated(postValue, 255);
+        this.postValue = Util.abbreviated(postValue, JdoColumnLength.AuditEntry.PROPERTY_VALUE);
     }
     
     // //////////////////////////////////////
-
-    private Object lookupBookmark(Bookmark bookmark) {
-        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;
-        }
-    }
-
-    private static String abbreviated(final String str, final int maxLength) {
-        return str != null? (str.length() < maxLength ? str : str.substring(0, maxLength - 3) + "..."): null;
-    }
-    
+    // Injected services
     // //////////////////////////////////////
 
 

http://git-wip-us.apache.org/repos/asf/isis/blob/49c7c05d/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditEntryRepository.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditEntryRepository.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditEntryRepository.java
deleted file mode 100644
index f561326..0000000
--- a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditEntryRepository.java
+++ /dev/null
@@ -1,44 +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.audit;
-
-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;
-
-public class AuditEntryRepository extends AbstractFactoryAndRepository {
-    
-    @Programmatic
-    public List<AuditEntryJdo> listAll() {
-        return allInstances(AuditEntryJdo.class);
-    }
-    
-    @Programmatic
-    public List<AuditEntryJdo> findByTransactionId(final UUID transactionId) {
-        return allMatches(
-                new QueryDefault<AuditEntryJdo>(AuditEntryJdo.class, 
-                        "findByTransactionId", 
-                        "transactionId", transactionId));
-    }
-
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/49c7c05d/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditingServiceJdo.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditingServiceJdo.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditingServiceJdo.java
index 50a59c8..a1b93ea 100644
--- a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditingServiceJdo.java
+++ b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditingServiceJdo.java
@@ -18,26 +18,24 @@
  */
 package org.apache.isis.objectstore.jdo.applib.service.audit;
 
+import java.util.UUID;
+
 import org.apache.isis.applib.AbstractFactoryAndRepository;
 import org.apache.isis.applib.annotation.Programmatic;
-import org.apache.isis.applib.services.HasTransactionId;
 import org.apache.isis.applib.services.audit.AuditingService3;
 import org.apache.isis.applib.services.bookmark.Bookmark;
-import org.apache.isis.applib.services.interaction.Interaction;
-import org.apache.isis.applib.services.interaction.InteractionContext;
 
 public class AuditingServiceJdo extends AbstractFactoryAndRepository implements AuditingService3 {
 
     @Programmatic
-    public void audit(java.sql.Timestamp timestamp, String user, Bookmark target, String propertyId, String preValue, String postValue) {
+    public void audit(
+            final UUID transactionId, final Bookmark target, final String propertyId, 
+            final String preValue, final String postValue, 
+            final String user, final java.sql.Timestamp timestamp) {
         AuditEntryJdo auditEntry = newTransientInstance(AuditEntryJdo.class);
         auditEntry.setTimestamp(timestamp);
         auditEntry.setUser(user);
-        Interaction interaction = this.interactionContext.getInteraction();
-        if(interaction instanceof HasTransactionId) {
-            HasTransactionId hasTransactionId = (HasTransactionId) interaction;
-            auditEntry.setTransactionId(hasTransactionId.getTransactionId());
-        }
+        auditEntry.setTransactionId(transactionId);
         auditEntry.setTarget(target);
         auditEntry.setPropertyId(propertyId);
         auditEntry.setPreValue(preValue);
@@ -45,11 +43,4 @@ public class AuditingServiceJdo extends AbstractFactoryAndRepository implements
         persistIfNotAlready(auditEntry);
     }
 
-    
-    // //////////////////////////////////////
-
-    
-    @javax.inject.Inject
-    private InteractionContext interactionContext;
-    
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/49c7c05d/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditingServiceJdoContributions.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditingServiceJdoContributions.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditingServiceJdoContributions.java
new file mode 100644
index 0000000..7804391
--- /dev/null
+++ b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditingServiceJdoContributions.java
@@ -0,0 +1,46 @@
+/**
+ *  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.audit;
+
+import java.util.List;
+
+import org.apache.isis.applib.AbstractService;
+import org.apache.isis.applib.annotation.ActionSemantics;
+import org.apache.isis.applib.annotation.ActionSemantics.Of;
+import org.apache.isis.applib.annotation.NotContributed;
+import org.apache.isis.applib.annotation.NotContributed.As;
+import org.apache.isis.applib.annotation.NotInServiceMenu;
+import org.apache.isis.applib.annotation.Render;
+import org.apache.isis.applib.annotation.Render.Type;
+import org.apache.isis.applib.services.HasTransactionId;
+
+public class AuditingServiceJdoContributions extends AbstractService {
+
+    @ActionSemantics(Of.SAFE)
+    @NotInServiceMenu
+    @NotContributed(As.ACTION)
+    @Render(Type.EAGERLY)
+    public List<AuditEntryJdo> auditEntries(final HasTransactionId hasTransactionId) {
+        return auditEntryRepository.findByTransactionId(hasTransactionId.getTransactionId());
+    }
+    
+    // //////////////////////////////////////
+
+    @javax.inject.Inject
+    private AuditingServiceJdoRepository auditEntryRepository;
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/49c7c05d/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditingServiceJdoRepository.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditingServiceJdoRepository.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditingServiceJdoRepository.java
new file mode 100644
index 0000000..701a29c
--- /dev/null
+++ b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditingServiceJdoRepository.java
@@ -0,0 +1,44 @@
+/*
+ *  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.audit;
+
+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;
+
+public class AuditingServiceJdoRepository extends AbstractFactoryAndRepository {
+    
+    @Programmatic
+    public List<AuditEntryJdo> listAll() {
+        return allInstances(AuditEntryJdo.class);
+    }
+    
+    @Programmatic
+    public List<AuditEntryJdo> findByTransactionId(final UUID transactionId) {
+        return allMatches(
+                new QueryDefault<AuditEntryJdo>(AuditEntryJdo.class, 
+                        "findByTransactionId", 
+                        "transactionId", transactionId));
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/49c7c05d/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskContributions.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskContributions.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskContributions.java
deleted file mode 100644
index 2461fe7..0000000
--- a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskContributions.java
+++ /dev/null
@@ -1,46 +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.background;
-
-import java.util.List;
-
-import org.apache.isis.applib.AbstractFactoryAndRepository;
-import org.apache.isis.applib.annotation.ActionSemantics;
-import org.apache.isis.applib.annotation.Render;
-import org.apache.isis.applib.annotation.ActionSemantics.Of;
-import org.apache.isis.applib.annotation.NotContributed;
-import org.apache.isis.applib.annotation.NotContributed.As;
-import org.apache.isis.applib.annotation.NotInServiceMenu;
-import org.apache.isis.applib.annotation.Render.Type;
-import org.apache.isis.applib.services.HasTransactionId;
-
-
-public class BackgroundTaskContributions extends AbstractFactoryAndRepository {
-
-    @ActionSemantics(Of.SAFE)
-    @NotInServiceMenu
-    @NotContributed(As.ACTION)
-    @Render(Type.EAGERLY)
-    public List<BackgroundTaskJdo> backgroundTasks(final HasTransactionId hasTransactionId) {
-        return backgroundTaskRepository.findByTransactionId(hasTransactionId.getTransactionId());
-    }
-
-    // //////////////////////////////////////
-
-    @javax.inject.Inject
-    private BackgroundTaskRepository backgroundTaskRepository;
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/49c7c05d/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 ca67b5b..105fab1 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
@@ -17,42 +17,42 @@
 package org.apache.isis.objectstore.jdo.applib.service.background;
 
 import java.math.BigDecimal;
-import java.math.RoundingMode;
 import java.sql.Timestamp;
 import java.util.UUID;
 
 import javax.inject.Inject;
 import javax.jdo.annotations.IdentityType;
+import javax.jdo.annotations.NotPersistent;
 
 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.Disabled;
+import org.apache.isis.applib.annotation.ActionSemantics.Of;
 import org.apache.isis.applib.annotation.Hidden;
+import org.apache.isis.applib.annotation.Immutable;
 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.annotation.ActionSemantics.Of;
 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.InteractionFactory;
 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;
 
 
 @javax.jdo.annotations.PersistenceCapable(
-        identityType=IdentityType.DATASTORE, 
-        table="IsisBackgroundTask")
-@javax.jdo.annotations.DatastoreIdentity(
-        strategy=javax.jdo.annotations.IdGeneratorStrategy.IDENTITY,
-         column="id")
+        identityType=IdentityType.APPLICATION, 
+        table="IsisBackgroundTask",
+        objectIdClass=BackgroundTaskJdoPK.class)
 @javax.jdo.annotations.Queries( {
     @javax.jdo.annotations.Query(
             name="findByTransactionId", language="JDOQL",  
@@ -60,44 +60,73 @@ import org.apache.isis.applib.util.ObjectContracts;
                     + "FROM org.apache.isis.objectstore.jdo.applib.service.background.BackgroundTaskJdo "
                     + "WHERE transactionId == :transactionId")
 })
+@ObjectType("IsisBackgroundTask")
 @Named("Background Task")
 @MemberGroupLayout(
         columnSpans={6,0,6}, 
-        left={"Target"},
-        right={"Identifiers","Timings"})
+        left={"Identifiers","Timings"},
+        right={"Detail"})
+@Immutable
 public class BackgroundTaskJdo implements HasTransactionId {
 
     @SuppressWarnings("unused")
     private static final Logger LOG = LoggerFactory.getLogger(BackgroundTaskJdo.class);
 
-    
+
+    // //////////////////////////////////////
+    // transactionId (property)
     // //////////////////////////////////////
 
-    private String actionIdentifier;
     
+    private UUID transactionId;
+
     /**
-     * The identifier of the action that this background task will/has run.
+     * The unique identifier (a GUID) of the transaction in which this background task was persisted.
      * 
      * <p>
-     * This information is also available within the {@link #getMemento()}, but is redundantly stored here also
-     * to enable analytics.
+     * The combination of ({@link #getTransactionId() transactionId}, {@link #getSequence() sequence}) makes up the
+     * primary key.
      */
-    @javax.jdo.annotations.Column(allowsNull="false", length=255)
-    @Title(sequence="1")
-    @TypicalLength(60)
-    @Hidden(where=Where.ALL_TABLES)
-    @MemberOrder(name="Identifiers",sequence = "11")
-    @Disabled
-    public String getActionIdentifier() {
-        return actionIdentifier;
+    @javax.jdo.annotations.PrimaryKey
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.TRANSACTION_ID)
+    @TypicalLength(36)
+    @Hidden(where=Where.PARENTED_TABLES)
+    @MemberOrder(name="Identifiers",sequence = "10")
+    @Override
+    public UUID getTransactionId() {
+        return transactionId;
     }
 
-    public void setActionIdentifier(final String actionIdentifier) {
-        this.actionIdentifier = actionIdentifier;
+    @Override
+    public void setTransactionId(final UUID transactionId) {
+        this.transactionId = transactionId;
     }
 
-    
-    
+
+    // //////////////////////////////////////
+    // sequence (property)
+    // //////////////////////////////////////
+
+    private int sequence;
+
+    /**
+     * The 0-based additional identifier of a published event within the given {@link #getTransactionId() transaction}.
+     * 
+     * <p>
+     * The combination of ({@link #getTransactionId() transactionId}, {@link #getSequence() sequence}) makes up the
+     * primary key.
+     */
+    @javax.jdo.annotations.PrimaryKey
+    @MemberOrder(name="Identifiers", sequence = "20")
+    public int getSequence() {
+        return sequence;
+    }
+
+    public void setSequence(final int sequence) {
+        this.sequence = sequence;
+    }
+
+
     // //////////////////////////////////////
     // user (property)
     // //////////////////////////////////////
@@ -108,10 +137,10 @@ public class BackgroundTaskJdo implements HasTransactionId {
      * The user that invoked the initial interaction that gave rise to this background task, and also the credentials
      * with which the task will/has run.
      */
-    @javax.jdo.annotations.Column(allowsNull="false", length=50)
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.USER_NAME)
     @Title(sequence="2", prepend=", ")
-    @MemberOrder(name="Identifiers", sequence = "5")
-    @Disabled
+    @MemberOrder(name="Identifiers", sequence = "30")
+    @Hidden(where=Where.PARENTED_TABLES)
     public String getUser() {
         return user;
     }
@@ -121,46 +150,52 @@ public class BackgroundTaskJdo implements HasTransactionId {
     }
 
 
-
-
+    
     // //////////////////////////////////////
-    // memento (property)
+    // timestamp (property)
     // //////////////////////////////////////
-    
-    private String memento;
-    
-    @javax.jdo.annotations.Column(allowsNull="false", length=1024)
-    @MultiLine(numberOfLines=20)
-    @Hidden(where=Where.ALL_TABLES)
-    @MemberOrder(name="Target",sequence = "4")
-    @Disabled
-    public String getMemento() {
-        return memento;
+
+    private Timestamp timestamp;
+
+    /**
+     * The date/time at which this background task was created.
+     */
+    @javax.jdo.annotations.Persistent
+    @javax.jdo.annotations.Column(allowsNull="false")
+    @MemberOrder(name="Identifiers", sequence = "40")
+    @Hidden(where=Where.PARENTED_TABLES)
+    public Timestamp getTimestamp() {
+        return timestamp;
     }
-    
-    public void setMemento(final String memento) {
-        this.memento = memento;
+
+    public void setTimestamp(final Timestamp createdAt) {
+        this.timestamp = createdAt;
     }
-    
-    
-    
+
+
+
+
     // //////////////////////////////////////
     // target (property)
+    // openTargetObject (action)
     // //////////////////////////////////////
 
     @Programmatic
     public Bookmark getTarget() {
-        return new Bookmark(getTargetStr());
+        return Util.bookmarkFor(getTargetStr());
     }
     
     @Programmatic
     public void setTarget(Bookmark target) {
-        setTargetStr(target.toString());
+        setTargetStr(Util.asString(target));
     }
 
+    // //////////////////////////////////////
+    
     private String targetStr;
-    @javax.jdo.annotations.Column(allowsNull="false", length=255, name="target")
-    @Hidden
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.BOOKMARK, name="target")
+    @Named("Target")
+    @MemberOrder(name="Detail", sequence="10")
     public String getTargetStr() {
         return targetStr;
     }
@@ -169,39 +204,61 @@ public class BackgroundTaskJdo implements HasTransactionId {
         this.targetStr = targetStr;
     }
 
-
-    
-    // //////////////////////////////////////
-    // targetObject (derived property)
     // //////////////////////////////////////
 
     @ActionSemantics(Of.SAFE)
-    @MemberOrder(name="Target", sequence="3")
-    @Named("Object")
-    public Object getTargetObject() {
-        return bookmarkService.lookup(getTarget());
+    @MemberOrder(name="TargetStr", sequence="1")
+    @Named("Open")
+    public Object openTargetObject() {
+        return Util.lookupBookmark(getTarget(), bookmarkService, container);
+    }
+    public boolean hideOpenTargetObject() {
+        return getTarget() == null;
     }
 
-
+    
     // //////////////////////////////////////
-    // createdAt (property)
+    // actionIdentifier (property)
     // //////////////////////////////////////
 
-    private Timestamp createdAt;
-
+    private String actionIdentifier;
+    
     /**
-     * The date/time at which this background task was created.
+     * The identifier of the action that this background task will/has run.
+     * 
+     * <p>
+     * This information is also available within the {@link #getMemento()}, but is redundantly stored here also
+     * to enable analytics.
      */
-    @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(allowsNull="false")
-    @MemberOrder(name="Timings", sequence = "3")
-    @Disabled
-    public Timestamp getCreatedAt() {
-        return createdAt;
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.ACTION_IDENTIFIER)
+    @Title(sequence="1")
+    @TypicalLength(60)
+    @MemberOrder(name="Detail",sequence = "20")
+    public String getActionIdentifier() {
+        return actionIdentifier;
+    }
+
+    public void setActionIdentifier(final String actionIdentifier) {
+        this.actionIdentifier = Util.abbreviated(actionIdentifier, JdoColumnLength.ACTION_IDENTIFIER);
     }
 
-    public void setCreatedAt(final Timestamp createdAt) {
-        this.createdAt = createdAt;
+
+    // //////////////////////////////////////
+    // memento (property)
+    // //////////////////////////////////////
+    
+    private String memento;
+    
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.BackgroundTask.MEMENTO)
+    @MultiLine(numberOfLines=20)
+    @Hidden(where=Where.ALL_TABLES)
+    @MemberOrder(name="Detail",sequence = "30")
+    public String getMemento() {
+        return memento;
+    }
+    
+    public void setMemento(final String memento) {
+        this.memento = memento;
     }
 
 
@@ -217,7 +274,6 @@ public class BackgroundTaskJdo implements HasTransactionId {
     @javax.jdo.annotations.Persistent
     @javax.jdo.annotations.Column(allowsNull="true")
     @MemberOrder(name="Timings", sequence = "3")
-    @Disabled
     public Timestamp getStartedAt() {
         return startedAt;
     }
@@ -239,7 +295,6 @@ public class BackgroundTaskJdo implements HasTransactionId {
     @javax.jdo.annotations.Persistent
     @javax.jdo.annotations.Column(allowsNull="true")
     @MemberOrder(name="Timings", sequence = "4")
-    @Disabled
     public Timestamp getCompletedAt() {
         return completedAt;
     }
@@ -264,45 +319,29 @@ public class BackgroundTaskJdo implements HasTransactionId {
     @Named("Duration")
     @MemberOrder(name="Timings", sequence = "7")
     public BigDecimal getDuration() {
-        if(getCompletedAt() == null) {
-            return null;
-        }
-        long millis = getCompletedAt().getTime() - getStartedAt().getTime();
-        return new BigDecimal(millis).divide(new BigDecimal(1000)).setScale(3, RoundingMode.HALF_EVEN);
+        return Util.durationBetween(getStartedAt(), getCompletedAt());
     }
 
 
+
     // //////////////////////////////////////
-    // transactionId (property)
+    // complete (derived property)
     // //////////////////////////////////////
-
     
-    private UUID transactionId;
-
-    /**
-     * The unique identifier (a GUID) of the transaction of the {@link Interaction} that gave rise to this
-     * background task (if known, and if the interaction is itself persisted by way of a suitable implementation of
-     * {@link InteractionFactory}).
-     */
-    @javax.jdo.annotations.Column(allowsNull="true", length=36)
-    @TypicalLength(36)
-    @MemberOrder(name="Identifiers",sequence = "20")
-    @Disabled
-    @Override
-    public UUID getTransactionId() {
-        return transactionId;
-    }
 
-    @Override
-    public void setTransactionId(final UUID transactionId) {
-        this.transactionId = transactionId;
+    @javax.jdo.annotations.NotPersistent
+    @MemberOrder(name="Timings", sequence = "8")
+    public boolean isComplete() {
+        return getCompletedAt() != null;
     }
 
     // //////////////////////////////////////
+    // toString
+    // //////////////////////////////////////
 
     @Override
     public String toString() {
-        return ObjectContracts.toString(this, "actionIdentifier,user,createdAt,startedAt,completedAt,duration,transactionId");
+        return ObjectContracts.toString(this, "actionIdentifier,user,timestamp,startedAt,completedAt,duration,transactionId");
     }
 
 
@@ -311,4 +350,7 @@ public class BackgroundTaskJdo implements HasTransactionId {
     @Inject
     private BookmarkService bookmarkService;
 
+    @javax.inject.Inject
+    private DomainObjectContainer container;
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/49c7c05d/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskJdoPK.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskJdoPK.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskJdoPK.java
new file mode 100644
index 0000000..b3de1f1
--- /dev/null
+++ b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskJdoPK.java
@@ -0,0 +1,102 @@
+/*
+ *  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.background;
+
+import java.io.Serializable;
+import java.util.StringTokenizer;
+import java.util.UUID;
+
+public class BackgroundTaskJdoPK implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final String SEPARATOR = "_";
+
+    public UUID transactionId;
+    public int sequence;
+
+    // //////////////////////////////////////
+
+    
+    public BackgroundTaskJdoPK() {
+    }
+    
+    public BackgroundTaskJdoPK(final String value) {
+        final StringTokenizer token = new StringTokenizer (value, SEPARATOR);
+        this.transactionId = UUID.fromString(token.nextToken());
+        this.sequence = Integer.parseInt(token.nextToken());
+    }
+
+    // //////////////////////////////////////
+
+    public UUID getTransactionId() {
+        return transactionId;
+    }
+    public void setTransactionId(UUID transactionId) {
+        this.transactionId = transactionId;
+    }
+    
+    // //////////////////////////////////////
+
+    public int getSequence() {
+        return sequence;
+    }
+    public void setSequence(int sequence) {
+        this.sequence = sequence;
+    }
+    
+    // //////////////////////////////////////
+
+    
+    
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + sequence;
+        result = prime * result + ((transactionId == null) ? 0 : transactionId.hashCode());
+        return result;
+    }
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        BackgroundTaskJdoPK other = (BackgroundTaskJdoPK) obj;
+        if (sequence != other.sequence)
+            return false;
+        if (transactionId == null) {
+            if (other.transactionId != null)
+                return false;
+        } else if (!transactionId.equals(other.transactionId))
+            return false;
+        return true;
+    }
+    
+    // //////////////////////////////////////
+
+    
+    @Override
+    public String toString() {
+        return transactionId + SEPARATOR + sequence;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/49c7c05d/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskRepository.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskRepository.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskRepository.java
deleted file mode 100644
index f18a670..0000000
--- a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskRepository.java
+++ /dev/null
@@ -1,47 +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.background;
-
-import java.util.List;
-import java.util.UUID;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.isis.applib.AbstractFactoryAndRepository;
-import org.apache.isis.applib.annotation.Programmatic;
-import org.apache.isis.applib.query.QueryDefault;
-
-public class BackgroundTaskRepository extends AbstractFactoryAndRepository {
-
-    @SuppressWarnings("unused")
-    private static final Logger LOG = LoggerFactory.getLogger(BackgroundTaskRepository.class);
-
-    @Programmatic
-    public List<BackgroundTaskJdo> listAll() {
-        return allInstances(BackgroundTaskJdo.class);
-    }
-
-    @Programmatic
-    public List<BackgroundTaskJdo> findByTransactionId(final UUID transactionId) {
-        return allMatches(
-                new QueryDefault<BackgroundTaskJdo>(BackgroundTaskJdo.class, 
-                        "findByTransactionId", 
-                        "transactionId", transactionId));
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/49c7c05d/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 c16e048..03eda70 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
@@ -36,16 +36,17 @@ public class BackgroundTaskServiceJdo extends AbstractService implements Backgro
 
     @Programmatic
     @Override
-    public void execute(final ActionInvocationMemento aim, final UUID transactionId) {
+    public void execute(final ActionInvocationMemento aim, final UUID transactionId, final int sequence) {
         final BackgroundTaskJdo backgroundTask = newTransientInstance(BackgroundTaskJdo.class);
 
         backgroundTask.setActionIdentifier(aim.getActionId());
-        backgroundTask.setCreatedAt(Clock.getTimeAsJavaSqlTimestamp());
+        backgroundTask.setTimestamp(Clock.getTimeAsJavaSqlTimestamp());
         backgroundTask.setMemento(aim.asMementoString());
         backgroundTask.setUser(aim.getUser());
         backgroundTask.setTargetStr(aim.getTarget().toString());
 
         backgroundTask.setTransactionId(transactionId);
+        backgroundTask.setSequence(sequence);
         persist(backgroundTask);
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/49c7c05d/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskServiceJdoContributions.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskServiceJdoContributions.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskServiceJdoContributions.java
new file mode 100644
index 0000000..9a1189d
--- /dev/null
+++ b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskServiceJdoContributions.java
@@ -0,0 +1,46 @@
+/**
+ *  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.background;
+
+import java.util.List;
+
+import org.apache.isis.applib.AbstractFactoryAndRepository;
+import org.apache.isis.applib.annotation.ActionSemantics;
+import org.apache.isis.applib.annotation.Render;
+import org.apache.isis.applib.annotation.ActionSemantics.Of;
+import org.apache.isis.applib.annotation.NotContributed;
+import org.apache.isis.applib.annotation.NotContributed.As;
+import org.apache.isis.applib.annotation.NotInServiceMenu;
+import org.apache.isis.applib.annotation.Render.Type;
+import org.apache.isis.applib.services.HasTransactionId;
+
+
+public class BackgroundTaskServiceJdoContributions extends AbstractFactoryAndRepository {
+
+    @ActionSemantics(Of.SAFE)
+    @NotInServiceMenu
+    @NotContributed(As.ACTION)
+    @Render(Type.EAGERLY)
+    public List<BackgroundTaskJdo> backgroundTasks(final HasTransactionId hasTransactionId) {
+        return backgroundTaskRepository.findByTransactionId(hasTransactionId.getTransactionId());
+    }
+
+    // //////////////////////////////////////
+
+    @javax.inject.Inject
+    private BackgroundTaskServiceJdoRepository backgroundTaskRepository;
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/49c7c05d/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskServiceJdoRepository.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskServiceJdoRepository.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskServiceJdoRepository.java
new file mode 100644
index 0000000..1cd4458
--- /dev/null
+++ b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/background/BackgroundTaskServiceJdoRepository.java
@@ -0,0 +1,47 @@
+/**
+ *  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.background;
+
+import java.util.List;
+import java.util.UUID;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.isis.applib.AbstractFactoryAndRepository;
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.query.QueryDefault;
+
+public class BackgroundTaskServiceJdoRepository extends AbstractFactoryAndRepository {
+
+    @SuppressWarnings("unused")
+    private static final Logger LOG = LoggerFactory.getLogger(BackgroundTaskServiceJdoRepository.class);
+
+    @Programmatic
+    public List<BackgroundTaskJdo> listAll() {
+        return allInstances(BackgroundTaskJdo.class);
+    }
+
+    @Programmatic
+    public List<BackgroundTaskJdo> findByTransactionId(final UUID transactionId) {
+        return allMatches(
+                new QueryDefault<BackgroundTaskJdo>(BackgroundTaskJdo.class, 
+                        "findByTransactionId", 
+                        "transactionId", transactionId));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/49c7c05d/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
index 2d660f3..1c82c5a 100644
--- 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
@@ -17,12 +17,15 @@
 package org.apache.isis.objectstore.jdo.applib.service.interaction;
 
 import java.math.BigDecimal;
-import java.math.RoundingMode;
 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;
 
@@ -35,6 +38,7 @@ 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;
@@ -43,8 +47,9 @@ 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.InteractionFactory;
+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(
@@ -61,128 +66,203 @@ import org.apache.isis.applib.util.ObjectContracts;
             value="SELECT "
                     + "FROM org.apache.isis.objectstore.jdo.applib.service.interaction.InteractionJdo "
                     + "WHERE completedAt == null "
-                    + "ORDER BY startedAt DESC"),
+                    + "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 startedAt DESC")
+                    + "ORDER BY timestamp DESC")
 })
+@ObjectType("IsisInteration")
 @MemberGroupLayout(
         columnSpans={6,0,6}, 
-        left={"Target","Notes"}, 
-        right={"Identifiers","Timings","Results"})
+        left={"Identifiers","Target","Notes"},
+        right={"Detail","Timings","Results"})
 @Named("Interaction")
-public class InteractionJdo implements Interaction, HasTransactionId {
+public class InteractionJdo implements Interaction {
 
     @SuppressWarnings("unused")
     private static final Logger LOG = LoggerFactory.getLogger(InteractionJdo.class);
 
-    
+
     // //////////////////////////////////////
-    // actionIdentifier (property)
+    // transactionId (property)
     // //////////////////////////////////////
 
-    private String actionIdentifier;
-    
-    @javax.jdo.annotations.Column(allowsNull="false", length=255)
-    @Title(sequence="1")
-    @TypicalLength(60)
-    @Hidden(where=Where.ALL_TABLES)
-    @MemberOrder(name="Identifiers",sequence = "11")
-    public String getActionIdentifier() {
-        return actionIdentifier;
+        
+    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;
     }
 
-    public void setActionIdentifier(final String actionIdentifier) {
-        this.actionIdentifier = abbreviated(actionIdentifier, 255);
+    /**
+     * <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=50)
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.Interaction.TARGET_CLASS)
     @TypicalLength(30)
-    @MemberOrder(name="Target", sequence = "1")
+    @MemberOrder(name="Target", sequence = "10")
     @Named("Class")
     public String getTargetClass() {
         return targetClass;
     }
 
     public void setTargetClass(final String targetClass) {
-        this.targetClass = abbreviated(targetClass, 50);
+        this.targetClass = Util.abbreviated(targetClass, JdoColumnLength.Interaction.TARGET_CLASS);
     }
 
 
-
-
     // //////////////////////////////////////
     // targetAction (property)
     // //////////////////////////////////////
     
     private String targetAction;
     
-    @javax.jdo.annotations.Column(allowsNull="false", length=50)
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.Interaction.TARGET_ACTION)
     @TypicalLength(30)
-    @MemberOrder(name="Target", sequence = "2")
+    @MemberOrder(name="Target", sequence = "20")
     @Named("Action")
     public String getTargetAction() {
         return targetAction;
     }
     
     public void setTargetAction(final String targetAction) {
-        this.targetAction = abbreviated(targetAction, 50);
+        this.targetAction = Util.abbreviated(targetAction, JdoColumnLength.Interaction.TARGET_ACTION);
     }
     
 
     // //////////////////////////////////////
     // target (property)
+    // openTargetObject (action)
     // //////////////////////////////////////
 
     @Programmatic
     @Override
     public Bookmark getTarget() {
-        return new Bookmark(getTargetStr());
+        return Util.bookmarkFor(getTargetStr());
     }
     
     @Programmatic
     @Override
     public void setTarget(Bookmark target) {
-        setTargetStr(target.toString());
+        setTargetStr(Util.asString(target));
     }
 
+    // //////////////////////////////////////
+    
     private String targetStr;
-    @javax.jdo.annotations.Column(allowsNull="false", length=255, name="target")
+    @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 = abbreviated(targetStr, 255);
+        this.targetStr = targetStr;
     }
 
-    
-    // //////////////////////////////////////
-    // openTargetObject (action)
     // //////////////////////////////////////
 
     @ActionSemantics(Of.SAFE)
     @MemberOrder(name="TargetStr", sequence="1")
     @Named("Open")
     public Object openTargetObject() {
-        return lookupBookmark(getTarget());
+        return Util.lookupBookmark(getTarget(), bookmarkService, container);
     }
     public boolean hideOpenTargetObject() {
-        return getTargetStr() == null;
+        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)
@@ -190,37 +270,36 @@ public class InteractionJdo implements Interaction, HasTransactionId {
     
     private String arguments;
     
-    @javax.jdo.annotations.Column(allowsNull="false", length=1024)
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.Interaction.ARGUMENTS)
     @MultiLine(numberOfLines=6)
     @Hidden(where=Where.ALL_TABLES)
-    @MemberOrder(name="Target",sequence = "4")
+    @MemberOrder(name="Detail",sequence = "4")
     @Disabled
     public String getArguments() {
         return arguments;
     }
     
     public void setArguments(final String arguments) {
-        this.arguments = abbreviated(arguments, 1024);
+        this.arguments = Util.abbreviated(arguments, JdoColumnLength.Interaction.ARGUMENTS);
     }
 
+
     // //////////////////////////////////////
-    // startedAt (property)
+    // startedAt (derived property)
     // //////////////////////////////////////
-
-    private Timestamp startedAt;
-
-    @javax.jdo.annotations.Persistent
-    @javax.jdo.annotations.Column(allowsNull="false")
+    
+    /**
+     * The date/time at which this interaction started.
+     */
+    @javax.jdo.annotations.NotPersistent
     @MemberOrder(name="Timings", sequence = "3")
+    @Disabled
     public Timestamp getStartedAt() {
-        return startedAt;
+        return getTimestamp();
     }
-
-    public void setStartedAt(final Timestamp startedAt) {
-        this.startedAt = startedAt;
-    }
-
-
+    
+    
+    
     // //////////////////////////////////////
     // completedAt (property)
     // //////////////////////////////////////
@@ -249,21 +328,22 @@ public class InteractionJdo implements Interaction, HasTransactionId {
 
 
     // //////////////////////////////////////
-    // user (property)
+    // duration (derived property)
     // //////////////////////////////////////
 
-    private String user;
-
-    @javax.jdo.annotations.Column(allowsNull="false", length=50)
-    @Title(sequence="2", prepend=", ")
-    @MemberOrder(name="Identifiers", sequence = "5")
-    public String getUser() {
-        return user;
+    /**
+     * 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());
     }
 
-    public void setUser(final String user) {
-        this.user = abbreviated(user,50);
-    }
 
 
     // //////////////////////////////////////
@@ -280,7 +360,7 @@ public class InteractionJdo implements Interaction, HasTransactionId {
      * 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=1024)
+    @javax.jdo.annotations.Column(allowsNull="true", length=JdoColumnLength.Interaction.NOTES)
     @MultiLine(numberOfLines=10)
     @Hidden(where=Where.ALL_TABLES)
     @MemberOrder(name="Notes", sequence = "6")
@@ -289,69 +369,20 @@ public class InteractionJdo implements Interaction, HasTransactionId {
     }
 
     public void setNotes(final String notes) {
-        this.notes = abbreviated(notes, 1024);
-    }
-
-
-    // //////////////////////////////////////
-    // 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() {
-        if(getCompletedAt() == null) {
-            return null;
-        }
-        long millis = getCompletedAt().getTime() - getStartedAt().getTime();
-        return new BigDecimal(millis).divide(new BigDecimal(1000)).setScale(3, RoundingMode.HALF_EVEN);
+        this.notes = notes;
     }
 
 
     // //////////////////////////////////////
-    // 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=36)
-    @TypicalLength(36)
-    @MemberOrder(name="Identifiers",sequence = "20")
-    @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;
-    }
-
-    // //////////////////////////////////////
     // 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
@@ -363,7 +394,7 @@ public class InteractionJdo implements Interaction, HasTransactionId {
      * <b>NOT API</b>: intended to be called only by the framework.
      * 
      * <p>
-     * Implementation notes: populated by the viewer as hint to {@link InteractionFactory} implementation.
+     * Implementation notes: populated by the viewer as hint to {@link InteractionService} implementation.
      */
     @Override
     public void setNature(Nature nature) {
@@ -373,53 +404,55 @@ public class InteractionJdo implements Interaction, HasTransactionId {
     
     // //////////////////////////////////////
     // result (property)
+    // openResultObject (action)
     // //////////////////////////////////////
 
     @Programmatic
     @Override
     public Bookmark getResult() {
-        return getResultStr() != null? new Bookmark(getResultStr()): null;
+        return Util.bookmarkFor(getResultStr());
     }
-    
+
     @Programmatic
     @Override
     public void setResult(Bookmark result) {
-        setResultStr(result != null? result.toString(): null);
+        setResultStr(Util.asString(result));
     }
 
+    // //////////////////////////////////////
+    
     private String resultStr;
-    @javax.jdo.annotations.Column(allowsNull="true", length=255, name="result")
+
+    @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 = abbreviated(resultStr,255);
+        this.resultStr = resultStr;
     }
 
-    
-    // //////////////////////////////////////
-    // openResultObject (action)
     // //////////////////////////////////////
 
     @ActionSemantics(Of.SAFE)
     @MemberOrder(name="ResultStr", sequence="1")
     @Named("Open")
     public Object openResultObject() {
-        Bookmark bookmark = getResult();
-        return lookupBookmark(bookmark);
+        return Util.lookupBookmark(getResult(), bookmarkService, container);
     }
     public boolean hideOpenResultObject() {
-        return getResultStr() == null;
+        return getResult() == null;
     }
 
 
-
     // //////////////////////////////////////
     // exception (property)
+    // causedException (derived property)
+    // showException (associated action)
     // //////////////////////////////////////
 
     private String exception;
@@ -433,7 +466,7 @@ public class InteractionJdo implements Interaction, HasTransactionId {
      * 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=2000)
+    @javax.jdo.annotations.Column(allowsNull="true", length=JdoColumnLength.Interaction.EXCEPTION)
     @Hidden
     @Override
     public String getException() {
@@ -442,14 +475,11 @@ public class InteractionJdo implements Interaction, HasTransactionId {
 
     @Override
     public void setException(final String exception) {
-        this.exception = abbreviated(exception, 2000);
+        this.exception = Util.abbreviated(exception, JdoColumnLength.Interaction.EXCEPTION);
     }
     
     
     // //////////////////////////////////////
-    // causedException (derived property)
-    // showException (associated action)
-    // //////////////////////////////////////
     
     @javax.jdo.annotations.NotPersistent
     @MemberOrder(name="Results",sequence = "30")
@@ -458,6 +488,9 @@ public class InteractionJdo implements Interaction, HasTransactionId {
         return getException() != null;
     }
 
+    
+    // //////////////////////////////////////
+    
     @ActionSemantics(Of.SAFE)
     @MemberOrder(name="causedException", sequence = "1")
     public String showException() {
@@ -467,34 +500,37 @@ public class InteractionJdo implements Interaction, HasTransactionId {
         return !isCausedException();
     }
 
+
+    // //////////////////////////////////////
+    // next(...) impl
     // //////////////////////////////////////
 
+    private final Map<String, AtomicInteger> sequenceByName = Maps.newHashMap();
 
+    @Programmatic
     @Override
-    public String toString() {
-        return ObjectContracts.toString(this, "startedAt,user,actionIdentifier,target,completedAt,duration,transactionId");
+    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
+    // //////////////////////////////////////
 
-    private Object lookupBookmark(Bookmark bookmark) {
-        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;
-        }
-    }
 
-    private static String abbreviated(final String str, final int maxLength) {
-        return str != null? (str.length() < maxLength ? str : str.substring(0, maxLength - 3) + "..."): null;
+    @Override
+    public String toString() {
+        return ObjectContracts.toString(this, "startedAt,user,actionIdentifier,target,completedAt,duration,transactionId");
     }
 
+    
     // //////////////////////////////////////
     
     @javax.inject.Inject

http://git-wip-us.apache.org/repos/asf/isis/blob/49c7c05d/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/interaction/InteractionRepository.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/interaction/InteractionRepository.java b/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/interaction/InteractionRepository.java
deleted file mode 100644
index 8fd209b..0000000
--- a/component/objectstore/jdo/jdo-applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/interaction/InteractionRepository.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 InteractionRepository 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;
-
-}