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 2013/06/26 09:45:23 UTC

git commit: ISIS-446, ISIS-441: enhancements to ToDoItem class

Updated Branches:
  refs/heads/master 59c5479b0 -> 60ba3ba82


ISIS-446, ISIS-441: enhancements to ToDoItem class

- adding DeveloperUtilities to example
- using ObjectContracts in ToDoItem
  - fixed issue whereby couldn't use isXxx() methods; now can.


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

Branch: refs/heads/master
Commit: 60ba3ba828d1f049591f8eefc58d33c28643e2af
Parents: 59c5479
Author: Dan Haywood <da...@apache.org>
Authored: Wed Jun 26 08:36:27 2013 +0100
Committer: Dan Haywood <da...@apache.org>
Committed: Wed Jun 26 08:36:27 2013 +0100

----------------------------------------------------------------------
 .../devutils/DeveloperUtilitiesService.java     |  30 +++
 .../isis/applib/util/ObjectContracts.java       |  16 +-
 .../apache/isis/applib/util/InvoiceItem.java    |  12 +-
 .../util/ObjectContractsTest_compareTo.java     |  31 ++-
 .../util/ObjectContractsTest_toString.java      |  31 ++-
 .../DeveloperUtilitiesServiceDefault.java       | 100 ++++++++
 .../services/devutils/MetaModelRow.java         | 246 +++++++++++++++++++
 .../dom/src/main/java/dom/todo/ToDoItem.java    |  43 +---
 ...cket_restful_jdo-webapp-with-fixtures.launch |   4 +
 .../java/app/services/DeveloperUtilities.java   |  39 +++
 .../src/main/webapp/WEB-INF/isis.properties     |   1 +
 11 files changed, 491 insertions(+), 62 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/60ba3ba8/core/applib/src/main/java/org/apache/isis/applib/services/devutils/DeveloperUtilitiesService.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/devutils/DeveloperUtilitiesService.java b/core/applib/src/main/java/org/apache/isis/applib/services/devutils/DeveloperUtilitiesService.java
