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/07/04 16:53:40 UTC

[12/16] git commit: ISIS-833: moved applib services into own modules, rationalized most of the applib/runtime modules

ISIS-833: moved applib services into own modules, rationalized most of the applib/runtime modules

(full details are on the corresponding JIRA, https://issues.apache.org/jira/browse/ISIS-833, along with draft text for aiding migratio when prepare release notes).


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

Branch: refs/heads/master
Commit: e3c205925455267d486efa16e78484d6c302cb01
Parents: bf34a19
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Fri Jul 4 13:42:07 2014 +0100
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Fri Jul 4 13:42:07 2014 +0100

----------------------------------------------------------------------
 core/applib/pom.xml                             |  93 ++-
 .../org/apache/isis/applib/annotation/Bulk.java |   8 +-
 .../applib/services/audit/AuditingService3.java |  14 +-
 .../background/BackgroundCommandService.java    |  13 +-
 .../BookmarkHolderActionContributions.java      |  66 ++
 .../services/bookmark/BookmarkService.java      |   2 -
 .../ClassDiscoveryServiceUsingReflections.java  |   5 +-
 .../applib/services/clock/ClockService.java     |   6 +-
 .../applib/services/command/CommandContext.java |   9 +-
 .../services/command/spi/CommandService.java    |  12 +-
 .../services/publish/EventSerializer.java       |   7 +-
 .../services/publish/PublishingService.java     |  17 +
 .../queryresultscache/QueryResultsCache.java    |   8 +-
 .../applib/services/scratchpad/Scratchpad.java  |   8 +-
 .../BookmarkHolderAssociationContributions.java |  67 ++
 .../jdo/applib/annotations/Auditable.java       |  36 +
 .../isis/objectstore/jdo/applib/Auditable.java  |  26 +
 .../applib/service/DomainChangeJdoAbstract.java | 290 ++++++++
 .../jdo/applib/service/JdoColumnLength.java     |  68 ++
 .../objectstore/jdo/applib/service/Util.java    |  68 ++
 ...ionRecognizerCompositeForJdoObjectStore.java |  45 ++
 ...ptionRecognizerForJDODataStoreException.java |  31 +
 ...RecognizerForJDOObjectNotFoundException.java |  31 +
 ...nstraintViolationUniqueOrIndexException.java |  30 +
 ...tegrityConstraintViolationExceptionTest.java |  52 ++
 .../apache/isis/core/commons/ensure/Ensure.java |   2 +-
 .../bookmarks/BookmarkServiceDefault.java       |  47 +-
 .../jdo/applib/service/audit/AuditEntryJdo.java | 359 +++++++++
 .../service/audit/AuditingServiceJdo.java       |  55 ++
 .../audit/AuditingServiceJdoContributions.java  |  55 ++
 .../audit/AuditingServiceJdoRepository.java     | 129 ++++
 .../src/main/resources/images/AuditEntryJdo.png | Bin 0 -> 477 bytes
 core/module-command-jdo/pom.xml                 |   5 +
 .../background/BackgroundCommandServiceJdo.java |  89 +++
 ...ackgroundCommandServiceJdoContributions.java |  73 ++
 .../BackgroundCommandServiceJdoRepository.java  |  70 ++
 .../jdo/applib/service/command/CommandJdo.java  | 740 +++++++++++++++++++
 .../service/command/CommandServiceJdo.java      | 117 +++
 .../command/CommandServiceJdoContributions.java |  70 ++
 .../command/CommandServiceJdoRepository.java    | 169 +++++
 ...xecutionFromBackgroundCommandServiceJdo.java |  46 ++
 .../src/main/resources/images/CommandJdo.png    | Bin 0 -> 582 bytes
 .../service/command/CommandJdoTest_next.java    |  43 ++
 core/module-devutils/pom.xml                    |  32 +
 .../jdo/applib/service/publish/IoUtils.java     | 126 ++++
 .../service/publish/PublishedEventJdo.java      | 490 ++++++++++++
 .../service/publish/PublishedEventJdoPK.java    | 102 +++
 .../service/publish/PublishingServiceJdo.java   | 122 +++
 .../PublishingServiceJdoContributions.java      |  47 ++
 .../publish/PublishingServiceJdoRepository.java | 156 ++++
 .../main/resources/images/PublishedEventJdo.png | Bin 0 -> 541 bytes
 .../jdo/applib/service/publish/IoUtilsTest.java |  36 +
 .../module-publishingeventserializer-ro/pom.xml |  89 +++
 .../EventSerializerRendererContext.java         |  95 +++
 .../RestfulObjectsSpecEventSerializer.java      | 124 ++++
 .../main/resources/images/PublishedEventJdo.png | Bin 0 -> 541 bytes
 .../service/settings/ApplicationSettingJdo.java |  96 +++
 .../settings/ApplicationSettingsServiceJdo.java | 120 +++
 .../ApplicationSettingsServiceJdoHidden.java    |  81 ++
 .../service/settings/SettingAbstractJdo.java    | 190 +++++
 .../applib/service/settings/UserSettingJdo.java | 129 ++++
 .../service/settings/UserSettingJdoPK.java      |  90 +++
 .../settings/UserSettingsServiceJdo.java        | 170 +++++
 .../settings/UserSettingsServiceJdoHidden.java  |  88 +++
 core/module-settings/pom.xml                    |  32 +
 .../core/wrapper/WrapperFactoryDefault.java     |   7 +-
 core/objectstore-jdo-applib/pom.xml             | 138 ----
 .../src/main/java/META-INF/persistence.xml      |  26 -
 .../jdo/applib/annotations/Auditable.java       |  36 -
 .../isis/objectstore/jdo/applib/Auditable.java  |  26 -
 .../applib/service/DomainChangeJdoAbstract.java | 306 --------
 .../jdo/applib/service/JdoColumnLength.java     |  68 --
 .../objectstore/jdo/applib/service/Util.java    |  68 --
 .../jdo/applib/service/audit/AuditEntryJdo.java | 359 ---------
 .../service/audit/AuditingServiceJdo.java       |  55 --
 .../audit/AuditingServiceJdoContributions.java  |  46 --
 .../audit/AuditingServiceJdoRepository.java     | 118 ---
 .../background/BackgroundCommandServiceJdo.java |  80 --
 ...ackgroundCommandServiceJdoContributions.java |  65 --
 .../BackgroundCommandServiceJdoRepository.java  |  58 --
 .../jdo/applib/service/command/CommandJdo.java  | 740 -------------------
 .../service/command/CommandServiceJdo.java      | 114 ---
 .../command/CommandServiceJdoContributions.java |  64 --
 .../command/CommandServiceJdoRepository.java    | 158 ----
 ...ionRecognizerCompositeForJdoObjectStore.java |  45 --
 ...ptionRecognizerForJDODataStoreException.java |  31 -
 ...RecognizerForJDOObjectNotFoundException.java |  31 -
 ...nstraintViolationUniqueOrIndexException.java |  30 -
 .../jdo/applib/service/publish/IoUtils.java     | 126 ----
 .../service/publish/PublishedEventJdo.java      | 506 -------------
 .../service/publish/PublishedEventJdoPK.java    | 102 ---
 .../service/publish/PublishingServiceJdo.java   | 127 ----
 .../PublishingServiceJdoContributions.java      |  47 --
 .../publish/PublishingServiceJdoRepository.java | 154 ----
 .../service/settings/ApplicationSettingJdo.java |  96 ---
 .../settings/ApplicationSettingsServiceJdo.java | 120 ---
 .../ApplicationSettingsServiceJdoHidden.java    |  81 --
 .../service/settings/SettingAbstractJdo.java    | 190 -----
 .../applib/service/settings/UserSettingJdo.java | 129 ----
 .../service/settings/UserSettingJdoPK.java      |  90 ---
 .../settings/UserSettingsServiceJdo.java        | 170 -----
 .../settings/UserSettingsServiceJdoHidden.java  |  88 ---
 .../src/main/resources/images/AuditEntryJdo.png | Bin 477 -> 0 bytes
 .../src/main/resources/images/CommandJdo.png    | Bin 582 -> 0 bytes
 .../main/resources/images/PublishedEventJdo.png | Bin 541 -> 0 bytes
 .../service/command/CommandJdoTest_next.java    |  43 --
 ...tegrityConstraintViolationExceptionTest.java |  52 --
 .../jdo/applib/service/publish/IoUtilsTest.java |  36 -
 .../service/eventbus/EventBusServiceJdo.java    |   6 +-
 .../service/support/IsisJdoSupportImpl.java     |   6 +-
 ...xecutionFromBackgroundCommandServiceJdo.java |  46 --
 core/objectstore-jdo-metamodel/pom.xml          |   2 +-
 core/pom.xml                                    | 163 +++-
 .../services/memento/MementoServiceDefault.java |   8 +-
 .../xmlsnapshot/XmlSnapshotServiceDefault.java  |   6 +-
 .../AbstractIsisSessionTemplate.java            |   3 -
 .../EventSerializerRendererContext.java         |  98 ---
 .../RestfulObjectsSpecEventSerializer.java      | 119 ---
 .../quickstart_wicket_restful_jdo/dom/pom.xml   |  14 +-
 .../java/integration/ToDoSystemInitializer.java |  12 +-
 .../quickstart_wicket_restful_jdo/pom.xml       |   1 -
 .../webapp/pom.xml                              |  30 +-
 .../src/main/webapp/WEB-INF/isis.properties     |  29 +-
 .../simple_wicket_restful_jdo/dom/pom.xml       |  21 +-
 .../integration/SimpleAppSystemInitializer.java |  19 +-
 .../simple_wicket_restful_jdo/webapp/pom.xml    |  66 +-
 .../src/main/webapp/WEB-INF/isis.properties     |  29 +-
 127 files changed, 5718 insertions(+), 5282 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/pom.xml
----------------------------------------------------------------------
diff --git a/core/applib/pom.xml b/core/applib/pom.xml
index e41bb77..e3375af 100644
--- a/core/applib/pom.xml
+++ b/core/applib/pom.xml
@@ -66,7 +66,80 @@
 			</plugin>
 		</plugins>
 	</reporting>
-	
+
+    <build>
+        <resources>
+            <resource>
+                <filtering>false</filtering>
+                <directory>src/main/resources</directory>
+            </resource>
+            <resource>
+                <filtering>false</filtering>
+                <directory>src/main/java</directory>
+                <includes>
+                    <include>**</include>
+                </includes>
+                <excludes>
+                    <exclude>**/*.java</exclude>
+                </excludes>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.datanucleus</groupId>
+                <artifactId>datanucleus-maven-plugin</artifactId>
+                <version>${datanucleus-maven-plugin.version}</version>
+                <configuration>
+                    <fork>false</fork>
+                    <verbose>true</verbose>
+                </configuration>
+                <executions>
+                    <execution>
+                        <phase>compile</phase>
+                        <goals>
+                            <goal>enhance</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <pluginManagement>
+            <plugins>
+                <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
+                <plugin>
+                    <groupId>org.eclipse.m2e</groupId>
+                    <artifactId>lifecycle-mapping</artifactId>
+                    <version>1.0.0</version>
+                    <configuration>
+                        <lifecycleMappingMetadata>
+                            <pluginExecutions>
+                                <pluginExecution>
+                                    <pluginExecutionFilter>
+                                        <groupId>
+                                            org.datanucleus
+                                        </groupId>
+                                        <artifactId>
+                                            datanucleus-maven-plugin
+                                        </artifactId>
+                                        <versionRange>
+                                            [3.2.0-release,)
+                                        </versionRange>
+                                        <goals>
+                                            <goal>enhance</goal>
+                                        </goals>
+                                    </pluginExecutionFilter>
+                                    <action>
+                                        <ignore />
+                                    </action>
+                                </pluginExecution>
+                            </pluginExecutions>
+                        </lifecycleMappingMetadata>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+
 	<dependencies>
 		<dependency>
 			<groupId>joda-time</groupId>
@@ -85,23 +158,27 @@
             <artifactId>geronimo-jcdi_1.0_spec</artifactId>
         </dependency>
 
-        <!--
-        must be kept consistent with the API bundled by
-        org.datanucleus:datanucleus-accessplatform-jdo-rdbms
-        -->
+
+        <!-- DataNucleus (jdo-api, and for enhancer) -->
+        <dependency>
+            <groupId>org.datanucleus</groupId>
+            <artifactId>datanucleus-accessplatform-jdo-rdbms</artifactId>
+            <type>pom</type>
+        </dependency>
         <dependency>
-            <groupId>javax.jdo</groupId>
-            <artifactId>jdo-api</artifactId>
-            <version>3.1-rc1</version>
+            <groupId>org.datanucleus</groupId>
+            <artifactId>datanucleus-jodatime</artifactId>
         </dependency>
 
 
+
         <dependency>
             <groupId>org.apache.isis.core</groupId>
             <artifactId>isis-core-unittestsupport</artifactId>
             <scope>test</scope>
         </dependency>
 
+        <!-- as used by ClassDiscoveryServiceUsingReflections -->
         <dependency>
             <groupId>org.reflections</groupId>
             <artifactId>reflections</artifactId>

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/applib/annotation/Bulk.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/Bulk.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/Bulk.java
index d016c3b..84cff20 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/Bulk.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/Bulk.java
@@ -60,12 +60,12 @@ public @interface Bulk {
     AppliesTo value() default AppliesTo.BULK_AND_REGULAR;
     
     /**
-     * This service provides access to context information about a bulk action invocation.
+     * This service (API and implementation) provides access to context information about a bulk action invocation.
      *
      * <p>
-     * Because this service is annotated with {@link org.apache.isis.applib.annotation.DomainService} and is
-     * implemented in the applib, it is automatically registered and available for use; no configuration is required.
-     * </p>
+     * This implementation has no UI and there is only one implementation (this class) in applib, so it is annotated
+     * with {@link org.apache.isis.applib.annotation.DomainService}.  This means that it is automatically registered
+     * and available for use; no further configuration is required.
      */
     @DomainService
     @RequestScoped

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/applib/services/audit/AuditingService3.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/audit/AuditingService3.java b/core/applib/src/main/java/org/apache/isis/applib/services/audit/AuditingService3.java
index 2378815..2208689 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/audit/AuditingService3.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/audit/AuditingService3.java
@@ -25,7 +25,19 @@ import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 
 /**
- * Will be called whenever an object has changed its state.
+ * Will be called whenever an auditable entity has changed its state.
+ *
+ * <p>
+ * Typically entities are marked as auditable using the {@link org.apache.isis.applib.annotation.Audited}
+ * annotation.
+ *
+ * <p>
+ * There are currently two implementations, <tt>AuditingServiceJdo</tt> (part of the
+ * <tt>o.a.i.module:isis-module-audit-jdo</tt>) and the demo
+ * {@link org.apache.isis.applib.services.audit.AuditingService3.Stderr}.
+ *
+ * <p>
+ * To use either service, must include on the classpath and also register the service (eg in <tt>isis.properties</tt>).
  */
 public interface AuditingService3 {
     

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/applib/services/background/BackgroundCommandService.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/background/BackgroundCommandService.java b/core/applib/src/main/java/org/apache/isis/applib/services/background/BackgroundCommandService.java
index 02d434f..092ad82 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/background/BackgroundCommandService.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/background/BackgroundCommandService.java
@@ -20,13 +20,20 @@ import org.apache.isis.applib.services.command.Command;
 
 
 /**
- * Execute a {@link ActionInvocationMemento memento-ized} action as a
- * decoupled task.
- * 
+ * Persists a {@link ActionInvocationMemento memento-ized} action such that it can be executed asynchronously,
+ * for example through a Quartz scheduler.
+ *
  * <p>
  * Separate from {@link BackgroundService} primarily so that the default
  * implementation, <tt>BackgroundServiceDefault</tt> (in core-runtime) can
  * delegate to different implementations of this service.
+ *
+ * <p>
+ * There is currently only implementation of this service, <tt>BackgroundCommandServiceJdo</tt> in
+ * <tt>o.a.i.module:isis-module-command-jdo</tt>.  That implementation has no UI and no side-effects (the programmatic
+ * API is through {@link org.apache.isis.applib.services.background.BackgroundService}).  It is therefore
+ * annotated with {@link org.apache.isis.applib.annotation.DomainService} so that it is automatically registered as
+ * a service.
  */
 public interface BackgroundCommandService {
 

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/applib/services/bookmark/BookmarkHolderActionContributions.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/bookmark/BookmarkHolderActionContributions.java b/core/applib/src/main/java/org/apache/isis/applib/services/bookmark/BookmarkHolderActionContributions.java
new file mode 100644
index 0000000..f9a07fb
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/bookmark/BookmarkHolderActionContributions.java
@@ -0,0 +1,66 @@
+/*
+ *  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.bookmark;
+
+import java.util.Map;
+import javax.annotation.PostConstruct;
+import org.apache.isis.applib.annotation.NotContributed;
+import org.apache.isis.applib.annotation.NotInServiceMenu;
+import org.apache.isis.applib.annotation.Programmatic;
+
+/**
+ * Domain service that contributes an action (named '<tt>lookup</tt>') to
+ * any class that implements {@link org.apache.isis.applib.services.bookmark.BookmarkHolder}.
+ *
+ * <p>
+ * Alternatively, can use {@link org.apache.isis.core.metamodel.services.bookmarks.BookmarkHolderAssociationContributions}
+ * to contribute an property.
+ *
+ * <p>
+ * The service must be explicitly registered, typically in <tt>isis.properties</tt>.
+ */
+public class BookmarkHolderActionContributions  {
+
+
+    //region > init
+    @Programmatic
+    @PostConstruct
+    public void init(Map<String,String> props) {
+        ensureDependenciesInjected();
+    }
+
+    private void ensureDependenciesInjected() {
+        if(this.bookmarkService == null){
+            throw new IllegalStateException("BookmarkService domain service must be configured");
+        }
+    }
+    //endregion
+
+
+    @NotInServiceMenu
+    @NotContributed(NotContributed.As.ASSOCIATION)
+    public Object lookup(final BookmarkHolder bookmarkHolder) {
+        return bookmarkService.lookup(bookmarkHolder);
+    }
+
+
+    @javax.inject.Inject
+    private BookmarkService bookmarkService;
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/applib/services/bookmark/BookmarkService.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/bookmark/BookmarkService.java b/core/applib/src/main/java/org/apache/isis/applib/services/bookmark/BookmarkService.java
index 6dda621..0afc2c0 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/bookmark/BookmarkService.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/bookmark/BookmarkService.java
@@ -18,7 +18,6 @@
  */
 package org.apache.isis.applib.services.bookmark;
 
-import org.apache.isis.applib.annotation.Named;
 import org.apache.isis.applib.annotation.NotInServiceMenu;
 import org.apache.isis.applib.annotation.Programmatic;
 
@@ -31,7 +30,6 @@ import org.apache.isis.applib.annotation.Programmatic;
  * automatically registered and available for use; no configuration is required.
  * </p>
  */
-@Named("Bookmarks")
 public interface BookmarkService {
 
     @NotInServiceMenu

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/applib/services/classdiscovery/ClassDiscoveryServiceUsingReflections.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/classdiscovery/ClassDiscoveryServiceUsingReflections.java b/core/applib/src/main/java/org/apache/isis/applib/services/classdiscovery/ClassDiscoveryServiceUsingReflections.java
index 2d820db..a8b5df2 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/classdiscovery/ClassDiscoveryServiceUsingReflections.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/classdiscovery/ClassDiscoveryServiceUsingReflections.java
@@ -32,8 +32,9 @@ import org.apache.isis.applib.annotation.DomainService;
  * is the <tt>FixtureScripts</tt> domain service.
  *
  * <p>
- * Because this service is annotated with {@link org.apache.isis.applib.annotation.DomainService} and is
- * implemented in the core applib, it is automatically registered and available for use; no configuration is required.
+ * This service has no UI and there is only one implementation (this class) in applib, so it is annotated with
+ * {@link org.apache.isis.applib.annotation.DomainService}.  This means that it is automatically registered and
+ * available for use; no further configuration is required.
  * </p>
  */
 @DomainService

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/applib/services/clock/ClockService.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/clock/ClockService.java b/core/applib/src/main/java/org/apache/isis/applib/services/clock/ClockService.java
index 7c2ab95..6e1d129 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/clock/ClockService.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/clock/ClockService.java
@@ -30,9 +30,9 @@ import org.apache.isis.applib.clock.Clock;
  * co-ordinated time management through a centralized time service.
  *
  * <p>
- * Because this service is annotated with {@link org.apache.isis.applib.annotation.DomainService} and is
- * implemented in the core applib, it is automatically registered and available for use; no configuration is required.
- * </p>
+ * This service has no UI and there is only one implementation (this class) in applib, so it is annotated with
+ * {@link org.apache.isis.applib.annotation.DomainService}.  This means that it is automatically registered and
+ * available for use; no further configuration is required.
  */
 @DomainService
 public class ClockService {

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/applib/services/command/CommandContext.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/command/CommandContext.java b/core/applib/src/main/java/org/apache/isis/applib/services/command/CommandContext.java
index 5d15b40..f99987a 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/command/CommandContext.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/command/CommandContext.java
@@ -25,12 +25,11 @@ import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.annotation.Programmatic;
 
 /**
- * This service provides access to context information about any {@link Command}.
+ * This service (API and implementation) provides access to context information about any {@link Command}.
  *
- * <p>
- * Because this service is annotated with {@link org.apache.isis.applib.annotation.DomainService} and is
- * implemented in the core applib, it is automatically registered and available for use; no configuration is required.
- * </p>
+ * This implementation has no UI and there is only one implementation (this class) in applib, so it is annotated with
+ * {@link org.apache.isis.applib.annotation.DomainService}.  This means that it is automatically registered and
+ * available for use; no further configuration is required.
  */
 @DomainService
 @RequestScoped

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandService.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandService.java b/core/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandService.java
index f671b49..7c7bb7a 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandService.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/command/spi/CommandService.java
@@ -22,14 +22,12 @@ import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.services.command.Command;
 
 /**
- * Intended for service to implement, providing a different implementation of
- * {@link Command}.
- * 
+ * Factory and persistence service for {@link Command}s.
+ *
  * <p>
- * The default implementation (provided automatically by the framework) will
- * instantiate an in-memory implementation of {@link Command}.  However, other
- * services (eg as provided by the JDO objectstore) might provide a persistable 
- * {@link Command} object.
+ * There is currently only one implementation, <tt>CommandServiceJdo</tt>, part of the
+ * <tt>o.a.i.module:isis-module-command-jdo</tt>.  To use, must both include on the classpath and also
+ * register its services (eg in <tt>isis.properties</tt>).
  */
 public interface CommandService {
 

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventSerializer.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventSerializer.java b/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventSerializer.java
index 3046abf..802ede0 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventSerializer.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventSerializer.java
@@ -26,7 +26,7 @@ import org.apache.isis.applib.annotation.Programmatic;
 public interface EventSerializer {
 
     /**
-     * Combine the {@link EventMetadata metadata} and the {@link EventPayload payload}
+     * Combines the {@link EventMetadata metadata} and the {@link EventPayload payload}
      * into some serialized form (such as JSON, XML or a string) that can then be published.
      * 
      * <p>
@@ -39,7 +39,10 @@ public interface EventSerializer {
      * @return a string, some JSON, some XML or some other standard serialized form. 
      */
     public Object serialize(EventMetadata metadata, EventPayload payload);
-    
+
+    /**
+     * Used as a fallback if no other implementation is defined.
+     */
     public static class Simple implements EventSerializer {
 
         @Programmatic

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/applib/services/publish/PublishingService.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/publish/PublishingService.java b/core/applib/src/main/java/org/apache/isis/applib/services/publish/PublishingService.java
index d91c6cc..e4790d5 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/publish/PublishingService.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/publish/PublishingService.java
@@ -21,6 +21,23 @@ package org.apache.isis.applib.services.publish;
 
 import org.apache.isis.applib.annotation.Hidden;
 
+
+/**
+ * Will be called whenever an publishable entity has changed its state, or an published action has been invoked.
+ *
+ * <p>
+ * Typically an entity is marked to be published using the {@link org.apache.isis.applib.annotation.PublishedObject}
+ * annotation, and an action is marked to be published using the
+ * {@link org.apache.isis.applib.annotation.PublishedAction} annotation.
+ *
+ * <p>
+ * There are currently two implementations, <tt>PublishingServiceJdo</tt> (part of the
+ * <tt>o.a.i.module:isis-module-publishing-jdo</tt>) and the demo
+ * {@link org.apache.isis.applib.services.publish.PublishingService.Stderr}.
+ *
+ * <p>
+ * To use either service, must include on the classpath and also register the service (eg in <tt>isis.properties</tt>).
+ */
 public interface PublishingService {
     
     @Hidden

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/applib/services/queryresultscache/QueryResultsCache.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/queryresultscache/QueryResultsCache.java b/core/applib/src/main/java/org/apache/isis/applib/services/queryresultscache/QueryResultsCache.java
index fb918d9..bff25c4 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/queryresultscache/QueryResultsCache.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/queryresultscache/QueryResultsCache.java
@@ -31,14 +31,14 @@ import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.annotation.Programmatic;
 
 /**
- * This service provides a mechanism by which idempotent query results can be cached for the duration of an interaction.
+ * This service (API and implementation) provides a mechanism by which idempotent query results can be cached for the duration of an interaction.
  * Most commonly this allows otherwise &quot;naive&quot; - eg that makes a repository call many times within a loop - to
  * be performance tuned.  The benefit is that the algorithm of the business logic can remain easy to understand.
  *
  * <p>
- * Because this service is annotated with {@link org.apache.isis.applib.annotation.DomainService} and is
- * implemented in the applib, it is automatically registered and available for use; no configuration is required.
- * </p>
+ * This implementation has no UI and there is only one implementation (this class) in applib, it is annotated with
+ * {@link org.apache.isis.applib.annotation.DomainService}.  This means that it is automatically registered and
+ * available for use; no further configuration is required.
  */
 @DomainService
 @RequestScoped

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/applib/services/scratchpad/Scratchpad.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/scratchpad/Scratchpad.java b/core/applib/src/main/java/org/apache/isis/applib/services/scratchpad/Scratchpad.java
index 999f7e6..24c84d7 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/scratchpad/Scratchpad.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/scratchpad/Scratchpad.java
@@ -28,14 +28,14 @@ import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.annotation.Programmatic;
 
 /**
- * This service provides a mechanism to interchange information between multiple objects invoked in the same
+ * This service (API and implementation) provides a mechanism to interchange information between multiple objects invoked in the same
  * interaction.  Most commonly this will be as the result of invoking a {@link org.apache.isis.applib.annotation.Bulk}
  * action.
  *
  * <p>
- * Because this service is annotated with {@link org.apache.isis.applib.annotation.DomainService} and is
- * implemented in the core applib, it is automatically registered and available for use; no configuration is required.
- * </p>
+ * This implementation has no UI and there is only one implementation (this class) in applib, so it is annotated with
+ * {@link org.apache.isis.applib.annotation.DomainService}.  This means that it is automatically registered and
+ * available for use; no further configuration is required.
  */
 @DomainService
 @RequestScoped

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/core/metamodel/services/bookmarks/BookmarkHolderAssociationContributions.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/core/metamodel/services/bookmarks/BookmarkHolderAssociationContributions.java b/core/applib/src/main/java/org/apache/isis/core/metamodel/services/bookmarks/BookmarkHolderAssociationContributions.java
new file mode 100644
index 0000000..8eb4aeb
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/core/metamodel/services/bookmarks/BookmarkHolderAssociationContributions.java
@@ -0,0 +1,67 @@
+/*
+ *  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.core.metamodel.services.bookmarks;
+
+import java.util.Map;
+import javax.annotation.PostConstruct;
+import org.apache.isis.applib.annotation.NotContributed;
+import org.apache.isis.applib.annotation.NotInServiceMenu;
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.services.bookmark.BookmarkHolder;
+import org.apache.isis.applib.services.bookmark.BookmarkService;
+
+/**
+ * Domain service that contributes a property (named '<tt>Object</tt>') to
+ * any class that implements {@link org.apache.isis.applib.services.bookmark.BookmarkHolder}.
+ *
+ * <p>
+ * Alternatively, can use {@link org.apache.isis.applib.services.bookmark.BookmarkHolderActionContributions}
+ * to contribute an action.
+ *
+ * <p>
+ * The service must be explicitly registered, typically in <tt>isis.properties</tt>.
+ */
+public class BookmarkHolderAssociationContributions {
+
+
+    //region > init
+    @Programmatic
+    @PostConstruct
+    public void init(Map<String,String> props) {
+        ensureDependenciesInjected();
+    }
+
+    private void ensureDependenciesInjected() {
+        if(this.bookmarkService == null){
+            throw new IllegalStateException("BookmarkService domain service must be configured");
+        }
+    }
+    //endregion
+
+    @NotInServiceMenu
+    @NotContributed(NotContributed.As.ACTION)
+    public Object object(final BookmarkHolder bookmarkHolder) {
+        return bookmarkService.lookup(bookmarkHolder);
+    }
+
+
+    @javax.inject.Inject
+    private BookmarkService bookmarkService;
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/core/objectstore/jdo/applib/annotations/Auditable.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/core/objectstore/jdo/applib/annotations/Auditable.java b/core/applib/src/main/java/org/apache/isis/core/objectstore/jdo/applib/annotations/Auditable.java
new file mode 100644
index 0000000..c903b65
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/core/objectstore/jdo/applib/annotations/Auditable.java
@@ -0,0 +1,36 @@
+/*
+ *  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.core.objectstore.jdo.applib.annotations;
+
+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;
+
+/**
+ * @deprecated use the {@link org.apache.isis.applib.annotation.Audited the applib Audited} annotation instead.
+ */
+@Deprecated
+@Inherited
+@Target({ ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Auditable {
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/Auditable.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/Auditable.java b/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/Auditable.java
new file mode 100644
index 0000000..8035bfd
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/Auditable.java
@@ -0,0 +1,26 @@
+/*
+ *  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;
+
+/**
+ * @deprecated use the {@link org.apache.isis.applib.marker.Auditable the applib Auditable} marker interface instead.
+ */
+@Deprecated
+public interface Auditable extends org.apache.isis.applib.marker.Auditable {
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/DomainChangeJdoAbstract.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/DomainChangeJdoAbstract.java b/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/DomainChangeJdoAbstract.java
new file mode 100644
index 0000000..28f73eb
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/DomainChangeJdoAbstract.java
@@ -0,0 +1,290 @@
+/**
+ *  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.sql.Timestamp;
+import java.util.Comparator;
+import java.util.UUID;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.isis.applib.DomainObjectContainer;
+import org.apache.isis.applib.annotation.*;
+import org.apache.isis.applib.annotation.ActionSemantics.Of;
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.applib.services.bookmark.BookmarkService;
+import org.apache.isis.applib.util.ObjectContracts;
+
+/**
+ * An abstraction of some sort of recorded change to a domain object, either a <tt>CommandJdo</tt>, an
+ * <tt>AuditEntryJdo</tt> or a <tt>PublishedEventJdo</tt>.
+ */
+@MemberGroupLayout(
+        columnSpans={6,0,6,12}, 
+        left={"Identifiers"},
+        right={"Target","Detail"})
+@Named("Domain Change")
+@Immutable
+public abstract class DomainChangeJdoAbstract {
+
+    @SuppressWarnings("unused")
+    private static final Logger LOG = LoggerFactory.getLogger(DomainChangeJdoAbstract.class);
+
+    public static enum ChangeType {
+        COMMAND,
+        AUDIT_ENTRY,
+        PUBLISHED_EVENT;
+        @Override
+        public String toString() {
+            return name().replace("_", " ");
+        }
+    }
+    public DomainChangeJdoAbstract(final ChangeType changeType) {
+        this.type = changeType;
+    }
+    
+    private final ChangeType type;
+    /**
+     * Distinguishes <tt>CommandJdo</tt>s, <tt>AuditEntryJdo</tt>s and <tt>PublishedEventJdo</tt>s      * when these are shown mixed together in a (standalone) table.
+     */
+    @MemberOrder(name="Identifiers", sequence = "1")
+    @Hidden(where = Where.ALL_EXCEPT_STANDALONE_TABLES)
+    public ChangeType getType() {
+        return type;
+    }
+
+
+    // //////////////////////////////////////
+
+    /**
+     * The user that caused the change.
+     * 
+     * <p>
+     * This dummy implementation is a trick so that Isis will render the property in a standalone table.  Each of the
+     * subclasses override with the &quot;real&quot; implementation.
+     */
+    @MemberOrder(name="Identifiers", sequence = "10")
+    public String getUser() {
+        return null;
+    }
+
+    // //////////////////////////////////////
+
+    
+    /**
+     * The time that the change occurred.
+     * 
+     * <p>
+     * This dummy implementation is a trick so that Isis will render the property in a standalone table.  Each of the
+     * subclasses override with the &quot;real&quot; implementation.
+     */
+    @MemberOrder(name="Identifiers", sequence = "20")
+    public Timestamp getTimestamp() {
+        return null;
+    }
+    
+    // //////////////////////////////////////
+
+    /**
+     * The unique identifier (a GUID) of the transaction in which this change occurred.
+     * 
+     * <p>
+     * This dummy implementation is a trick so that Isis will render the property in a standalone table.  Each of the
+     * subclasses override with the &quot;real&quot; implementation.
+     */
+    @MemberOrder(name="Identifiers",sequence = "50")
+    public UUID getTransactionId() {
+        return null;
+    }
+
+    // //////////////////////////////////////
+
+    /**
+     * The class of the domain object being changed.
+     * 
+     * <p>
+     * This dummy implementation is a trick so that Isis will render the property in a standalone table.  Each of the
+     * subclasses override with the &quot;real&quot; implementation.
+     */
+    @MemberOrder(name="Target", sequence = "10")
+    @Named("Class")
+    public String getTargetClass() {
+        return null;
+    }
+
+    // //////////////////////////////////////
+
+    @Programmatic
+    public Bookmark getTarget() {
+        return Util.bookmarkFor(getTargetStr());
+    }
+    
+    @Programmatic
+    public void setTarget(Bookmark target) {
+        setTargetStr(Util.asString(target));
+    }
+
+    // //////////////////////////////////////
+    
+    private String targetAction;
+    
+    /**
+     * The action invoked which caused the domain object to be changed..
+     * 
+     * <p>
+     * Populated only for <tt>CommandJdo</tt>s.
+     * 
+     * <p>
+     * This dummy implementation is a trick so that Isis will render the property in a standalone table.  Each of the
+     * subclasses override with the &quot;real&quot; implementation.
+     */
+    @Hidden(where=Where.ALL_EXCEPT_STANDALONE_TABLES)
+    @Optional
+    @MemberOrder(name="Target", sequence = "20")
+    @Named("Action")
+    public String getTargetAction() {
+        return targetAction;
+    }
+
+
+    // //////////////////////////////////////
+
+    /**
+     * The (string representation of the) {@link Bookmark} identifying the domain object that has changed.
+     * 
+     * <p>
+     * This dummy implementation is a trick so that Isis will render the property in a standalone table.  Each of the
+     * subclasses override with the &quot;real&quot; implementation.
+     */
+    @MemberOrder(name="Target", sequence="30")
+    @Named("Object")
+    public String getTargetStr() {
+        return null;
+    }
+    
+    /**
+     * For {@link #setTarget(Bookmark)} to delegate to.
+     */
+    public abstract void setTargetStr(final String targetStr);
+
+
+    // //////////////////////////////////////
+
+    @Bulk
+    @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;
+    }
+
+
+    // //////////////////////////////////////
+    
+    /**
+     * The property of the object that was changed.
+     * 
+     * <p>
+     * Populated only for <tt>AuditEntryJdo</tt>.
+     * 
+     * <p>
+     * This dummy implementation is a trick so that Isis will render the property in a standalone table.  Each of the
+     * subclasses override with the &quot;real&quot; implementation.
+     */
+    @Hidden(where=Where.ALL_EXCEPT_STANDALONE_TABLES)
+    @Optional
+    @MemberOrder(name="Target",sequence = "21")
+    public String getPropertyId() {
+        return null;
+    }
+
+    // //////////////////////////////////////
+
+
+    /**
+     * The value of the property prior to it being changed.
+     * 
+     * <p>
+     * Populated only for <tt>AuditEntryJdo</tt>.
+     * 
+     * <p>
+     * This dummy implementation is a trick so that Isis will render the property in a standalone table.  Each of the
+     * subclasses override with the &quot;real&quot; implementation.
+     */
+    @Hidden(where=Where.ALL_EXCEPT_STANDALONE_TABLES)
+    @Optional
+    @MemberOrder(name="Detail",sequence = "6")
+    public String getPreValue() {
+        return null;
+    }
+
+    
+    // //////////////////////////////////////
+
+    /**
+     * The value of the property after it has changed.
+     * 
+     * <p>
+     * Populated only for <tt>AuditEntryJdo</tt>.
+     * 
+     * <p>
+     * This dummy implementation is a trick so that Isis will render the property in a standalone table.  Each of the
+     * subclasses override with the &quot;real&quot; implementation.
+     */
+    @Hidden(where=Where.ALL_EXCEPT_STANDALONE_TABLES)
+    @Optional
+    @MemberOrder(name="Detail",sequence = "7")
+    public String getPostValue() {
+        return null;
+    }
+    
+
+    // //////////////////////////////////////
+
+    public static Comparator<DomainChangeJdoAbstract> compareByTimestampDescThenType(){
+        return ObjectContracts.compareBy("timestamp desc,type");
+    }
+
+    public static Comparator<DomainChangeJdoAbstract> compareByTargetThenTimestampDescThenType(){
+        return ObjectContracts.compareBy("targetStr,timestamp desc,type");
+    }
+    
+    public static Comparator<DomainChangeJdoAbstract> compareByTargetThenUserThenTimestampDescThenType(){
+        return ObjectContracts.compareBy("targetStr,user,timestamp desc,type");
+    }
+    
+    public static Comparator<DomainChangeJdoAbstract> compareByUserThenTimestampDescThenType(){
+        return ObjectContracts.compareBy("user,timestamp desc,type");
+    }
+    
+    public static Comparator<DomainChangeJdoAbstract> compareByUserThenTargetThenTimestampDescThenType(){
+        return ObjectContracts.compareBy("user,targetStr,timestamp desc,type");
+    }
+
+    // //////////////////////////////////////
+    // dependencies
+    // //////////////////////////////////////
+    
+    @javax.inject.Inject
+    protected BookmarkService bookmarkService;
+    
+    @javax.inject.Inject
+    protected DomainObjectContainer container;
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/JdoColumnLength.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/JdoColumnLength.java b/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/JdoColumnLength.java
new file mode 100644
index 0000000..7864aa9
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/JdoColumnLength.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;
+
+public final class JdoColumnLength {
+
+    private JdoColumnLength() {
+    }
+
+    public final static int TRANSACTION_ID = 36;
+    // ie OID str (based on the defacto limit of a request URL in web browsers such as IE8)
+    public final static int BOOKMARK = 2000; 
+    public static final int MEMBER_IDENTIFIER = 255;
+    public static final int USER_NAME = 50;
+    public final static int TARGET_CLASS = 50;
+    public final static int TARGET_ACTION = 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 Command {
+        private Command() {
+        }
+        public static final int EXECUTE_IN = 10;
+    }
+
+    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 = 255;
+        public static final int EVENT_TYPE = 20;
+        public static final int STATE = 20;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/Util.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/Util.java b/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/Util.java
new file mode 100644
index 0000000..cd6f4c9
--- /dev/null
+++ b/core/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.command.Command;
+
+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/e3c20592/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerCompositeForJdoObjectStore.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerCompositeForJdoObjectStore.java b/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerCompositeForJdoObjectStore.java
new file mode 100644
index 0000000..a985243
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerCompositeForJdoObjectStore.java
@@ -0,0 +1,45 @@
+/*
+ *  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.exceprecog;
+
+import org.apache.isis.applib.annotation.Hidden;
+import org.apache.isis.applib.services.exceprecog.ExceptionRecognizer;
+import org.apache.isis.applib.services.exceprecog.ExceptionRecognizerComposite;
+
+/**
+ * Convenience implementation of the {@link ExceptionRecognizer} domain service that
+ * recognizes a number of common and non-fatal exceptions (such as unique constraint
+ * violations).
+ * 
+ * <p>
+ * If using the JDO Object store, either register in <tt>isis.properties</tt>, or
+ * compose your own, out of the underlying more fine-grained {@link ExceptionRecognizer} implementations. 
+ */
+@Hidden
+public class ExceptionRecognizerCompositeForJdoObjectStore extends ExceptionRecognizerComposite {
+    
+    
+    public ExceptionRecognizerCompositeForJdoObjectStore() {
+        // most specific ones first
+        add(new ExceptionRecognizerForSQLIntegrityConstraintViolationUniqueOrIndexException());
+        add(new ExceptionRecognizerForJDOObjectNotFoundException());
+        add(new ExceptionRecognizerForJDODataStoreException());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForJDODataStoreException.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForJDODataStoreException.java b/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForJDODataStoreException.java
new file mode 100644
index 0000000..a79e090
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForJDODataStoreException.java
@@ -0,0 +1,31 @@
+/*
+ *  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.exceprecog;
+
+import org.apache.isis.applib.services.exceprecog.ExceptionRecognizerForType;
+
+public class ExceptionRecognizerForJDODataStoreException extends ExceptionRecognizerForType {
+
+    public ExceptionRecognizerForJDODataStoreException() {
+        super(ofTypeExcluding(javax.jdo.JDODataStoreException.class, "NOT NULL check constraint"), 
+            prefix("Unable to save changes.  " +
+            	   "Does similar data already exist, or has referenced data been deleted?"));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForJDOObjectNotFoundException.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForJDOObjectNotFoundException.java b/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForJDOObjectNotFoundException.java
new file mode 100644
index 0000000..c80a30a
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForJDOObjectNotFoundException.java
@@ -0,0 +1,31 @@
+/*
+ *  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.exceprecog;
+
+import org.apache.isis.applib.services.exceprecog.ExceptionRecognizerForType;
+
+public class ExceptionRecognizerForJDOObjectNotFoundException extends ExceptionRecognizerForType {
+
+    public ExceptionRecognizerForJDOObjectNotFoundException() {
+        super(javax.jdo.JDOObjectNotFoundException.class, 
+            prefix("Unable to load object.  " +
+            	   "Has it been deleted by someone else?"));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForSQLIntegrityConstraintViolationUniqueOrIndexException.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForSQLIntegrityConstraintViolationUniqueOrIndexException.java b/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForSQLIntegrityConstraintViolationUniqueOrIndexException.java
new file mode 100644
index 0000000..eadaa30
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForSQLIntegrityConstraintViolationUniqueOrIndexException.java
@@ -0,0 +1,30 @@
+/*
+ *  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.exceprecog;
+
+import org.apache.isis.applib.services.exceprecog.ExceptionRecognizerForType;
+
+public class ExceptionRecognizerForSQLIntegrityConstraintViolationUniqueOrIndexException extends ExceptionRecognizerForType {
+
+    public ExceptionRecognizerForSQLIntegrityConstraintViolationUniqueOrIndexException() {
+        super(ofTypeIncluding(java.sql.SQLIntegrityConstraintViolationException.class, "unique constraint or index violation"), 
+                prefix("Data already exists"));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/applib/src/test/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForSQLIntegrityConstraintViolationExceptionTest.java
----------------------------------------------------------------------
diff --git a/core/applib/src/test/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForSQLIntegrityConstraintViolationExceptionTest.java b/core/applib/src/test/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForSQLIntegrityConstraintViolationExceptionTest.java
new file mode 100644
index 0000000..35d8f5c
--- /dev/null
+++ b/core/applib/src/test/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerForSQLIntegrityConstraintViolationExceptionTest.java
@@ -0,0 +1,52 @@
+/**
+ *  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.exceprecog;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.assertThat;
+
+import java.sql.SQLIntegrityConstraintViolationException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class ExceptionRecognizerForSQLIntegrityConstraintViolationExceptionTest {
+
+    private ExceptionRecognizerForSQLIntegrityConstraintViolationUniqueOrIndexException exceptionRecognizer;
+
+    @Before
+    public void setUp() throws Exception {
+        exceptionRecognizer = new ExceptionRecognizerForSQLIntegrityConstraintViolationUniqueOrIndexException();
+    }
+    
+    @Test
+    public void uniqueConstraintOrIndexViolation() throws Exception {
+        final String msg = "initial gumph: unique constraint or index violation; further details";
+        final SQLIntegrityConstraintViolationException ex = new SQLIntegrityConstraintViolationException(msg);
+        String recognize = exceptionRecognizer.recognize(ex);
+        assertThat(recognize, is("Data already exists<br/><br/>" + msg));
+    }
+
+    @Test
+    public void notNullCheckConstraintViolation() throws Exception {
+        final String msg = "initial gumph: NOT NULL check constraint; further details";
+        final SQLIntegrityConstraintViolationException ex = new SQLIntegrityConstraintViolationException(msg);
+        String recognize = exceptionRecognizer.recognize(ex);
+        assertThat(recognize, is(nullValue()));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/metamodel/src/main/java/org/apache/isis/core/commons/ensure/Ensure.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/commons/ensure/Ensure.java b/core/metamodel/src/main/java/org/apache/isis/core/commons/ensure/Ensure.java
index 3cff2ae..6bfca7e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/commons/ensure/Ensure.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/commons/ensure/Ensure.java
@@ -45,7 +45,7 @@ public final class Ensure {
     /**
      * To ensure that the provided argument is correct.
      * 
-     * @see #ensureThatArg(Object, Matcher,State)
+     * @see #ensureThatArg(Object, Matcher, String)
      * @see #ensureThatState(Object, Matcher, String)
      * @see #ensureThatContext(Object, Matcher)
      * 

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/bookmarks/BookmarkServiceDefault.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/bookmarks/BookmarkServiceDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/bookmarks/BookmarkServiceDefault.java
index daa4370..6998c6a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/bookmarks/BookmarkServiceDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/bookmarks/BookmarkServiceDefault.java
@@ -18,8 +18,9 @@
  */
 package org.apache.isis.core.metamodel.services.bookmarks;
 
-import org.apache.isis.applib.annotation.*;
-import org.apache.isis.applib.annotation.NotContributed.As;
+import org.apache.isis.applib.annotation.DomainService;
+import org.apache.isis.applib.annotation.Hidden;
+import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.bookmark.BookmarkHolder;
 import org.apache.isis.applib.services.bookmark.BookmarkService;
@@ -31,56 +32,22 @@ import org.apache.isis.core.runtime.persistence.ObjectNotFoundException;
  * This service enables a serializable &quot;bookmark&quot; to be created for an entity.
  *
  * <p>
- * Because this service is annotated with {@link org.apache.isis.applib.annotation.DomainService} and is
- * implemented in the core.metamodel, it is automatically registered and available for use; no configuration is required.
- * </p>
+ * This implementation has no UI and there are no other implementations of the service API, and so it annotated
+ * with {@link org.apache.isis.applib.annotation.DomainService}.  Because this class is implemented in core, this means
+ * that it is automatically registered and available for use; no further configuration is required.
  */
 @DomainService
 public class BookmarkServiceDefault implements BookmarkService, DomainObjectServicesAware {
 
     private DomainObjectServices domainObjectServices;
     
-    /**
-     * Contributed action contributed to any class that implements {@link BookmarkHolder}.
-     * 
-     * <p>
-     * If required, applications can suppress by subclassing and annotating the
-     * overridden method with <tt>@Hidden</tt>:
-     * <pre>
-     * @Hidden
-     * public Object lookup(final BookmarkHolder bookmarkHolder) {
-     *     return super.lookup(bookmarkHolder);
-     * }
-     * </pre>
-     */
     @Override
-    @NotInServiceMenu
-    @NotContributed(As.ASSOCIATION)
+    @Programmatic
     public Object lookup(final BookmarkHolder bookmarkHolder) {
         Bookmark bookmark = bookmarkHolder.bookmark();
         return bookmark != null? lookup(bookmark): null;
     }
 
-    /**
-     * Contributed property (named '<tt>Object</tt>'), contributed to
-     * any class that implements {@link BookmarkHolder}.
-     * 
-     * <p>
-     * If required, applications can suppress by subclassing and annotating the
-     * overridden method with <tt>@Hidden</tt>:
-     * <pre>
-     * @Hidden
-     * public Object object(final BookmarkHolder bookmarkHolder) {
-     *     return super.object(bookmarkHolder);
-     * }
-     * </pre>
-     */
-    @NotInServiceMenu
-    @NotContributed(As.ACTION)
-    public Object object(final BookmarkHolder bookmarkHolder) {
-        return lookup(bookmarkHolder);
-    }
-    
     @Hidden
     @Override
     public Object lookup(final Bookmark bookmark) {

http://git-wip-us.apache.org/repos/asf/isis/blob/e3c20592/core/module-audit-jdo/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditEntryJdo.java
----------------------------------------------------------------------
diff --git a/core/module-audit-jdo/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditEntryJdo.java b/core/module-audit-jdo/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditEntryJdo.java
new file mode 100644
index 0000000..05592db
--- /dev/null
+++ b/core/module-audit-jdo/src/main/java/org/apache/isis/objectstore/jdo/applib/service/audit/AuditEntryJdo.java
@@ -0,0 +1,359 @@
+/*
+ *  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.sql.Timestamp;
+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.Identifier;
+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.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.util.ObjectContracts;
+import org.apache.isis.applib.util.TitleBuffer;
+import org.apache.isis.objectstore.jdo.applib.service.DomainChangeJdoAbstract;
+import org.apache.isis.objectstore.jdo.applib.service.JdoColumnLength;
+import org.apache.isis.objectstore.jdo.applib.service.Util;
+
+@javax.jdo.annotations.PersistenceCapable(
+        identityType=IdentityType.DATASTORE,
+        table="IsisAuditEntry")
+@javax.jdo.annotations.DatastoreIdentity(
+        strategy=javax.jdo.annotations.IdGeneratorStrategy.IDENTITY,
+        column="id")
+@javax.jdo.annotations.Queries( {
+    @javax.jdo.annotations.Query(
+            name="findByTransactionId", language="JDOQL",  
+            value="SELECT "
+                    + "FROM org.apache.isis.objectstore.jdo.applib.service.audit.AuditEntryJdo "
+                    + "WHERE transactionId == :transactionId"),
+    @javax.jdo.annotations.Query(
+            name="findByTargetAndTimestampBetween", language="JDOQL",  
+            value="SELECT "
+                    + "FROM org.apache.isis.objectstore.jdo.applib.service.audit.AuditEntryJdo "
+                    + "WHERE targetStr == :targetStr " 
+                    + "&& timestamp >= :from " 
+                    + "&& timestamp <= :to "
+                    + "ORDER BY timestamp DESC"),
+    @javax.jdo.annotations.Query(
+            name="findByTargetAndTimestampAfter", language="JDOQL",  
+            value="SELECT "
+                    + "FROM org.apache.isis.objectstore.jdo.applib.service.audit.AuditEntryJdo "
+                    + "WHERE targetStr == :targetStr " 
+                    + "&& timestamp >= :from "
+                    + "ORDER BY timestamp DESC"),
+    @javax.jdo.annotations.Query(
+            name="findByTargetAndTimestampBefore", language="JDOQL",  
+            value="SELECT "
+                    + "FROM org.apache.isis.objectstore.jdo.applib.service.audit.AuditEntryJdo "
+                    + "WHERE targetStr == :targetStr " 
+                    + "&& timestamp <= :to "
+                    + "ORDER BY timestamp DESC"),
+    @javax.jdo.annotations.Query(
+            name="findByTarget", language="JDOQL",  
+            value="SELECT "
+                    + "FROM org.apache.isis.objectstore.jdo.applib.service.audit.AuditEntryJdo "
+                    + "WHERE targetStr == :targetStr " 
+                    + "ORDER BY timestamp DESC"),
+    @javax.jdo.annotations.Query(
+            name="findByTimestampBetween", language="JDOQL",  
+            value="SELECT "
+                    + "FROM org.apache.isis.objectstore.jdo.applib.service.audit.AuditEntryJdo "
+                    + "WHERE timestamp >= :from " 
+                    + "&&    timestamp <= :to "
+                    + "ORDER BY timestamp DESC"),
+    @javax.jdo.annotations.Query(
+            name="findByTimestampAfter", language="JDOQL",  
+            value="SELECT "
+                    + "FROM org.apache.isis.objectstore.jdo.applib.service.audit.AuditEntryJdo "
+                    + "WHERE timestamp >= :from "
+                    + "ORDER BY timestamp DESC"),
+    @javax.jdo.annotations.Query(
+            name="findByTimestampBefore", language="JDOQL",  
+            value="SELECT "
+                    + "FROM org.apache.isis.objectstore.jdo.applib.service.audit.AuditEntryJdo "
+                    + "WHERE timestamp <= :to "
+                    + "ORDER BY timestamp DESC"),
+    @javax.jdo.annotations.Query(
+            name="find", language="JDOQL",  
+            value="SELECT "
+                    + "FROM org.apache.isis.objectstore.jdo.applib.service.audit.AuditEntryJdo "
+                    + "ORDER BY timestamp DESC")
+})
+@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")
+@ObjectType("IsisAuditEntry")
+@MemberGroupLayout(
+        columnSpans={6,0,6},
+        left={"Identifiers","Target"},
+        right={"Detail"})
+public class AuditEntryJdo extends DomainChangeJdoAbstract implements HasTransactionId {
+
+    public AuditEntryJdo() {
+        super(ChangeType.AUDIT_ENTRY);
+    }
+
+    // //////////////////////////////////////
+    // Identification
+    // //////////////////////////////////////
+
+    public String title() {
+        final TitleBuffer buf = new TitleBuffer();
+        buf.append(
+        new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(getTimestamp()));
+        buf.append(",", getUser());
+        buf.append(":", getTargetStr());
+        buf.append(" ", getMemberIdentifier());
+        return buf.toString();
+    }
+    
+
+    // //////////////////////////////////////
+    // user (property)
+    // //////////////////////////////////////
+
+    private String user;
+
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.USER_NAME)
+    @Hidden(where=Where.PARENTED_TABLES)
+    @MemberOrder(name="Identifiers",sequence = "10")
+    public String getUser() {
+        return user;
+    }
+
+    public void setUser(final String user) {
+        this.user = user;
+    }
+    
+
+    // //////////////////////////////////////
+    // timestamp (property)
+    // //////////////////////////////////////
+
+    private Timestamp timestamp;
+
+    @javax.jdo.annotations.Column(allowsNull="false")
+    @Hidden(where=Where.PARENTED_TABLES)
+    @MemberOrder(name="Identifiers",sequence = "20")
+    public Timestamp getTimestamp() {
+        return timestamp;
+    }
+
+    public void setTimestamp(final Timestamp timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    
+
+
+    // //////////////////////////////////////
+    // transactionId (property)
+    // //////////////////////////////////////
+    
+    private UUID transactionId;
+
+    /**
+     * 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="false", length=JdoColumnLength.TRANSACTION_ID)
+    @TypicalLength(36)
+    @MemberOrder(name="Identifiers",sequence = "30")
+    @Hidden(where=Where.PARENTED_TABLES)
+    @Disabled
+    @Override
+    public UUID getTransactionId() {
+        return transactionId;
+    }
+
+    @Override
+    public void setTransactionId(final UUID transactionId) {
+        this.transactionId = transactionId;
+    }
+
+
+    // //////////////////////////////////////
+    // targetClass (property)
+    // //////////////////////////////////////
+
+    private String targetClass;
+
+    @javax.jdo.annotations.Column(allowsNull="true", length=JdoColumnLength.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.TARGET_CLASS);
+    }
+
+
+    // //////////////////////////////////////
+    // target (property)
+    // openTargetObject (action)
+    // //////////////////////////////////////
+
+    private String targetStr;
+
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.BOOKMARK, name="target")
+    @Named("Object")
+    @MemberOrder(name="Target", sequence="30")
+    public String getTargetStr() {
+        return targetStr;
+    }
+
+    public void setTargetStr(final String targetStr) {
+        this.targetStr = targetStr;
+    }
+
+    
+    // //////////////////////////////////////
+    // memberIdentifier (property)
+    // //////////////////////////////////////
+
+    private String memberIdentifier;
+
+    /**
+     * This is the fully-qualified class and property Id, as per
+     * {@link Identifier#toClassAndNameIdentityString()}.
+     */
+    @javax.jdo.annotations.Column(allowsNull="true", length=JdoColumnLength.MEMBER_IDENTIFIER)
+    @TypicalLength(60)
+    @Hidden(where=Where.ALL_TABLES)
+    @MemberOrder(name="Detail",sequence = "1")
+    public String getMemberIdentifier() {
+        return memberIdentifier;
+    }
+
+    public void setMemberIdentifier(final String memberIdentifier) {
+        this.memberIdentifier = Util.abbreviated(memberIdentifier, JdoColumnLength.MEMBER_IDENTIFIER);
+    }
+
+
+    // //////////////////////////////////////
+    // propertyId (property)
+    // //////////////////////////////////////
+    
+    private String propertyId;
+
+    /**
+     * This is the property name (without the class).
+     */
+    @javax.jdo.annotations.Column(allowsNull="true", length=JdoColumnLength.AuditEntry.PROPERTY_ID)
+    @Hidden(where=Where.NOWHERE)
+    @MemberOrder(name="Target",sequence = "20")
+    public String getPropertyId() {
+        return propertyId;
+    }
+    
+    public void setPropertyId(final String propertyId) {
+        this.propertyId = Util.abbreviated(propertyId, JdoColumnLength.AuditEntry.PROPERTY_ID);
+    }
+    
+    
+    // //////////////////////////////////////
+    // preValue (property)
+    // //////////////////////////////////////
+
+    private String preValue;
+
+    @javax.jdo.annotations.Column(allowsNull="true", length=JdoColumnLength.AuditEntry.PROPERTY_VALUE)
+    @Hidden(where=Where.NOWHERE)
+    @MemberOrder(name="Detail",sequence = "6")
+    public String getPreValue() {
+        return preValue;
+    }
+
+    public void setPreValue(final String preValue) {
+        this.preValue = Util.abbreviated(preValue, JdoColumnLength.AuditEntry.PROPERTY_VALUE);
+    }
+    
+    
+    // //////////////////////////////////////
+    // postValue (property)
+    // //////////////////////////////////////
+
+    private String postValue;
+
+    @javax.jdo.annotations.Column(allowsNull="true", length=JdoColumnLength.AuditEntry.PROPERTY_VALUE)
+    @Hidden(where=Where.NOWHERE)
+    @MemberOrder(name="Detail",sequence = "7")
+    public String getPostValue() {
+        return postValue;
+    }
+
+    public void setPostValue(final String postValue) {
+        this.postValue = Util.abbreviated(postValue, JdoColumnLength.AuditEntry.PROPERTY_VALUE);
+    }
+    
+    
+    
+    // //////////////////////////////////////
+    // toString
+    // //////////////////////////////////////
+
+    @Override
+    public String toString() {
+        return ObjectContracts.toString(this, "timestamp,user,targetStr,memberIdentifier");
+    }
+
+    
+    // //////////////////////////////////////
+    // Injected services
+    // //////////////////////////////////////
+
+
+    @javax.inject.Inject
+    private BookmarkService bookmarkService;
+
+    @javax.inject.Inject
+    private DomainObjectContainer container;
+}