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/09/25 11:52:22 UTC

[3/7] ISIS-887: mothballed the core/module* modules, moved to mothballed/core/module*

http://git-wip-us.apache.org/repos/asf/isis/blob/790e70df/mothballed/core/module-command-jdo/src/main/java/org/apache/isis/objectstore/jdo/applib/service/command/CommandJdo.java
----------------------------------------------------------------------
diff --git a/mothballed/core/module-command-jdo/src/main/java/org/apache/isis/objectstore/jdo/applib/service/command/CommandJdo.java b/mothballed/core/module-command-jdo/src/main/java/org/apache/isis/objectstore/jdo/applib/service/command/CommandJdo.java
new file mode 100644
index 0000000..fb5fabc
--- /dev/null
+++ b/mothballed/core/module-command-jdo/src/main/java/org/apache/isis/objectstore/jdo/applib/service/command/CommandJdo.java
@@ -0,0 +1,740 @@
+/**
+ *  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.command;
+
+import java.math.BigDecimal;
+import java.sql.Timestamp;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.jdo.annotations.IdentityType;
+import javax.jdo.annotations.NotPersistent;
+
+import com.google.common.collect.Maps;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.isis.applib.DomainObjectContainer;
+import org.apache.isis.applib.annotation.ActionSemantics;
+import org.apache.isis.applib.annotation.ActionSemantics.Of;
+import org.apache.isis.applib.annotation.Bulk;
+import org.apache.isis.applib.annotation.Command.ExecuteIn;
+import org.apache.isis.applib.annotation.Command.Persistence;
+import org.apache.isis.applib.annotation.Hidden;
+import org.apache.isis.applib.annotation.Immutable;
+import org.apache.isis.applib.annotation.Mandatory;
+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.TypicalLength;
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.applib.services.bookmark.BookmarkService;
+import org.apache.isis.applib.services.command.Command;
+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;
+import org.apache.isis.objectstore.jdo.applib.service.DomainChangeJdoAbstract.ChangeType;
+
+
+@javax.jdo.annotations.PersistenceCapable(
+        identityType=IdentityType.APPLICATION, 
+        table="IsisCommand")
+@javax.jdo.annotations.Queries( {
+    @javax.jdo.annotations.Query(
+            name="findByTransactionId", language="JDOQL",  
+            value="SELECT "
+                    + "FROM org.apache.isis.objectstore.jdo.applib.service.command.CommandJdo "
+                    + "WHERE transactionId == :transactionId "),
+    @javax.jdo.annotations.Query(
+            name="findBackgroundCommandByTransactionId", language="JDOQL",  
+            value="SELECT "
+                    + "FROM org.apache.isis.objectstore.jdo.applib.service.command.CommandJdo "
+                    + "WHERE transactionId == :transactionId "
+                    + "&& executeIn == 'BACKGROUND'"),
+    @javax.jdo.annotations.Query(
+            name="findBackgroundCommandsByParent", language="JDOQL",  
+            value="SELECT "
+                    + "FROM org.apache.isis.objectstore.jdo.applib.service.command.CommandJdo "
+                    + "WHERE parent == :parent "
+                    + "&& executeIn == 'BACKGROUND'"),
+    @javax.jdo.annotations.Query(
+            name="findBackgroundCommandsNotYetStarted", language="JDOQL",  
+            value="SELECT "
+                    + "FROM org.apache.isis.objectstore.jdo.applib.service.command.CommandJdo "
+                    + "WHERE executeIn == 'BACKGROUND' "
+                    + "&& startedAt == null "
+                    + "ORDER BY timestamp ASC "
+                    ),
+    @javax.jdo.annotations.Query(
+            name="findCurrent", language="JDOQL",  
+            value="SELECT "
+                    + "FROM org.apache.isis.objectstore.jdo.applib.service.command.CommandJdo "
+                    + "WHERE completedAt == null "
+                    + "ORDER BY timestamp DESC"),
+    @javax.jdo.annotations.Query(
+            name="findCompleted", language="JDOQL",  
+            value="SELECT "
+                    + "FROM org.apache.isis.objectstore.jdo.applib.service.command.CommandJdo "
+                    + "WHERE completedAt != null "
+                    + "&& executeIn == 'FOREGROUND' "
+                    + "ORDER BY timestamp DESC"),
+    @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")
+})
+@ObjectType("IsisCommand")
+@MemberGroupLayout(
+        columnSpans={6,0,6,12}, 
+        left={"Identifiers","Target","Notes"},
+        right={"Detail","Timings","Results"})
+@Named("Command")
+@Immutable
+public class CommandJdo extends DomainChangeJdoAbstract implements Command {
+
+    @SuppressWarnings("unused")
+    private static final Logger LOG = LoggerFactory.getLogger(CommandJdo.class);
+
+    public CommandJdo() {
+        super(ChangeType.COMMAND);
+    }
+
+
+
+    // //////////////////////////////////////
+    // Identification
+    // //////////////////////////////////////
+
+    public String title() {
+        final TitleBuffer buf = new TitleBuffer();
+        buf.append(getTargetStr());
+        buf.append(" ").append(getMemberIdentifier());
+        return buf.toString();
+    }
+
+
+
+    // //////////////////////////////////////
+    // user (property)
+    // //////////////////////////////////////
+
+    private String user;
+
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.USER_NAME)
+    @MemberOrder(name="Identifiers", sequence = "10")
+    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 action was created.
+     */
+    @javax.jdo.annotations.Persistent
+    @javax.jdo.annotations.Column(allowsNull="false")
+    @MemberOrder(name="Identifiers", sequence = "20")
+    public Timestamp getTimestamp() {
+        return timestamp;
+    }
+    
+    /**
+     * <b>NOT API</b>: intended to be called only by the framework.
+     */
+    public void setTimestamp(final Timestamp timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    
+    // //////////////////////////////////////
+    // executor (property)
+    // //////////////////////////////////////
+    
+    private Executor executor;
+    
+    @Programmatic
+    @javax.jdo.annotations.NotPersistent
+    @Override
+    public Executor getExecutor() {
+        return executor;
+    }
+
+    @Override
+    public void setExecutor(Executor nature) {
+        this.executor = nature;
+    }
+
+    // //////////////////////////////////////
+    // executeIn (property)
+    // //////////////////////////////////////
+
+    private ExecuteIn executeIn;
+
+    /**
+     * Whether the action was invoked explicitly by the user, or scheduled as a background
+     * task, or as for some other reason, eg a side-effect of rendering an object due to 
+     * get-after-post).
+     */
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.Command.EXECUTE_IN)
+    @MemberOrder(name="Identifiers", sequence = "32")
+    @Override
+    public ExecuteIn getExecuteIn() {
+        return executeIn;
+    }
+    
+    /**
+     * <b>NOT API</b>: intended to be called only by the framework.
+     */
+    @Override
+    public void setExecuteIn(ExecuteIn nature) {
+        this.executeIn = nature;
+    }
+
+
+    // //////////////////////////////////////
+    // parent (property)
+    // //////////////////////////////////////
+
+    private Command parent;
+    
+    @Override
+    @javax.jdo.annotations.Persistent
+    @javax.jdo.annotations.Column(name="parentTransactionId", allowsNull="true")
+    @Hidden(where=Where.PARENTED_TABLES)
+    @MemberOrder(name="Identifiers",sequence = "40")
+    public Command getParent() {
+        return parent;
+    }
+
+    @Override
+    public void setParent(Command parent) {
+        this.parent = parent;
+    }
+
+    
+    // //////////////////////////////////////
+    // transactionId (property)
+    // //////////////////////////////////////
+
+        
+    private UUID transactionId;
+
+    /**
+     * The unique identifier (a GUID) of the transaction in which this command occurred.
+     */
+    @javax.jdo.annotations.PrimaryKey
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.TRANSACTION_ID)
+    @TypicalLength(JdoColumnLength.TRANSACTION_ID)
+    @MemberOrder(name="Identifiers",sequence = "50")
+    @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 command is persisted.
+     */
+    @Override
+    public void setTransactionId(final UUID transactionId) {
+        this.transactionId = transactionId;
+    }
+
+    
+    // //////////////////////////////////////
+    // targetClass (property)
+    // //////////////////////////////////////
+
+    private String targetClass;
+
+    @javax.jdo.annotations.Column(allowsNull="false", 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);
+    }
+
+
+    // //////////////////////////////////////
+    // targetAction (property)
+    // //////////////////////////////////////
+    
+    private String targetAction;
+    
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.TARGET_ACTION)
+    @Mandatory
+    @Hidden(where=Where.NOWHERE)
+    @TypicalLength(30)
+    @MemberOrder(name="Target", sequence = "20")
+    @Named("Action")
+    public String getTargetAction() {
+        return targetAction;
+    }
+    
+    public void setTargetAction(final String targetAction) {
+        this.targetAction = Util.abbreviated(targetAction, JdoColumnLength.TARGET_ACTION);
+    }
+    
+
+    // //////////////////////////////////////
+    // target (property)
+    // openTargetObject (action)
+    // //////////////////////////////////////
+
+    private String targetStr;
+    @javax.jdo.annotations.Column(allowsNull="false", length=JdoColumnLength.BOOKMARK, name="target")
+    @Hidden(where=Where.ALL_TABLES)
+    @MemberOrder(name="Target", sequence="30")
+    @Named("Object")
+    public String getTargetStr() {
+        return targetStr;
+    }
+
+    public void setTargetStr(final String targetStr) {
+        this.targetStr = targetStr;
+    }
+
+    // //////////////////////////////////////
+    // arguments (property)
+    // //////////////////////////////////////
+    
+    private String arguments;
+    
+    @javax.jdo.annotations.Column(allowsNull="true", jdbcType="CLOB")
+    @MultiLine(numberOfLines=7)
+    @Hidden(where=Where.ALL_TABLES)
+    @MemberOrder(name="Target",sequence = "40")
+    public String getArguments() {
+        return arguments;
+    }
+    
+    public void setArguments(final String arguments) {
+        this.arguments = arguments;
+    }
+
+    
+
+    // //////////////////////////////////////
+    // memberIdentifier (property)
+    // //////////////////////////////////////
+
+    private String memberIdentifier;
+    
+    @javax.jdo.annotations.Column(allowsNull="false", 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);
+    }
+
+
+
+    // //////////////////////////////////////
+    // memento (property)
+    // //////////////////////////////////////
+    
+    private String memento;
+    
+    @javax.jdo.annotations.Column(allowsNull="true", jdbcType="CLOB")
+    @MultiLine(numberOfLines=9)
+    @Hidden(where=Where.ALL_TABLES)
+    @MemberOrder(name="Detail",sequence = "30")
+    public String getMemento() {
+        return memento;
+    }
+    
+    public void setMemento(final String memento) {
+        this.memento = memento;
+    }
+
+
+
+    // //////////////////////////////////////
+    // startedAt (derived property)
+    // //////////////////////////////////////
+    
+    private Timestamp startedAt;
+
+    @javax.jdo.annotations.Persistent
+    @javax.jdo.annotations.Column(allowsNull="true")
+    @MemberOrder(name="Timings", sequence = "3")
+    public Timestamp getStartedAt() {
+        return startedAt;
+    }
+
+    /**
+     * <b>NOT API</b>: intended to be called only by the framework.
+     */
+    public void setStartedAt(final Timestamp startedAt) {
+        this.startedAt = startedAt;
+    }
+    
+    
+    
+    // //////////////////////////////////////
+    // completedAt (property)
+    // //////////////////////////////////////
+
+    private Timestamp completedAt;
+
+    /**
+     * The date/time at which this interaction completed.
+     */
+    @javax.jdo.annotations.Persistent
+    @javax.jdo.annotations.Column(allowsNull="true")
+    @MemberOrder(name="Timings", sequence = "4")
+    @Override
+    public Timestamp getCompletedAt() {
+        return completedAt;
+    }
+
+    @Override
+    public void setCompletedAt(final Timestamp completed) {
+        this.completedAt = completed;
+    }
+
+
+    // //////////////////////////////////////
+    // duration (derived property)
+    // //////////////////////////////////////
+
+    /**
+     * The number of seconds (to 3 decimal places) that this interaction lasted.
+     * 
+     * <p>
+     * Populated only if it has {@link #getCompletedAt() completed}.
+     */
+    @javax.validation.constraints.Digits(integer=5, fraction=3)
+    @Named("Duration")
+    @MemberOrder(name="Timings", sequence = "7")
+    public BigDecimal getDuration() {
+        return Util.durationBetween(getStartedAt(), getCompletedAt());
+    }
+
+
+
+    // //////////////////////////////////////
+    // complete (derived property)
+    // //////////////////////////////////////
+    
+
+    @javax.jdo.annotations.NotPersistent
+    @MemberOrder(name="Timings", sequence = "8")
+    @Hidden(where=Where.OBJECT_FORMS)
+    public boolean isComplete() {
+        return getCompletedAt() != null;
+    }
+
+    
+    
+    // //////////////////////////////////////
+    // state (derived property)
+    // //////////////////////////////////////
+
+    @javax.jdo.annotations.NotPersistent
+    @MemberOrder(name="Results",sequence = "10")
+    @Hidden(where=Where.OBJECT_FORMS)
+    @Named("Result")
+    public String getResultSummary() {
+        if(getCompletedAt() == null) {
+            return "";
+        }
+        if(getException() != null) {
+            return "EXCEPTION";
+        } 
+        if(getResultStr() != null) {
+            return "OK";
+        } else {
+            return "OK (VOID)";
+        }
+    }
+
+    
+    // //////////////////////////////////////
+    // result (property)
+    // openResultObject (action)
+    // //////////////////////////////////////
+    
+    @Programmatic
+    @Override
+    public Bookmark getResult() {
+        return Util.bookmarkFor(getResultStr());
+    }
+
+    @Programmatic
+    @Override
+    public void setResult(Bookmark result) {
+        setResultStr(Util.asString(result));
+    }
+
+    // //////////////////////////////////////
+    
+    private String resultStr;
+
+    @javax.jdo.annotations.Column(allowsNull="true", length=JdoColumnLength.BOOKMARK, name="result")
+    @Hidden(where=Where.ALL_TABLES)
+    @Named("Result Bookmark")
+    @MemberOrder(name="Results", sequence="25")
+    public String getResultStr() {
+        return resultStr;
+    }
+
+    public void setResultStr(final String resultStr) {
+        this.resultStr = resultStr;
+    }
+
+    // //////////////////////////////////////
+
+    @ActionSemantics(Of.SAFE)
+    @MemberOrder(name="ResultStr", sequence="1")
+    @Named("Open")
+    public Object openResultObject() {
+        return Util.lookupBookmark(getResult(), bookmarkService, container);
+    }
+    public boolean hideOpenResultObject() {
+        return getResult() == null;
+    }
+
+
+    // //////////////////////////////////////
+    // exception (property)
+    // causedException (derived property)
+    // showException (associated action)
+    // //////////////////////////////////////
+
+    private String exception;
+
+    /**
+     * Stack trace of any exception that might have occurred if this interaction/transaction aborted.
+     * 
+     * <p>
+     * Not visible in the UI, but accessible 
+     * <p>
+     * Not part of the applib API, because the default implementation is not persistent
+     * and so there's no object that can be accessed to be annotated.
+     */
+    @javax.jdo.annotations.Column(allowsNull="true", jdbcType="CLOB")
+    @Hidden
+    @Override
+    public String getException() {
+        return exception;
+    }
+
+    @Override
+    public void setException(final String exception) {
+        this.exception = exception;
+    }
+    
+    
+    // //////////////////////////////////////
+    
+    @javax.jdo.annotations.NotPersistent
+    @MemberOrder(name="Results",sequence = "30")
+    @Hidden(where=Where.ALL_TABLES)
+    public boolean isCausedException() {
+        return getException() != null;
+    }
+
+    
+    // //////////////////////////////////////
+    
+    @ActionSemantics(Of.SAFE)
+    @MemberOrder(name="causedException", sequence = "1")
+    public String showException() {
+        return getException();
+    }
+    public boolean hideShowException() {
+        return !isCausedException();
+    }
+
+
+    // //////////////////////////////////////
+    // next(...) impl
+    // //////////////////////////////////////
+
+    private final Map<String, AtomicInteger> sequenceByName = Maps.newHashMap();
+
+
+
+    @Programmatic
+    @Override
+    public int next(String sequenceName) {
+        AtomicInteger next = sequenceByName.get(sequenceName);
+        if(next == null) {
+            next = new AtomicInteger(0);
+            sequenceByName.put(sequenceName, next);
+        } else {
+            next.incrementAndGet();
+        }
+        return next.get();
+    }
+
+    
+    // //////////////////////////////////////
+    // persistence (programmatic)
+    // //////////////////////////////////////
+
+    private Persistence persistence;
+    
+    @javax.jdo.annotations.NotPersistent
+    @Programmatic
+    @Override
+    public Persistence getPersistence() {
+        return persistence;
+    }
+
+    @Override
+    public void setPersistence(Persistence persistence) {
+        this.persistence = persistence;
+    }
+
+
+    // //////////////////////////////////////
+    // setPersistHint (SPI impl)
+    // //////////////////////////////////////
+    
+    private boolean persistHint;
+
+    @NotPersistent
+    @Programmatic
+    public boolean isPersistHint() {
+        return persistHint;
+    }
+    
+    @Programmatic
+    @Override
+    public void setPersistHint(boolean persistHint) {
+        this.persistHint = persistHint;
+    }
+
+    
+    // //////////////////////////////////////
+    
+    @Programmatic
+    boolean shouldPersist() {
+        if(Persistence.PERSISTED == getPersistence()) {
+            return true;
+        }
+        if(Persistence.IF_HINTED == getPersistence()) {
+            return isPersistHint();
+        }
+        return false;
+    }
+
+
+
+    // //////////////////////////////////////
+    // toString
+    // //////////////////////////////////////
+
+    @Override
+    public String toString() {
+        return ObjectContracts.toString(this, "targetStr,memberIdentifier,user,startedAt,completedAt,duration,transactionId");
+    }
+
+    
+    
+    // //////////////////////////////////////
+    // dependencies
+    // //////////////////////////////////////
+    
+
+    @javax.inject.Inject
+    private BookmarkService bookmarkService;
+    
+    @javax.inject.Inject
+    private DomainObjectContainer container;
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/790e70df/mothballed/core/module-command-jdo/src/main/java/org/apache/isis/objectstore/jdo/applib/service/command/CommandServiceJdo.java
----------------------------------------------------------------------
diff --git a/mothballed/core/module-command-jdo/src/main/java/org/apache/isis/objectstore/jdo/applib/service/command/CommandServiceJdo.java b/mothballed/core/module-command-jdo/src/main/java/org/apache/isis/objectstore/jdo/applib/service/command/CommandServiceJdo.java
new file mode 100644
index 0000000..45616c8
--- /dev/null
+++ b/mothballed/core/module-command-jdo/src/main/java/org/apache/isis/objectstore/jdo/applib/service/command/CommandServiceJdo.java
@@ -0,0 +1,119 @@
+/**
+ *  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.command;
+
+import java.util.UUID;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.isis.applib.AbstractService;
+import org.apache.isis.applib.annotation.Command.ExecuteIn;
+import org.apache.isis.applib.annotation.Command.Persistence;
+import org.apache.isis.applib.annotation.DomainService;
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.clock.Clock;
+import org.apache.isis.applib.services.command.Command;
+import org.apache.isis.applib.services.command.Command.Executor;
+import org.apache.isis.applib.services.command.spi.CommandService;
+
+/**
+ *
+ */
+@DomainService
+public class CommandServiceJdo extends AbstractService implements CommandService {
+
+    @SuppressWarnings("unused")
+    private static final Logger LOG = LoggerFactory.getLogger(CommandServiceJdo.class);
+
+    /**
+     * Creates an {@link CommandJdo}, initializing its 
+     * {@link Command#setExecuteIn(Command.ExecuteIn) nature} to be
+     * {@link Command.ExecuteIn#OTHER rendering}.
+     */
+    @Programmatic
+    @Override
+    public Command create() {
+        CommandJdo command = newTransientInstance(CommandJdo.class);
+        command.setExecutor(Executor.OTHER);
+        command.setPersistence(Persistence.IF_HINTED);
+        return command;
+    }
+
+    @Programmatic
+    @Override
+    public void startTransaction(final Command command, final UUID transactionId) {
+        if(command instanceof CommandJdo) {
+            // should be the case, since this service created the object in the #create() method
+            final CommandJdo commandJdo = (CommandJdo) command;
+            final UUID currentTransactionId = commandJdo.getTransactionId();
+            if(currentTransactionId != null && !currentTransactionId.equals(transactionId)) {
+                // the logic in IsisTransaction means that any subsequent transactions within a given command
+                // should reuse the xactnId of the first transaction created within that interaction.
+                throw new IllegalStateException("Attempting to set a different transactionId on command");
+            }
+            commandJdo.setTransactionId(transactionId);
+        }
+    }
+
+    @Programmatic
+    @Override
+    public void complete(final Command command) {
+        final CommandJdo commandJdo = asUserInitiatedCommandJdo(command);
+        if(commandJdo == null) {
+            return;
+        }
+        if(commandJdo.getCompletedAt() != null) {
+            // already attempted to complete.
+            // chances are, we're here as the result of a redirect following a previous exception
+            // so just ignore.
+            return;
+        }
+            
+        commandJdo.setCompletedAt(Clock.getTimeAsJavaSqlTimestamp());
+        persistIfNotAlready(commandJdo);
+    }
+
+    @Override
+    public boolean persistIfPossible(Command command) {
+        if(!(command instanceof CommandJdo)) {
+            // ought not to be the case, since this service created the object in the #create() method
+            return false;
+        }
+        final CommandJdo commandJdo = (CommandJdo)command;
+        persistIfNotAlready(commandJdo);
+        return true;
+    }
+    
+    
+    /**
+     * Not API, also used by {@link CommandServiceJdoRepository}.
+     */
+    CommandJdo asUserInitiatedCommandJdo(final Command command) {
+        if(!(command instanceof CommandJdo)) {
+            // ought not to be the case, since this service created the object in the #create() method
+            return null;
+        }
+        if(command.getExecuteIn() != ExecuteIn.FOREGROUND) {
+            return null;
+        } 
+        final CommandJdo commandJdo = (CommandJdo) command;
+        return commandJdo.shouldPersist()? commandJdo: null;
+    }
+
+    
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/790e70df/mothballed/core/module-command-jdo/src/main/java/org/apache/isis/objectstore/jdo/applib/service/command/CommandServiceJdoContributions.java
----------------------------------------------------------------------
diff --git a/mothballed/core/module-command-jdo/src/main/java/org/apache/isis/objectstore/jdo/applib/service/command/CommandServiceJdoContributions.java b/mothballed/core/module-command-jdo/src/main/java/org/apache/isis/objectstore/jdo/applib/service/command/CommandServiceJdoContributions.java
new file mode 100644
index 0000000..6142d30
--- /dev/null
+++ b/mothballed/core/module-command-jdo/src/main/java/org/apache/isis/objectstore/jdo/applib/service/command/CommandServiceJdoContributions.java
@@ -0,0 +1,70 @@
+/**
+ *  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.command;
+
+import java.util.UUID;
+import org.apache.isis.applib.AbstractFactoryAndRepository;
+import org.apache.isis.applib.annotation.MemberOrder;
+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.services.HasTransactionId;
+import org.apache.isis.applib.services.command.Command;
+
+
+/**
+ * This service contributes a <tt>command</tt> action to any (non-command) implementation of
+ * {@link org.apache.isis.applib.services.HasTransactionId}; that is: audit entries, and published events.  Thus, it
+ * is possible to navigate from the effect back to the cause.
+ *
+ * <p>
+ * Because this service influences the UI, it must be explicitly registered as a service
+ * (eg using <tt>isis.properties</tt>).
+ */
+public class CommandServiceJdoContributions extends AbstractFactoryAndRepository {
+
+    @NotInServiceMenu
+    @NotContributed(As.ASSOCIATION) // ie contributed as an action
+    @MemberOrder(name="transactionId", sequence="1")
+    public CommandJdo command(final HasTransactionId hasTransactionId) {
+        return commandServiceRepository.findByTransactionId(hasTransactionId.getTransactionId());
+    }
+    /**
+     * Hide if the contributee is a {@link Command}, because {@link Command}s already have a
+     * {@link Command#getParent() parent} property.
+     */
+    public boolean hideCommand(final HasTransactionId hasTransactionId) {
+        return (hasTransactionId instanceof Command);
+    }
+    public String disableCommand(final HasTransactionId hasTransactionId) {
+        if(hasTransactionId == null) {
+            return "No transaction Id";
+        }
+        final UUID transactionId = hasTransactionId.getTransactionId();
+        final boolean command = commandServiceRepository.findByTransactionId(transactionId) == null;
+        return command? "No command found for transaction Id": null;
+    }
+
+
+    // //////////////////////////////////////
+
+    
+    @javax.inject.Inject
+    private CommandServiceJdoRepository commandServiceRepository;
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/790e70df/mothballed/core/module-command-jdo/src/main/java/org/apache/isis/objectstore/jdo/applib/service/command/CommandServiceJdoRepository.java
----------------------------------------------------------------------
diff --git a/mothballed/core/module-command-jdo/src/main/java/org/apache/isis/objectstore/jdo/applib/service/command/CommandServiceJdoRepository.java b/mothballed/core/module-command-jdo/src/main/java/org/apache/isis/objectstore/jdo/applib/service/command/CommandServiceJdoRepository.java
new file mode 100644
index 0000000..8d573a2
--- /dev/null
+++ b/mothballed/core/module-command-jdo/src/main/java/org/apache/isis/objectstore/jdo/applib/service/command/CommandServiceJdoRepository.java
@@ -0,0 +1,169 @@
+/**
+ *  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.command;
+
+import java.sql.Timestamp;
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.LocalDate;
+
+import org.apache.isis.applib.AbstractFactoryAndRepository;
+import org.apache.isis.applib.annotation.DomainService;
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.query.Query;
+import org.apache.isis.applib.query.QueryDefault;
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.applib.services.command.Command;
+import org.apache.isis.applib.services.command.CommandContext;
+
+
+/**
+ * Provides supporting functionality for querying and persisting
+ * {@link org.apache.isis.objectstore.jdo.applib.service.command.CommandJdo command} entities.
+ *
+ * <p>
+ * This supporting service with no UI and no side-effects, and is there are no other implementations of the service,
+ * thus has been annotated with {@link org.apache.isis.applib.annotation.DomainService}.  This means that there is no
+ * need to explicitly register it as a service (eg in <tt>isis.properties</tt>).
+ */
+@DomainService
+public class CommandServiceJdoRepository extends AbstractFactoryAndRepository {
+
+    @Programmatic
+    public List<CommandJdo> findByFromAndTo(
+            final LocalDate from, final LocalDate to) {
+        final Timestamp fromTs = toTimestampStartOfDayWithOffset(from, 0);
+        final Timestamp toTs = toTimestampStartOfDayWithOffset(to, 1);
+        
+        final Query<CommandJdo> query;
+        if(from != null) {
+            if(to != null) {
+                query = new QueryDefault<CommandJdo>(CommandJdo.class, 
+                        "findByTimestampBetween", 
+                        "from", fromTs,
+                        "to", toTs);
+            } else {
+                query = new QueryDefault<CommandJdo>(CommandJdo.class, 
+                        "findByTimestampAfter", 
+                        "from", fromTs);
+            }
+        } else {
+            if(to != null) {
+                query = new QueryDefault<CommandJdo>(CommandJdo.class, 
+                        "findByTimestampBefore", 
+                        "to", toTs);
+            } else {
+                query = new QueryDefault<CommandJdo>(CommandJdo.class, 
+                        "find");
+            }
+        }
+        return allMatches(query);
+    }
+
+
+    @Programmatic
+    public CommandJdo findByTransactionId(final UUID transactionId) {
+        persistCurrentCommandIfRequired();
+        return firstMatch(
+                new QueryDefault<CommandJdo>(CommandJdo.class, 
+                        "findByTransactionId", 
+                        "transactionId", transactionId));
+    }
+
+    @Programmatic
+    public List<CommandJdo> findCurrent() {
+        persistCurrentCommandIfRequired();
+        return allMatches(
+                new QueryDefault<CommandJdo>(CommandJdo.class, "findCurrent"));
+    }
+    
+    @Programmatic
+    public List<CommandJdo> findCompleted() {
+        persistCurrentCommandIfRequired();
+        return allMatches(
+                new QueryDefault<CommandJdo>(CommandJdo.class, "findCompleted"));
+    }
+
+    private void persistCurrentCommandIfRequired() {
+        if(commandContext == null || commandService == null) {
+            return;
+        } 
+        final Command command = commandContext.getCommand();
+        final CommandJdo commandJdo = commandService.asUserInitiatedCommandJdo(command);
+        if(commandJdo == null) {
+            return;
+        } 
+        persistIfNotAlready(commandJdo);
+    }
+
+    // //////////////////////////////////////
+
+    
+    @Programmatic
+    public List<CommandJdo> findByTargetAndFromAndTo(
+            final Bookmark target, final LocalDate from, final LocalDate to) {
+        final String targetStr = target.toString();
+        final Timestamp fromTs = toTimestampStartOfDayWithOffset(from, 0);
+        final Timestamp toTs = toTimestampStartOfDayWithOffset(to, 1);
+        
+        final Query<CommandJdo> query;
+        if(from != null) {
+            if(to != null) {
+                query = new QueryDefault<CommandJdo>(CommandJdo.class, 
+                        "findByTargetAndTimestampBetween", 
+                        "targetStr", targetStr,
+                        "from", fromTs,
+                        "to", toTs);
+            } else {
+                query = new QueryDefault<CommandJdo>(CommandJdo.class, 
+                        "findByTargetAndTimestampAfter", 
+                        "targetStr", targetStr,
+                        "from", fromTs);
+            }
+        } else {
+            if(to != null) {
+                query = new QueryDefault<CommandJdo>(CommandJdo.class, 
+                        "findByTargetAndTimestampBefore", 
+                        "targetStr", targetStr,
+                        "to", toTs);
+            } else {
+                query = new QueryDefault<CommandJdo>(CommandJdo.class, 
+                        "findByTarget", 
+                        "targetStr", targetStr);
+            }
+        }
+        return allMatches(query);
+    }
+
+    private static Timestamp toTimestampStartOfDayWithOffset(final LocalDate dt, int daysOffset) {
+        return dt!=null
+                ?new java.sql.Timestamp(dt.toDateTimeAtStartOfDay().plusDays(daysOffset).getMillis())
+                :null;
+    }
+
+    // //////////////////////////////////////
+
+    
+    @javax.inject.Inject
+    private CommandServiceJdo commandService;
+    
+    @javax.inject.Inject
+    private CommandContext commandContext;
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/790e70df/mothballed/core/module-command-jdo/src/main/java/org/apache/isis/objectstore/jdo/service/BackgroundCommandExecutionFromBackgroundCommandServiceJdo.java
----------------------------------------------------------------------
diff --git a/mothballed/core/module-command-jdo/src/main/java/org/apache/isis/objectstore/jdo/service/BackgroundCommandExecutionFromBackgroundCommandServiceJdo.java b/mothballed/core/module-command-jdo/src/main/java/org/apache/isis/objectstore/jdo/service/BackgroundCommandExecutionFromBackgroundCommandServiceJdo.java
new file mode 100644
index 0000000..9c22561
--- /dev/null
+++ b/mothballed/core/module-command-jdo/src/main/java/org/apache/isis/objectstore/jdo/service/BackgroundCommandExecutionFromBackgroundCommandServiceJdo.java
@@ -0,0 +1,49 @@
+/*
+ *  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.service;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.isis.applib.services.command.Command;
+import org.apache.isis.core.runtime.services.background.BackgroundCommandExecution;
+import org.apache.isis.objectstore.jdo.applib.service.background.BackgroundCommandServiceJdoRepository;
+import org.apache.isis.objectstore.jdo.applib.service.command.CommandJdo;
+
+/**
+ * If used, ensure that <code>org.apache.isis.module:isis-module-background</code> is also included on classpath.
+ */
+public final class BackgroundCommandExecutionFromBackgroundCommandServiceJdo extends BackgroundCommandExecution {
+
+    @SuppressWarnings("unused")
+    private final static Logger LOG = LoggerFactory.getLogger(BackgroundCommandExecutionFromBackgroundCommandServiceJdo.class);
+
+    @Override
+    protected List<? extends Command> findBackgroundCommandsToExecute() {
+        final List<CommandJdo> commands = backgroundCommandRepository.findBackgroundCommandsNotYetStarted();
+        return commands; 
+    }
+    
+    // //////////////////////////////////////
+
+    @javax.inject.Inject
+    private BackgroundCommandServiceJdoRepository backgroundCommandRepository;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/790e70df/mothballed/core/module-command-jdo/src/main/resources/images/CommandJdo.png
----------------------------------------------------------------------
diff --git a/mothballed/core/module-command-jdo/src/main/resources/images/CommandJdo.png b/mothballed/core/module-command-jdo/src/main/resources/images/CommandJdo.png
new file mode 100644
index 0000000..7545614
Binary files /dev/null and b/mothballed/core/module-command-jdo/src/main/resources/images/CommandJdo.png differ

http://git-wip-us.apache.org/repos/asf/isis/blob/790e70df/mothballed/core/module-command-jdo/src/test/java/org/apache/isis/objectstore/jdo/applib/service/command/CommandJdoTest_next.java
----------------------------------------------------------------------
diff --git a/mothballed/core/module-command-jdo/src/test/java/org/apache/isis/objectstore/jdo/applib/service/command/CommandJdoTest_next.java b/mothballed/core/module-command-jdo/src/test/java/org/apache/isis/objectstore/jdo/applib/service/command/CommandJdoTest_next.java
new file mode 100644
index 0000000..b5443e2
--- /dev/null
+++ b/mothballed/core/module-command-jdo/src/test/java/org/apache/isis/objectstore/jdo/applib/service/command/CommandJdoTest_next.java
@@ -0,0 +1,43 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.objectstore.jdo.applib.service.command;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Test;
+
+import org.apache.isis.objectstore.jdo.applib.service.command.CommandJdo;
+
+public class CommandJdoTest_next {
+
+    @Test
+    public void test() {
+        CommandJdo raj = new CommandJdo();
+        assertThat(raj.next("foo"), is(0));
+        assertThat(raj.next("foo"), is(1));
+        assertThat(raj.next("bar"), is(0));
+        assertThat(raj.next("bar"), is(1));
+        assertThat(raj.next("foo"), is(2));
+        assertThat(raj.next("bar"), is(2));
+        assertThat(raj.next("bar"), is(3));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/790e70df/mothballed/core/module-devutils/.gitignore
----------------------------------------------------------------------
diff --git a/mothballed/core/module-devutils/.gitignore b/mothballed/core/module-devutils/.gitignore
new file mode 100644
index 0000000..a48e45b
--- /dev/null
+++ b/mothballed/core/module-devutils/.gitignore
@@ -0,0 +1 @@
+/target-ide

http://git-wip-us.apache.org/repos/asf/isis/blob/790e70df/mothballed/core/module-devutils/applib/.gitignore
----------------------------------------------------------------------
diff --git a/mothballed/core/module-devutils/applib/.gitignore b/mothballed/core/module-devutils/applib/.gitignore
new file mode 100644
index 0000000..a48e45b
--- /dev/null
+++ b/mothballed/core/module-devutils/applib/.gitignore
@@ -0,0 +1 @@
+/target-ide

http://git-wip-us.apache.org/repos/asf/isis/blob/790e70df/mothballed/core/module-devutils/applib/pom.xml
----------------------------------------------------------------------
diff --git a/mothballed/core/module-devutils/applib/pom.xml b/mothballed/core/module-devutils/applib/pom.xml
new file mode 100644
index 0000000..4e8f8f4
--- /dev/null
+++ b/mothballed/core/module-devutils/applib/pom.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<groupId>org.apache.isis.module</groupId>
+		<artifactId>isis-module-devutils</artifactId>
+        <version>1.7.0-SNAPSHOT</version>
+	</parent>
+
+	<artifactId>isis-module-devutils-applib</artifactId>
+
+	<name>Isis Module: Developer Utilities applib</name>
+	<description>
+		API for the Developer Utilities module
+	</description>
+
+	<properties>
+        <siteBaseDir>../..</siteBaseDir>
+		<relativeUrl>module-devutils/applib/</relativeUrl>
+	</properties>
+
+    <url>http://isis.apache.org/${relativeUrl}</url>
+
+	<dependencies>
+        <dependency>
+            <groupId>org.apache.isis.core</groupId>
+            <artifactId>isis-core-applib</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.isis.core</groupId>
+            <artifactId>isis-core-unittestsupport</artifactId>
+            <scope>test</scope>
+        </dependency>
+   </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/isis/blob/790e70df/mothballed/core/module-devutils/applib/src/main/java/org/apache/isis/applib/services/devutils/DeveloperUtilitiesService.java
----------------------------------------------------------------------
diff --git a/mothballed/core/module-devutils/applib/src/main/java/org/apache/isis/applib/services/devutils/DeveloperUtilitiesService.java b/mothballed/core/module-devutils/applib/src/main/java/org/apache/isis/applib/services/devutils/DeveloperUtilitiesService.java
new file mode 100644
index 0000000..6a25cfc
--- /dev/null
+++ b/mothballed/core/module-devutils/applib/src/main/java/org/apache/isis/applib/services/devutils/DeveloperUtilitiesService.java
@@ -0,0 +1,75 @@
+/**
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.isis.applib.services.devutils;
+
+import org.apache.isis.applib.annotation.ActionSemantics;
+import org.apache.isis.applib.annotation.ActionSemantics.Of;
+import org.apache.isis.applib.annotation.Hidden;
+import org.apache.isis.applib.annotation.MemberOrder;
+import org.apache.isis.applib.annotation.Named;
+import org.apache.isis.applib.annotation.NotInServiceMenu;
+import org.apache.isis.applib.annotation.Prototype;
+import org.apache.isis.applib.value.Blob;
+import org.apache.isis.applib.value.Clob;
+
+@Named("Developer Utilities")
+public interface DeveloperUtilitiesService {
+
+    @MemberOrder(sequence="1")
+    @ActionSemantics(Of.SAFE)
+    @Prototype
+    public Clob downloadMetaModel();
+
+
+    /**
+     * Downloads a zip of the layout of all domain classes.
+     */
+    @ActionSemantics(Of.SAFE)
+    @MemberOrder(sequence="3")
+    @Prototype
+    public Blob downloadLayouts();
+
+    /**
+     * Rebuilds the metamodel of all registered domain services.
+     */
+    @ActionSemantics(Of.SAFE)
+    @MemberOrder(sequence="3")
+    @Prototype
+    public void refreshServices();
+
+    /**
+     * Download the JSON layout of the domain object's type.
+     */
+    @NotInServiceMenu
+    @ActionSemantics(Of.SAFE)
+    @MemberOrder(sequence="2")
+    @Prototype
+    public Clob downloadLayout(Object domainObject);
+
+    /**
+     * @deprecated - in prototype mode the Wicket viewer (at least) will automatically invalidate 
+     *               the Isis metamodel whenever the object is re-rendered.
+     */
+    @Deprecated
+    @Hidden
+    @NotInServiceMenu
+    @ActionSemantics(Of.SAFE)
+    @MemberOrder(sequence="99")
+    @Prototype
+    public Object refreshLayout(Object domainObject);
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/790e70df/mothballed/core/module-devutils/impl/.gitignore
----------------------------------------------------------------------
diff --git a/mothballed/core/module-devutils/impl/.gitignore b/mothballed/core/module-devutils/impl/.gitignore
new file mode 100644
index 0000000..a48e45b
--- /dev/null
+++ b/mothballed/core/module-devutils/impl/.gitignore
@@ -0,0 +1 @@
+/target-ide

http://git-wip-us.apache.org/repos/asf/isis/blob/790e70df/mothballed/core/module-devutils/impl/pom.xml
----------------------------------------------------------------------
diff --git a/mothballed/core/module-devutils/impl/pom.xml b/mothballed/core/module-devutils/impl/pom.xml
new file mode 100644
index 0000000..6b3c460
--- /dev/null
+++ b/mothballed/core/module-devutils/impl/pom.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<groupId>org.apache.isis.module</groupId>
+		<artifactId>isis-module-devutils</artifactId>
+        <version>1.7.0-SNAPSHOT</version>
+	</parent>
+
+	<artifactId>isis-module-devutils-impl</artifactId>
+
+	<name>Isis Module: Developer Utilities implementation</name>
+	<description>
+		Implementation of the Developer Utilities module
+	</description>
+
+	<properties>
+        <siteBaseDir>../..</siteBaseDir>
+		<relativeUrl>module-devutils/impl/</relativeUrl>
+	</properties>
+
+    <url>http://isis.apache.org/${relativeUrl}</url>
+
+	<dependencies>
+        <dependency>
+            <groupId>org.apache.isis.module</groupId>
+            <artifactId>isis-module-devutils-applib</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.isis.core</groupId>
+            <artifactId>isis-core-metamodel</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.isis.core</groupId>
+            <artifactId>isis-core-unittestsupport</artifactId>
+            <scope>test</scope>
+        </dependency>
+   </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/isis/blob/790e70df/mothballed/core/module-devutils/impl/src/main/java/org/apache/isis/core/metamodel/services/devutils/DeveloperUtilitiesServiceDefault.java
----------------------------------------------------------------------
diff --git a/mothballed/core/module-devutils/impl/src/main/java/org/apache/isis/core/metamodel/services/devutils/DeveloperUtilitiesServiceDefault.java b/mothballed/core/module-devutils/impl/src/main/java/org/apache/isis/core/metamodel/services/devutils/DeveloperUtilitiesServiceDefault.java
new file mode 100644
index 0000000..d36746b
--- /dev/null
+++ b/mothballed/core/module-devutils/impl/src/main/java/org/apache/isis/core/metamodel/services/devutils/DeveloperUtilitiesServiceDefault.java
@@ -0,0 +1,223 @@
+/*
+ *  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.devutils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+import javax.activation.MimeType;
+import javax.activation.MimeTypeParseException;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.Lists;
+import org.apache.isis.applib.FatalException;
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.services.devutils.DeveloperUtilitiesService;
+import org.apache.isis.applib.value.Blob;
+import org.apache.isis.applib.value.Clob;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManagerAware;
+import org.apache.isis.core.metamodel.layoutmetadata.json.LayoutMetadataReaderFromJson;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.SpecificationLoaderSpi;
+import org.apache.isis.core.metamodel.spec.SpecificationLoaderSpiAware;
+import org.apache.isis.core.metamodel.spec.feature.*;
+
+public class DeveloperUtilitiesServiceDefault implements DeveloperUtilitiesService, SpecificationLoaderSpiAware, AdapterManagerAware {
+
+
+    private final MimeType mimeTypeTextCsv;
+    private final MimeType mimeTypeApplicationZip;
+    private final MimeType mimeTypeApplicationJson;
+
+    public DeveloperUtilitiesServiceDefault() {
+        try {
+            mimeTypeTextCsv = new MimeType("text", "csv");
+            mimeTypeApplicationJson = new MimeType("application", "jzon");
+            mimeTypeApplicationZip = new MimeType("application", "zip");
+        } catch (MimeTypeParseException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    // //////////////////////////////////////
+
+    
+    @Override
+    public Clob downloadMetaModel() {
+
+        final Collection<ObjectSpecification> specifications = specificationLoader.allSpecifications();
+
+        final List<MetaModelRow> rows = Lists.newArrayList();
+        for (ObjectSpecification spec : specifications) {
+            if (exclude(spec)) {
+                continue;
+            }
+            final List<ObjectAssociation> properties = spec.getAssociations(Contributed.EXCLUDED, ObjectAssociation.Filters.PROPERTIES);
+            for (ObjectAssociation property : properties) {
+                final OneToOneAssociation otoa = (OneToOneAssociation) property;
+                if (exclude(otoa)) {
+                    continue;
+                }
+                rows.add(new MetaModelRow(spec, otoa));
+            }
+            final List<ObjectAssociation> associations = spec.getAssociations(Contributed.EXCLUDED, ObjectAssociation.Filters.COLLECTIONS);
+            for (ObjectAssociation collection : associations) {
+                final OneToManyAssociation otma = (OneToManyAssociation) collection;
+                if (exclude(otma)) {
+                    continue;
+                }
+                rows.add(new MetaModelRow(spec, otma));
+            }
+            final List<ObjectAction> actions = spec.getObjectActions(Contributed.INCLUDED);
+            for (ObjectAction action : actions) {
+                if (exclude(action)) {
+                    continue;
+                }
+                rows.add(new MetaModelRow(spec, action));
+            }
+        }
+
+        Collections.sort(rows);
+
+        final StringBuilder buf = new StringBuilder();
+        buf.append(MetaModelRow.header()).append("\n");
+        for (MetaModelRow row : rows) {
+            buf.append(row.asTextCsv()).append("\n");
+        }
+        return new Clob("metamodel.csv", mimeTypeTextCsv, buf.toString().toCharArray());
+    }
+
+    protected boolean exclude(OneToOneAssociation property) {
+        return false;
+    }
+
+    protected boolean exclude(OneToManyAssociation collection) {
+        return false;
+    }
+
+    protected boolean exclude(ObjectAction action) {
+        return false;
+    }
+
+    protected boolean exclude(ObjectSpecification spec) {
+        return isBuiltIn(spec) || spec.isAbstract();
+    }
+
+    protected boolean isBuiltIn(ObjectSpecification spec) {
+        final String className = spec.getFullIdentifier();
+        return className.startsWith("java") || className.startsWith("org.joda");
+    }
+
+    // //////////////////////////////////////
+    
+    @Override
+    public void refreshServices() {
+        Collection<ObjectSpecification> specifications = Lists.newArrayList(specificationLoader.allSpecifications());
+        for (ObjectSpecification objectSpec : specifications) {
+            if(objectSpec.isService()){
+                specificationLoader.invalidateCache(objectSpec.getCorrespondingClass());
+            }
+        }
+    }
+
+    // //////////////////////////////////////
+
+    @Override
+    public Object refreshLayout(Object domainObject) {
+        specificationLoader.invalidateCacheFor(domainObject);
+        return domainObject;
+    }
+
+    // //////////////////////////////////////
+    
+    @Override
+    public Clob downloadLayout(Object domainObject) {
+        
+        final ObjectAdapter adapterFor = adapterManager.adapterFor(domainObject);
+        final ObjectSpecification objectSpec = adapterFor.getSpecification();
+        
+        final LayoutMetadataReaderFromJson propertiesReader = new LayoutMetadataReaderFromJson();
+        final String json = propertiesReader.asJson(objectSpec);
+        
+        return new Clob(objectSpec.getShortIdentifier() +".layout.json", mimeTypeApplicationJson, json);
+    }
+
+    // //////////////////////////////////////
+
+    @Override
+    public Blob downloadLayouts() {
+        final LayoutMetadataReaderFromJson propertiesReader = new LayoutMetadataReaderFromJson();
+        final Collection<ObjectSpecification> allSpecs = specificationLoader.allSpecifications();
+        final Collection<ObjectSpecification> domainObjectSpecs = Collections2.filter(allSpecs, new Predicate<ObjectSpecification>(){
+            @Override
+            public boolean apply(ObjectSpecification input) {
+                return  !input.isAbstract() && 
+                        !input.isService() && 
+                        !input.isValue() && 
+                        !input.isParentedOrFreeCollection();
+            }});
+        try {
+            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            ZipOutputStream zos = new ZipOutputStream(baos);
+            OutputStreamWriter writer = new OutputStreamWriter(zos);
+            for (ObjectSpecification objectSpec : domainObjectSpecs) {
+                zos.putNextEntry(new ZipEntry(zipEntryNameFor(objectSpec)));
+                writer.write(propertiesReader.asJson(objectSpec));
+                writer.flush();
+                zos.closeEntry();
+            }
+            writer.close();
+            return new Blob("layouts.zip", mimeTypeApplicationZip, baos.toByteArray());
+        } catch (final IOException ex) {
+            throw new FatalException("Unable to create zip of layouts", ex);
+        }
+    }
+
+    private static String zipEntryNameFor(ObjectSpecification objectSpec) {
+        final String fqn = objectSpec.getFullIdentifier();
+        return fqn.replace(".", File.separator)+".layout.json";
+    }
+
+
+    // //////////////////////////////////////
+
+    private SpecificationLoaderSpi specificationLoader;
+    private AdapterManager adapterManager;
+
+    @Programmatic
+    @Override
+    public void setSpecificationLoaderSpi(SpecificationLoaderSpi specificationLoader) {
+        this.specificationLoader = specificationLoader;
+    }
+
+    @Override
+    public void setAdapterManager(AdapterManager adapterManager) {
+        this.adapterManager = adapterManager;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/790e70df/mothballed/core/module-devutils/impl/src/main/java/org/apache/isis/core/metamodel/services/devutils/MetaModelRow.java
----------------------------------------------------------------------
diff --git a/mothballed/core/module-devutils/impl/src/main/java/org/apache/isis/core/metamodel/services/devutils/MetaModelRow.java b/mothballed/core/module-devutils/impl/src/main/java/org/apache/isis/core/metamodel/services/devutils/MetaModelRow.java
new file mode 100644
index 0000000..a935972
--- /dev/null
+++ b/mothballed/core/module-devutils/impl/src/main/java/org/apache/isis/core/metamodel/services/devutils/MetaModelRow.java
@@ -0,0 +1,234 @@
+/**
+ *  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.devutils;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.SortedSet;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Strings;
+import com.google.common.collect.Sets;
+
+import org.apache.isis.applib.util.ObjectContracts;
+import org.apache.isis.core.commons.lang.StringExtensions;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facets.ImperativeFacet;
+import org.apache.isis.core.metamodel.facets.param.choices.ActionChoicesFacet;
+import org.apache.isis.core.metamodel.facets.actions.defaults.ActionDefaultsFacet;
+import org.apache.isis.core.metamodel.facets.all.hide.HiddenFacet;
+import org.apache.isis.core.metamodel.facets.param.autocomplete.ActionParameterAutoCompleteFacet;
+import org.apache.isis.core.metamodel.facets.param.choices.ActionParameterChoicesFacet;
+import org.apache.isis.core.metamodel.facets.param.defaults.ActionParameterDefaultsFacet;
+import org.apache.isis.core.metamodel.facets.properties.autocomplete.PropertyAutoCompleteFacet;
+import org.apache.isis.core.metamodel.facets.properties.choices.PropertyChoicesFacet;
+import org.apache.isis.core.metamodel.facets.properties.defaults.PropertyDefaultFacet;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
+import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+import org.apache.isis.core.metamodel.facets.actions.validate.ActionValidationFacet;
+import org.apache.isis.core.metamodel.facets.collections.validate.CollectionValidateAddToFacet;
+import org.apache.isis.core.metamodel.facets.collections.validate.CollectionValidateRemoveFromFacet;
+import org.apache.isis.core.metamodel.facets.members.disabled.DisabledFacet;
+import org.apache.isis.core.metamodel.facets.properties.validating.PropertyValidateFacet;
+
+public class MetaModelRow implements Comparable<MetaModelRow>{
+
+    enum MemberType {
+        PROPERTY,
+        COLLECTION,
+        ACTION;
+    }
+
+    private final ObjectSpecification spec;
+    private final MemberType memberType;
+    private final ObjectMember member;
+    private ObjectAction action;
+    
+    MetaModelRow(ObjectSpecification spec, OneToOneAssociation property) {
+        this.spec = spec;
+        this.member = property;
+        this.memberType = MemberType.PROPERTY;
+    }
+
+    MetaModelRow(ObjectSpecification spec, OneToManyAssociation collection) {
+        this.spec = spec;
+        this.member = collection;
+        this.memberType = MemberType.COLLECTION;
+    }
+    
+    MetaModelRow(ObjectSpecification spec, ObjectAction action) {
+        this.spec = spec;
+        this.member = this.action = action;
+        this.memberType = MemberType.ACTION;
+    }
+
+    public String getClassType() {
+        boolean service = false;
+        for(ObjectSpecification subspecs: spec.subclasses()) {
+            service = service || subspecs.isService();
+        }
+        return service || spec.isService() ?"2 Service":spec.isValue()?"3 Value":spec.isParentedOrFreeCollection()?"4 Collection":"1 Object";
+    }
+    public String getClassName() {
+        final String fullIdentifier = spec.getFullIdentifier();
+        final int lastDot = fullIdentifier.lastIndexOf(".");
+        return lastDot>0 && lastDot < fullIdentifier.length()-1
+                ?fullIdentifier.substring(lastDot+1,fullIdentifier.length())
+                :fullIdentifier;
+    }
+    public String getPackageName() {
+        final String fullIdentifier = spec.getFullIdentifier();
+        final int lastDot = fullIdentifier.lastIndexOf(".");
+        return lastDot>0?fullIdentifier.substring(0,lastDot):fullIdentifier;
+    }
+    public String getType() {
+        return memberType.name().toLowerCase();
+    }
+    public String getMemberName() {
+        return member.getId();
+    }
+    public String getNumParams() {
+        return action!=null?""+action.getParameterCount():"";
+    }
+    String getHidden() {
+        return interpret(HiddenFacet.class);
+    }
+    String getDisabled() {
+        return interpret(DisabledFacet.class);
+    }
+    public String getChoices() {
+        if(memberType == MemberType.PROPERTY) {
+            return interpretRowAndFacet(PropertyChoicesFacet.class);
+        } else if(memberType == MemberType.COLLECTION) {
+            return "";
+        } else {
+            final List<ObjectActionParameter> parameters = this.action.getParameters();
+            final SortedSet<String> interpretations = Sets.newTreeSet();
+            for (ObjectActionParameter param : parameters) {
+                final ActionParameterChoicesFacet facet = param.getFacet(ActionParameterChoicesFacet.class);
+                addIfNotEmpty(interpretFacet(facet), interpretations);
+            }
+            return !interpretations.isEmpty()? Joiner.on(";").join(interpretations) : interpretRowAndFacet(ActionChoicesFacet.class);
+        }
+    }
+    public String getAutoComplete() {
+        if(memberType == MemberType.PROPERTY) {
+            return interpretRowAndFacet(PropertyAutoCompleteFacet.class);
+        } else if(memberType == MemberType.COLLECTION) {
+           return "";
+        } else {
+            final List<ObjectActionParameter> parameters = this.action.getParameters();
+            final SortedSet<String> interpretations = Sets.newTreeSet();
+            for (ObjectActionParameter param : parameters) {
+                final ActionParameterAutoCompleteFacet facet = param.getFacet(ActionParameterAutoCompleteFacet.class);
+                addIfNotEmpty(interpretFacet(facet), interpretations);
+            }
+            return !interpretations.isEmpty()? Joiner.on(";").join(interpretations) : "";
+        }
+    }
+    String getDefault() {
+        if(memberType == MemberType.PROPERTY) {
+            return interpretRowAndFacet(PropertyDefaultFacet.class);
+        } else if(memberType == MemberType.COLLECTION) {
+            return "";
+        } else {
+            final List<ObjectActionParameter> parameters = this.action.getParameters();
+            final SortedSet<String> interpretations = Sets.newTreeSet();
+            for (ObjectActionParameter param : parameters) {
+                final ActionParameterDefaultsFacet facet = param.getFacet(ActionParameterDefaultsFacet.class);
+                addIfNotEmpty(interpretFacet(facet), interpretations);
+            }
+            return !interpretations.isEmpty()? Joiner.on(";").join(interpretations) : interpretRowAndFacet(ActionDefaultsFacet.class);
+        }
+    }
+    String getValidate() {
+        if(memberType == MemberType.PROPERTY) {
+            return interpretRowAndFacet(PropertyValidateFacet.class);
+        } else if(memberType == MemberType.COLLECTION) {
+            final SortedSet<String> interpretations = Sets.newTreeSet();
+            addIfNotEmpty(interpretRowAndFacet(CollectionValidateAddToFacet.class), interpretations);
+            addIfNotEmpty(interpretRowAndFacet(CollectionValidateRemoveFromFacet.class), interpretations);
+            return !interpretations.isEmpty()? Joiner.on(";").join(interpretations) : "";
+       } else {
+           return interpretRowAndFacet(ActionValidationFacet.class);
+        }
+    }
+
+    static Object header() {
+        return "classType,packageName,className,memberType,memberName,numParams,hidden,disabled,choices,autoComplete,default,validate";
+    }
+    
+    String asTextCsv() {
+        return Joiner.on(",").join(
+                getClassType(),
+                getPackageName(),
+                getClassName(),
+                getType(),
+                getMemberName(),
+                getNumParams(),
+                getHidden(),
+                getDisabled(),
+                getChoices(),
+                getAutoComplete(),
+                getDefault(),
+                getValidate());
+    }
+ 
+    private String interpretRowAndFacet(Class<? extends Facet> facetClass) {
+        final Facet facet = member.getFacet(facetClass);
+        return interpretFacet(facet);
+    }
+    
+    private static void addIfNotEmpty(final String str, final SortedSet<String> set) {
+        if(!Strings.isNullOrEmpty(str)) {
+            set.add(str);
+        }
+    }
+    
+    private String interpret(final Class<? extends Facet> cls) {
+        return interpretFacet(member.getFacet(cls));
+    }
+
+    private static String interpretFacet(final Facet facet) {
+        if (facet == null || facet.isNoop()) {
+            return "";
+        }
+        if (facet instanceof ImperativeFacet) {
+            ImperativeFacet imperativeFacet = (ImperativeFacet) facet;
+            return imperativeFacet.getMethods().get(0).getName();
+        } 
+        final String name = facet.getClass().getSimpleName();
+        if (ignore(name)) {
+            return "";
+        } 
+        final String abbr = StringExtensions.toAbbreviation(name);
+        return abbr.length()>0 ? abbr : name;
+    }
+
+    protected static boolean ignore(final String name) {
+        return Arrays.asList("PropertyValidateFacetDefault","PropertyDefaultFacetDerivedFromDefaultedFacet").contains(name);
+    }
+
+    @Override
+    public int compareTo(MetaModelRow o) {
+        return ObjectContracts.compare(this, o, "classType,className,type desc,memberName");
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/790e70df/mothballed/core/module-devutils/pom.xml
----------------------------------------------------------------------
diff --git a/mothballed/core/module-devutils/pom.xml b/mothballed/core/module-devutils/pom.xml
new file mode 100644
index 0000000..bae27b3
--- /dev/null
+++ b/mothballed/core/module-devutils/pom.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<groupId>org.apache.isis.core</groupId>
+		<artifactId>isis</artifactId>
+        <version>1.7.0-SNAPSHOT</version>
+	</parent>
+
+    <groupId>org.apache.isis.module</groupId>
+	<artifactId>isis-module-devutils</artifactId>
+    <packaging>pom</packaging>
+
+	<name>Isis Module: Developer Utilities</name>
+	<description>
+		Developer utilities.
+	</description>
+
+	<properties>
+        <siteBaseDir>..</siteBaseDir>
+		<relativeUrl>module-devutils/</relativeUrl>
+	</properties>
+
+    <url>http://isis.apache.org/${relativeUrl}</url>
+
+    <dependencyManagement>
+        <dependencies>
+
+            <dependency>
+                <groupId>org.apache.isis.module</groupId>
+                <artifactId>isis-module-devutils-applib</artifactId>
+                <version>1.7.0-SNAPSHOT</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.isis.module</groupId>
+                <artifactId>isis-module-devutils-applib</artifactId>
+                <version>1.7.0-SNAPSHOT</version>
+                <scope>test</scope>
+                <type>test-jar</type>
+            </dependency>
+
+            <dependency>
+                <groupId>org.apache.isis.module</groupId>
+                <artifactId>isis-module-devutils-impl</artifactId>
+                <version>1.7.0-SNAPSHOT</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.isis.module</groupId>
+                <artifactId>isis-module-devutils-impl</artifactId>
+                <version>1.7.0-SNAPSHOT</version>
+                <scope>test</scope>
+                <type>test-jar</type>
+            </dependency>
+
+        </dependencies>
+    </dependencyManagement>
+
+	<dependencies>
+        <dependency>
+            <groupId>org.apache.isis.core</groupId>
+            <artifactId>isis-core-applib</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.isis.core</groupId>
+            <artifactId>isis-core-unittestsupport</artifactId>
+            <scope>test</scope>
+        </dependency>
+   </dependencies>
+
+   <modules>
+       <module>applib</module>
+       <module>impl</module>
+   </modules>
+   
+</project>

http://git-wip-us.apache.org/repos/asf/isis/blob/790e70df/mothballed/core/module-publishing-jdo/.gitignore
----------------------------------------------------------------------
diff --git a/mothballed/core/module-publishing-jdo/.gitignore b/mothballed/core/module-publishing-jdo/.gitignore
new file mode 100644
index 0000000..a48e45b
--- /dev/null
+++ b/mothballed/core/module-publishing-jdo/.gitignore
@@ -0,0 +1 @@
+/target-ide

http://git-wip-us.apache.org/repos/asf/isis/blob/790e70df/mothballed/core/module-publishing-jdo/pom.xml
----------------------------------------------------------------------
diff --git a/mothballed/core/module-publishing-jdo/pom.xml b/mothballed/core/module-publishing-jdo/pom.xml
new file mode 100644
index 0000000..420125e
--- /dev/null
+++ b/mothballed/core/module-publishing-jdo/pom.xml
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<parent>
+		<groupId>org.apache.isis.core</groupId>
+		<artifactId>isis</artifactId>
+        <version>1.7.0-SNAPSHOT</version>
+	</parent>
+
+    <groupId>org.apache.isis.module</groupId>
+	<artifactId>isis-module-publishing-jdo</artifactId>
+
+	<name>Isis Module: Publishing (JDO Implementation)</name>
+	<description>
+		PublishingService implementation that persists published events
+        to the database (using JDO Objectstore).
+	</description>
+
+	<properties>
+        <siteBaseDir>..</siteBaseDir>
+		<relativeUrl>module-publishing/</relativeUrl>
+	</properties>
+
+    <url>http://isis.apache.org/${relativeUrl}</url>
+
+	<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>org.apache.isis.core</groupId>
+            <artifactId>isis-core-applib</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.isis.core</groupId>
+            <artifactId>isis-core-unittestsupport</artifactId>
+            <scope>test</scope>
+        </dependency>
+        
+        <dependency>
+          <groupId>org.slf4j</groupId>
+          <artifactId>slf4j-api</artifactId>
+        </dependency>
+        
+		<!-- DataNucleus (jdo-api, and for enhancer) -->
+        <dependency>
+            <groupId>org.datanucleus</groupId>
+            <artifactId>datanucleus-accessplatform-jdo-rdbms</artifactId>
+            <type>pom</type>
+        </dependency>
+        <dependency>
+            <groupId>org.datanucleus</groupId>
+            <artifactId>datanucleus-jodatime</artifactId>
+        </dependency>
+   </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/isis/blob/790e70df/mothballed/core/module-publishing-jdo/src/main/java/META-INF/persistence.xml
----------------------------------------------------------------------
diff --git a/mothballed/core/module-publishing-jdo/src/main/java/META-INF/persistence.xml b/mothballed/core/module-publishing-jdo/src/main/java/META-INF/persistence.xml
new file mode 100644
index 0000000..1cb71dd
--- /dev/null
+++ b/mothballed/core/module-publishing-jdo/src/main/java/META-INF/persistence.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+  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.
+-->
+<persistence xmlns="http://java.sun.com/xml/ns/persistence"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
+
+    <persistence-unit name="isis-module-publishing-jdo">
+    </persistence-unit>
+</persistence>