new file mode 100644
index 0000000..b7f5edf
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/devutils/DeveloperUtilitiesService.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.applib.services.devutils;
+
+import org.apache.isis.applib.annotation.ActionSemantics;
+import org.apache.isis.applib.annotation.ActionSemantics.Of;
+import org.apache.isis.applib.annotation.Named;
+import org.apache.isis.applib.value.Clob;
+
+@Named("Developer Utilities")
+public interface DeveloperUtilitiesService {
+
+    @ActionSemantics(Of.SAFE)
+    public Clob downloadMetaModel();
+    
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/60ba3ba8/core/applib/src/main/java/org/apache/isis/applib/util/ObjectContracts.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/util/ObjectContracts.java b/core/applib/src/main/java/org/apache/isis/applib/util/ObjectContracts.java
index 7f1cf07..b253724 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/util/ObjectContracts.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/util/ObjectContracts.java
@@ -170,17 +170,21 @@ class Clause {
         if(obj == null) {
             return null;
         }
-        String methodName = buildMethodName(propertyName);
+        final String methodNameSuffix = upperFirst(propertyName);
+        final String getMethodName = "get" + methodNameSuffix;
         try {
-            final Method getterMethod = obj.getClass().getMethod(methodName);
+            final Method getterMethod = obj.getClass().getMethod(getMethodName);
             return getterMethod.invoke(obj);
         } catch (Exception e) {
-            throw new IllegalArgumentException("No such method ' " + methodName + "'", e);
+            final String isMethodName = "is" + methodNameSuffix;
+            try {
+                final Method getterMethod = obj.getClass().getMethod(isMethodName);
+                return getterMethod.invoke(obj);
+            } catch (Exception ex) {
+                throw new IllegalArgumentException("No such method ' " + getMethodName + "' or '" + isMethodName + "'", e);
+            }
         }
     }
-    private static String buildMethodName(String propertyName) {
-        return "get" + upperFirst(propertyName);
-    }
     private static String upperFirst(final String str) {
         if (Strings.isNullOrEmpty(str)) {
             return str;

http://git-wip-us.apache.org/repos/asf/isis/blob/60ba3ba8/core/applib/src/test/java/org/apache/isis/applib/util/InvoiceItem.java
----------------------------------------------------------------------
diff --git a/core/applib/src/test/java/org/apache/isis/applib/util/InvoiceItem.java b/core/applib/src/test/java/org/apache/isis/applib/util/InvoiceItem.java
index c0a06de..792ad63 100644
--- a/core/applib/src/test/java/org/apache/isis/applib/util/InvoiceItem.java
+++ b/core/applib/src/test/java/org/apache/isis/applib/util/InvoiceItem.java
@@ -19,11 +19,12 @@ package org.apache.isis.applib.util;
 
 class InvoiceItem implements Comparable<InvoiceItem> {
 
-    static InvoiceItem newInvoiceItem(Invoice invoice, String productCode, Integer quantity) {
+    static InvoiceItem newInvoiceItem(Invoice invoice, String productCode, Integer quantity, Boolean rush) {
         final InvoiceItem invoiceItem = new InvoiceItem();
         invoiceItem.setInvoice(invoice);
         invoiceItem.setProductCode(productCode);
         invoiceItem.setQuantity(quantity);
+        invoiceItem.setRush(rush);
         return invoiceItem;
     }
 
@@ -51,8 +52,15 @@ class InvoiceItem implements Comparable<InvoiceItem> {
         this.quantity = quantity;
     }
  
+    private Boolean rush;
+    public Boolean isRush() {
+        return rush;
+    }
+    public void setRush(Boolean rush) {
+        this.rush = rush;
+    }
     
-    private static final String KEY_PROPERTIES = "invoice desc, productCode, quantity";
+    private static final String KEY_PROPERTIES = "invoice desc, productCode, quantity, rush desc";
     
     @Override
     public String toString() {

http://git-wip-us.apache.org/repos/asf/isis/blob/60ba3ba8/core/applib/src/test/java/org/apache/isis/applib/util/ObjectContractsTest_compareTo.java
----------------------------------------------------------------------
diff --git a/core/applib/src/test/java/org/apache/isis/applib/util/ObjectContractsTest_compareTo.java b/core/applib/src/test/java/org/apache/isis/applib/util/ObjectContractsTest_compareTo.java
index 6d75277..dc666b5 100644
--- a/core/applib/src/test/java/org/apache/isis/applib/util/ObjectContractsTest_compareTo.java
+++ b/core/applib/src/test/java/org/apache/isis/applib/util/ObjectContractsTest_compareTo.java
@@ -46,24 +46,31 @@ public class ObjectContractsTest_compareTo extends ComparableContractTest_compar
         return listOf(
                    listOf(
                            // invoice desc, ...
-                           InvoiceItem.newInvoiceItem(null, null, null)
-                          ,InvoiceItem.newInvoiceItem(inv456, null, null)
-                          ,InvoiceItem.newInvoiceItem(inv456, null, null)
-                          ,InvoiceItem.newInvoiceItem(inv123, null, null)
+                           InvoiceItem.newInvoiceItem(null, null, null, null)
+                          ,InvoiceItem.newInvoiceItem(inv456, null, null, null)
+                          ,InvoiceItem.newInvoiceItem(inv456, null, null, null)
+                          ,InvoiceItem.newInvoiceItem(inv123, null, null, null)
                            )
                    ,listOf(
                            // ..., productCode, ...
-                           InvoiceItem.newInvoiceItem(inv123, null, null)
-                           ,InvoiceItem.newInvoiceItem(inv123, "A", null)
-                           ,InvoiceItem.newInvoiceItem(inv123, "A", null)
-                           ,InvoiceItem.newInvoiceItem(inv123, "B", null)
+                           InvoiceItem.newInvoiceItem(inv123, null, null, null)
+                           ,InvoiceItem.newInvoiceItem(inv123, "A", null, null)
+                           ,InvoiceItem.newInvoiceItem(inv123, "A", null, null)
+                           ,InvoiceItem.newInvoiceItem(inv123, "B", null, null)
                            )
                    ,listOf(
                            // ..., quantity
-                           InvoiceItem.newInvoiceItem(inv123, "A", null)
-                           ,InvoiceItem.newInvoiceItem(inv123, "A", new Integer(1))
-                           ,InvoiceItem.newInvoiceItem(inv123, "A", new Integer(1))
-                           ,InvoiceItem.newInvoiceItem(inv123, "A", new Integer(2))
+                           InvoiceItem.newInvoiceItem(inv123, "A", null, null)
+                           ,InvoiceItem.newInvoiceItem(inv123, "A", new Integer(1), null)
+                           ,InvoiceItem.newInvoiceItem(inv123, "A", new Integer(1), null)
+                           ,InvoiceItem.newInvoiceItem(inv123, "A", new Integer(2), null)
+                           )
+                   ,listOf(
+                           // ..., rush desc
+                           InvoiceItem.newInvoiceItem(inv123, "A", new Integer(1), null)
+                           ,InvoiceItem.newInvoiceItem(inv123, "A", new Integer(1), true)
+                           ,InvoiceItem.newInvoiceItem(inv123, "A", new Integer(1), true)
+                           ,InvoiceItem.newInvoiceItem(inv123, "A", new Integer(1), false)
                            )
                 );
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/60ba3ba8/core/applib/src/test/java/org/apache/isis/applib/util/ObjectContractsTest_toString.java
----------------------------------------------------------------------
diff --git a/core/applib/src/test/java/org/apache/isis/applib/util/ObjectContractsTest_toString.java b/core/applib/src/test/java/org/apache/isis/applib/util/ObjectContractsTest_toString.java
index f27a7c0..89cef32 100644
--- a/core/applib/src/test/java/org/apache/isis/applib/util/ObjectContractsTest_toString.java
+++ b/core/applib/src/test/java/org/apache/isis/applib/util/ObjectContractsTest_toString.java
@@ -38,18 +38,20 @@ public class ObjectContractsTest_toString {
 
     @Test
     public void vanilla() {
-        assertThat(InvoiceItem.newInvoiceItem(null, null, null).toString(), is("InvoiceItem{invoice=null, productCode=null, quantity=null}"));
-        assertThat(InvoiceItem.newInvoiceItem(inv, null, null).toString(), is("InvoiceItem{invoice=Invoice{number=123}, productCode=null, quantity=null}"));
-        assertThat(InvoiceItem.newInvoiceItem(inv, "A", null).toString(), is("InvoiceItem{invoice=Invoice{number=123}, productCode=A, quantity=null}"));
-        assertThat(InvoiceItem.newInvoiceItem(inv, "A", new Integer(1)).toString(), is("InvoiceItem{invoice=Invoice{number=123}, productCode=A, quantity=1}"));
+        assertThat(InvoiceItem.newInvoiceItem(null, null, null, null).toString(), is("InvoiceItem{invoice=null, productCode=null, quantity=null, rush=null}"));
+        assertThat(InvoiceItem.newInvoiceItem(inv, null, null, null).toString(), is("InvoiceItem{invoice=Invoice{number=123}, productCode=null, quantity=null, rush=null}"));
+        assertThat(InvoiceItem.newInvoiceItem(inv, "A", null, null).toString(), is("InvoiceItem{invoice=Invoice{number=123}, productCode=A, quantity=null, rush=null}"));
+        assertThat(InvoiceItem.newInvoiceItem(inv, "A", new Integer(1), null).toString(), is("InvoiceItem{invoice=Invoice{number=123}, productCode=A, quantity=1, rush=null}"));
+        assertThat(InvoiceItem.newInvoiceItem(inv, "A", new Integer(1), true).toString(), is("InvoiceItem{invoice=Invoice{number=123}, productCode=A, quantity=1, rush=true}"));
     }
 
     @Test
     public void customized() {
-        assertThat(InvoiceItem2.newInvoiceItem(null, null, null).toString(), is("InvoiceItem2{invoice=null, productCode=null, quantity=null}"));
-        assertThat(InvoiceItem2.newInvoiceItem(inv2, null, null).toString(), is("InvoiceItem2{invoice=123, productCode=null, quantity=null}"));
-        assertThat(InvoiceItem2.newInvoiceItem(inv2, "A", null).toString(), is("InvoiceItem2{invoice=123, productCode=A, quantity=null}"));
-        assertThat(InvoiceItem2.newInvoiceItem(inv2, "A", new Integer(1)).toString(), is("InvoiceItem2{invoice=123, productCode=A, quantity=1}"));
+        assertThat(InvoiceItem2.newInvoiceItem(null, null, null, null).toString(), is("InvoiceItem2{invoice=null, productCode=null, quantity=null, rush=null}"));
+        assertThat(InvoiceItem2.newInvoiceItem(inv2, null, null, null).toString(), is("InvoiceItem2{invoice=123, productCode=null, quantity=null, rush=null}"));
+        assertThat(InvoiceItem2.newInvoiceItem(inv2, "A", null, null).toString(), is("InvoiceItem2{invoice=123, productCode=A, quantity=null, rush=null}"));
+        assertThat(InvoiceItem2.newInvoiceItem(inv2, "A", new Integer(1), null).toString(), is("InvoiceItem2{invoice=123, productCode=A, quantity=1, rush=null}"));
+        assertThat(InvoiceItem2.newInvoiceItem(inv2, "A", new Integer(1), false).toString(), is("InvoiceItem2{invoice=123, productCode=A, quantity=1, rush=false}"));
     }
 
 }
@@ -75,11 +77,12 @@ class Invoice2 implements Comparable<Invoice2>, Numbered {
 }
 class InvoiceItem2 implements Comparable<InvoiceItem2> {
 
-    static InvoiceItem2 newInvoiceItem(Invoice2 invoice, String productCode, Integer quantity) {
+    static InvoiceItem2 newInvoiceItem(Invoice2 invoice, String productCode, Integer quantity, Boolean rush) {
         final InvoiceItem2 invoiceItem = new InvoiceItem2();
         invoiceItem.setInvoice(invoice);
         invoiceItem.setProductCode(productCode);
         invoiceItem.setQuantity(quantity);
+        invoiceItem.setRush(rush);
         return invoiceItem;
     }
 
@@ -107,8 +110,16 @@ class InvoiceItem2 implements Comparable<InvoiceItem2> {
         this.quantity = quantity;
     }
  
+    private Boolean rush;
+    public Boolean isRush() {
+        return rush;
+    }
+    public void setRush(Boolean rush) {
+        this.rush = rush;
+    }
+    
     
-    private static final String KEY_PROPERTIES = "invoice desc, productCode, quantity";
+    private static final String KEY_PROPERTIES = "invoice desc, productCode, quantity, rush desc";
     
     @Override
     public String toString() {

http://git-wip-us.apache.org/repos/asf/isis/blob/60ba3ba8/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/devutils/DeveloperUtilitiesServiceDefault.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/devutils/DeveloperUtilitiesServiceDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/devutils/DeveloperUtilitiesServiceDefault.java
new file mode 100644
index 0000000..ca8996c
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/devutils/DeveloperUtilitiesServiceDefault.java
@@ -0,0 +1,100 @@
+/*
+ *  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.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import javax.activation.MimeType;
+import javax.activation.MimeTypeParseException;
+
+import com.google.common.collect.Lists;
+
+import org.apache.isis.applib.annotation.ActionSemantics;
+import org.apache.isis.applib.annotation.ActionSemantics.Of;
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.services.devutils.DeveloperUtilitiesService;
+import org.apache.isis.applib.value.Clob;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.SpecificationLoader;
+import org.apache.isis.core.metamodel.spec.SpecificationLoaderAware;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.metamodel.spec.feature.ObjectActionContainer.Contributed;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociationFilters;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+
+public class DeveloperUtilitiesServiceDefault implements DeveloperUtilitiesService, SpecificationLoaderAware {
+
+    private final MimeType mimeTypeTextCsv;
+
+    public DeveloperUtilitiesServiceDefault() {
+        try {
+            mimeTypeTextCsv = new MimeType("text", "csv");
+        } catch (MimeTypeParseException e) {
+            throw new RuntimeException(e);
+        }
+    }
+    
+    @Override
+    @ActionSemantics(Of.SAFE)
+    public Clob downloadMetaModel() {
+        
+        final Collection<ObjectSpecification> specifications = specificationLoader.allSpecifications();
+        
+        final List<MetaModelRow> rows = Lists.newArrayList();
+        for (ObjectSpecification spec : specifications) {
+            final List<ObjectAssociation> properties = spec.getAssociations(ObjectAssociationFilters.PROPERTIES);
+            for (ObjectAssociation property : properties) {
+                rows.add(new MetaModelRow(spec, (OneToOneAssociation)property));
+            }
+            final List<ObjectAssociation> associations = spec.getAssociations(ObjectAssociationFilters.COLLECTIONS);
+            for (ObjectAssociation collection : associations) {
+                rows.add(new MetaModelRow(spec, (OneToManyAssociation)collection));
+            }
+            final List<ObjectAction> actions = spec.getObjectActions(Contributed.INCLUDED);
+            for (ObjectAction action : actions) {
+                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());
+    }
+
+    
+    
+    private SpecificationLoader specificationLoader;
+    
+    @Override
+    @Programmatic
+    public void setSpecificationLookup(SpecificationLoader specificationLoader) {
+        this.specificationLoader = specificationLoader;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/60ba3ba8/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/devutils/MetaModelRow.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/devutils/MetaModelRow.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/devutils/MetaModelRow.java
new file mode 100644
index 0000000..8f52042
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/devutils/MetaModelRow.java
@@ -0,0 +1,246 @@
+/**
+ *  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.List;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+
+import org.apache.isis.applib.util.ObjectContracts;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facets.ImperativeFacet;
+import org.apache.isis.core.metamodel.facets.actions.choices.ActionChoicesFacet;
+import org.apache.isis.core.metamodel.facets.actions.defaults.ActionDefaultsFacet;
+import org.apache.isis.core.metamodel.facets.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.progmodel.facets.actions.validate.ActionValidationFacet;
+import org.apache.isis.core.progmodel.facets.collections.validate.CollectionValidateAddToFacet;
+import org.apache.isis.core.progmodel.facets.collections.validate.CollectionValidateRemoveFromFacet;
+import org.apache.isis.core.progmodel.facets.members.disabled.DisabledFacet;
+import org.apache.isis.core.progmodel.facets.properties.validate.PropertyValidateFacet;
+
+public class MetaModelRow implements Comparable<MetaModelRow>{
+
+    enum MemberType {
+        PROPERTY {
+            @Override
+            String getChoices(MetaModelRow metaModelRow) {
+                return interpretRowAndFacet(metaModelRow, PropertyChoicesFacet.class);
+            }
+            @Override
+            String getAutoComplete(MetaModelRow metaModelRow) {
+                return interpretRowAndFacet(metaModelRow, PropertyAutoCompleteFacet.class);
+            }
+            @Override
+            String getDefault(MetaModelRow metaModelRow) {
+                return interpretRowAndFacet(metaModelRow, PropertyDefaultFacet.class);
+            }
+            @Override
+            String getValidate(MetaModelRow metaModelRow) {
+                return interpretRowAndFacet(metaModelRow, PropertyValidateFacet.class);
+            }
+        },
+        COLLECTION {
+            @Override
+            String getChoices(MetaModelRow metaModelRow) {
+                return "";
+            }
+            @Override
+            String getAutoComplete(MetaModelRow metaModelRow) {
+                return "";
+            }
+            @Override
+            String getDefault(MetaModelRow metaModelRow) {
+                return "";
+            }
+            @Override
+            String getValidate(MetaModelRow metaModelRow) {
+                final List<String> interpretations = Lists.newArrayList();
+                addIfNotEmpty(interpretRowAndFacet(metaModelRow, CollectionValidateAddToFacet.class), interpretations);
+                addIfNotEmpty(interpretRowAndFacet(metaModelRow, CollectionValidateRemoveFromFacet.class), interpretations);
+                return !interpretations.isEmpty()? Joiner.on(";").join(interpretations) : "";
+            }
+        },
+        ACTION {
+            @Override
+            String getChoices(MetaModelRow metaModelRow) {
+                final List<ObjectActionParameter> parameters = metaModelRow.action.getParameters();
+                final List<String> interpretations = Lists.newArrayList();
+                for (ObjectActionParameter param : parameters) {
+                    final ActionParameterChoicesFacet facet = param.getFacet(ActionParameterChoicesFacet.class);
+                    addIfNotEmpty(interpretFacet(facet), interpretations);
+                }
+                return !interpretations.isEmpty()? Joiner.on(";").join(interpretations) : interpretRowAndFacet(metaModelRow, ActionChoicesFacet.class);
+            }
+            @Override
+            String getAutoComplete(MetaModelRow metaModelRow) {
+                final List<ObjectActionParameter> parameters = metaModelRow.action.getParameters();
+                final List<String> interpretations = Lists.newArrayList();
+                for (ObjectActionParameter param : parameters) {
+                    final ActionParameterAutoCompleteFacet facet = param.getFacet(ActionParameterAutoCompleteFacet.class);
+                    addIfNotEmpty(interpretFacet(facet), interpretations);
+                }
+                return !interpretations.isEmpty()? Joiner.on(";").join(interpretations) : "";
+            }
+            @Override
+            String getDefault(MetaModelRow metaModelRow) {
+                final List<ObjectActionParameter> parameters = metaModelRow.action.getParameters();
+                final List<String> interpretations = Lists.newArrayList();
+                for (ObjectActionParameter param : parameters) {
+                    final ActionParameterDefaultsFacet facet = param.getFacet(ActionParameterDefaultsFacet.class);
+                    addIfNotEmpty(interpretFacet(facet), interpretations);
+                }
+                return !interpretations.isEmpty()? Joiner.on(";").join(interpretations) : interpretRowAndFacet(metaModelRow, ActionDefaultsFacet.class);
+            }
+            @Override
+            String getValidate(MetaModelRow metaModelRow) {
+                return interpretRowAndFacet(metaModelRow, ActionValidationFacet.class);
+            }
+        };
+
+        private static String interpretRowAndFacet(MetaModelRow metaModelRow, Class<? extends Facet> facetClass) {
+            final Facet facet = metaModelRow.member.getFacet(facetClass);
+            return interpretFacet(facet);
+        }
+        
+        private static void addIfNotEmpty(final String str, final List<String> list) {
+            if(!Strings.isNullOrEmpty(str)) {
+                list.add(str);
+            }
+        }
+
+        abstract String getChoices(MetaModelRow metaModelRow);
+        abstract String getAutoComplete(MetaModelRow metaModelRow);
+        abstract String getDefault(MetaModelRow metaModelRow);
+        abstract String getValidate(MetaModelRow metaModelRow);
+    }
+    
+    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() {
+        return spec.getFullIdentifier();
+    }
+    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() {
+        return memberType.getChoices(this);
+    }
+    public String getAutoComplete() {
+        return memberType.getAutoComplete(this);
+    }
+    String getDefault() {
+        return memberType.getDefault(this);
+    }
+    String getValidate() {
+        return memberType.getValidate(this);
+    }
+
+    static Object header() {
+        return "classType,className,memberType,memberName,numParams,hidden,disabled,choices,autoComplete,default,validate";
+    }
+    
+    String asTextCsv() {
+        return Joiner.on(",").join(
+                getClassType(),
+                getClassName(),
+                getType(),
+                getMemberName(),
+                getNumParams(),
+                getHidden(),
+                getDisabled(),
+                getChoices(),
+                getAutoComplete(),
+                getDefault(),
+                getValidate());
+    }
+    
+    private String interpret(final Class<? extends Facet> cls) {
+        return interpretFacet(member.getFacet(cls));
+    }
+
+    private static String interpretFacet(final Facet facet) {
+        if (facet == null) {
+            return "";
+        }
+        if (facet instanceof ImperativeFacet) {
+            ImperativeFacet imperativeFacet = (ImperativeFacet) facet;
+            return imperativeFacet.getMethods().get(0).getName();
+        } else {
+            return "decl.";
+        }
+    }
+
+    @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/60ba3ba8/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java b/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java
index 65ce9c9..42b5ec9 100644
--- a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java
+++ b/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java
@@ -19,7 +19,6 @@
 package dom.todo;
 
 import java.math.BigDecimal;
-import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import java.util.SortedSet;
@@ -63,6 +62,7 @@ import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.applib.clock.Clock;
 import org.apache.isis.applib.filter.Filter;
 import org.apache.isis.applib.filter.Filters;
+import org.apache.isis.applib.util.ObjectContracts;
 import org.apache.isis.applib.util.TitleBuffer;
 import org.apache.isis.applib.value.Blob;
 
@@ -349,12 +349,19 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
     public static class DependenciesComparator implements Comparator<ToDoItem> {
         @Override
         public int compare(ToDoItem p, ToDoItem q) {
-            return ORDERING_BY_DESCRIPTION
+            Ordering<ToDoItem> byDescription = new Ordering<ToDoItem>() {
+                public int compare(final ToDoItem p, final ToDoItem q) {
+                    return Ordering.natural().nullsFirst().compare(p.getDescription(), q.getDescription());
+                }
+            };
+            return byDescription
                     .compound(Ordering.<ToDoItem>natural())
                     .compare(p, q);
         }
     }
 
+    
+
     @javax.jdo.annotations.Persistent(table="TODO_DEPENDENCIES")
     @javax.jdo.annotations.Join(column="DEPENDING_TODO_ID")
     @javax.jdo.annotations.Element(column="DEPENDENT_TODO_ID")
@@ -567,39 +574,12 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
     // //////////////////////////////////////
 
     /**
-     * by complete flag, then due by date, then description.
-     * 
-     * <p>
-     * Required because {@link #getDependencies()} is of type {@link SortedSet}. 
+     * Required so can store in {@link SortedSet sorted set}s (eg {@link #getDependencies()}). 
      */
     @Override
     public int compareTo(final ToDoItem other) {
-        return ORDERING_BY_COMPLETE
-                .compound(ORDERING_BY_DUE_BY)
-                .compound(ORDERING_BY_DESCRIPTION)
-                .compare(this, other);
+        return ObjectContracts.compare(this, other, "complete,dueBy,description");
     }
-    
-    private final static Ordering<ToDoItem> ORDERING_BY_COMPLETE = new Ordering<ToDoItem>() {
-        public int compare(final ToDoItem p, final ToDoItem q) {
-            return Ordering.natural().nullsFirst().compare(p.isComplete(), q.isComplete());
-        }
-    };
-    private final static Ordering<ToDoItem> ORDERING_BY_DUE_BY = new Ordering<ToDoItem>() {
-        public int compare(final ToDoItem p, final ToDoItem q) {
-            return Ordering.natural().nullsFirst().compare(p.getDueBy(), q.getDueBy());
-        }
-    };
-    private final static Ordering<ToDoItem> ORDERING_BY_DESCRIPTION = new Ordering<ToDoItem>() {
-        public int compare(final ToDoItem p, final ToDoItem q) {
-            return Ordering.natural().nullsFirst().compare(p.getDescription(), q.getDescription());
-        }
-    };
-    private final static Ordering<ToDoItem> ORDERING_BY_CATEGORY = new Ordering<ToDoItem>() {
-        public int compare(final ToDoItem p, final ToDoItem q) {
-            return Ordering.natural().nullsFirst().compare(p.getCategory(), q.getCategory());
-        }
-    };
 
     // //////////////////////////////////////
     // Injected
@@ -637,5 +617,4 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
 //        this.location = location;
 //    }
 
-
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/60ba3ba8/example/application/quickstart_wicket_restful_jdo/webapp/ide/eclipse/launch/quickstart_wicket_restful_jdo-webapp-with-fixtures.launch
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/webapp/ide/eclipse/launch/quickstart_wicket_restful_jdo-webapp-with-fixtures.launch b/example/application/quickstart_wicket_restful_jdo/webapp/ide/eclipse/launch/quickstart_wicket_restful_jdo-webapp-with-fixtures.launch
index fc241bc..3d56400 100644
--- a/example/application/quickstart_wicket_restful_jdo/webapp/ide/eclipse/launch/quickstart_wicket_restful_jdo-webapp-with-fixtures.launch
+++ b/example/application/quickstart_wicket_restful_jdo/webapp/ide/eclipse/launch/quickstart_wicket_restful_jdo-webapp-with-fixtures.launch
@@ -11,6 +11,10 @@
 <mapEntry key="[run]" value="org.eclipse.jdt.launching.localJavaApplication"/>
 </mapAttribute>
 <stringAttribute key="org.eclipse.debug.core.source_locator_id" value="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector"/>
+<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
+<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
+<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
+</listAttribute>
 <booleanAttribute key="org.eclipse.jdt.debug.ui.INCLUDE_EXTERNAL_JARS" value="true"/>
 <stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.m2e.launchconfig.classpathProvider"/>
 <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.apache.isis.WebServer"/>

http://git-wip-us.apache.org/repos/asf/isis/blob/60ba3ba8/example/application/quickstart_wicket_restful_jdo/webapp/src/main/java/app/services/DeveloperUtilities.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/webapp/src/main/java/app/services/DeveloperUtilities.java b/example/application/quickstart_wicket_restful_jdo/webapp/src/main/java/app/services/DeveloperUtilities.java
new file mode 100644
index 0000000..75c4e07
--- /dev/null
+++ b/example/application/quickstart_wicket_restful_jdo/webapp/src/main/java/app/services/DeveloperUtilities.java
@@ -0,0 +1,39 @@
+/**
+ *  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 app.services;
+
+import fixture.todo.ToDoItemsFixturesService;
+
+import org.apache.isis.applib.annotation.ActionSemantics;
+import org.apache.isis.applib.annotation.ActionSemantics.Of;
+import org.apache.isis.applib.annotation.MemberOrder;
+import org.apache.isis.applib.value.Clob;
+import org.apache.isis.core.metamodel.services.devutils.DeveloperUtilitiesServiceDefault;
+
+public class DeveloperUtilities extends DeveloperUtilitiesServiceDefault {
+
+    /**
+     * This override is simply to 'move' the action underneath the menu item
+     * for {@link ToDoItemsFixturesService fixtures}.
+     */
+    @MemberOrder(name="Fixtures", sequence="90")
+    @Override
+    @ActionSemantics(Of.SAFE)
+    public Clob downloadMetaModel() {
+        return super.downloadMetaModel();
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/60ba3ba8/example/application/quickstart_wicket_restful_jdo/webapp/src/main/webapp/WEB-INF/isis.properties
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/webapp/src/main/webapp/WEB-INF/isis.properties b/example/application/quickstart_wicket_restful_jdo/webapp/src/main/webapp/WEB-INF/isis.properties
index bc22e4c..99907bb 100644
--- a/example/application/quickstart_wicket_restful_jdo/webapp/src/main/webapp/WEB-INF/isis.properties
+++ b/example/application/quickstart_wicket_restful_jdo/webapp/src/main/webapp/WEB-INF/isis.properties
@@ -187,6 +187,7 @@ isis.reflector.facet-decorators=org.apache.isis.core.progmodel.facetdecorators.i
 #isis.services.prefix = 
 isis.services = objstore.jdo.todo.ToDoItemsJdo,\
                 fixture.todo.ToDoItemsFixturesService,\
+                app.services.DeveloperUtilities,\
                 org.apache.isis.core.metamodel.services.bookmarks.BookmarkServiceDefault,\
                 org.apache.isis.objectstore.jdo.service.RegisterEntities,\
                 org.apache.isis.objectstore.jdo.applib.service.exceprecog.ExceptionRecognizerCompositeForJdoObjectStore,\