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/10/22 00:52:49 UTC

[5/7] git commit: ISIS-437: updating quickstart archetype

ISIS-437: updating quickstart archetype


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

Branch: refs/heads/prepare/isis-1.3.0-RC1
Commit: c742898cfe9e73779bafd3e9ca360cb1021e9975
Parents: 4b83263
Author: Dan Haywood <da...@apache.org>
Authored: Mon Oct 21 23:41:48 2013 +0100
Committer: Dan Haywood <da...@apache.org>
Committed: Mon Oct 21 23:41:48 2013 +0100

----------------------------------------------------------------------
 .../quickstart_wicket_restful_jdo/dom/pom.xml   |   2 +-
 .../fixture/pom.xml                             |   2 +-
 .../integtests/pom.xml                          |   2 +-
 .../quickstart_wicket_restful_jdo/pom.xml       |  12 +-
 .../webapp/pom.xml                              |   2 +-
 .../quickstart_wicket_restful_jdo/pom.xml       |   8 +-
 .../META-INF/maven/archetype-metadata.xml       |  36 +-
 .../resources/archetype-resources/dom/pom.xml   |  75 ++-
 .../dom/src/main/java/app/ToDoAppDashboard.java |  93 ++++
 .../main/java/app/ToDoAppDashboard.layout.json  |  26 +
 .../main/java/app/ToDoAppDashboardService.java  |  52 ++
 .../dom/src/main/java/app/ToDoItemAnalysis.java | 127 +++++
 .../java/app/ToDoItemAnalysisContributions.java |  58 ++
 .../java/app/ToDoItemsByCategoryViewModel.java  | 191 +++++++
 .../ToDoItemsByCategoryViewModel.layout.json    |  43 ++
 .../java/app/ToDoItemsByDateRangeViewModel.java | 166 ++++++
 .../ToDoItemsByDateRangeViewModel.layout.json   |  33 ++
 .../dom/src/main/java/dom/todo/ToDoItem.java    | 553 ++++++++++++-------
 .../src/main/java/dom/todo/ToDoItem.layout.json |  92 +++
 .../dom/todo/ToDoItemChangedPayloadFactory.java |   4 +
 .../java/dom/todo/ToDoItemContributions.java    | 218 ++++++++
 .../dom/src/main/java/dom/todo/ToDoItems.java   | 236 ++++----
 .../src/main/java/services/ClockService.java    |  36 ++
 .../dom/src/main/resources/images/Dashboard.png | Bin 0 -> 2512 bytes
 .../src/main/resources/images/ToDoItem-done.png | Bin 0 -> 1794 bytes
 .../src/main/resources/images/ToDoItem-todo.png | Bin 0 -> 1257 bytes
 .../dom/src/main/resources/images/ToDoItem.gif  | Bin 1592 -> 0 bytes
 .../dom/src/main/resources/images/ToDoItem.png  | Bin 0 -> 1285 bytes
 .../test/java/dom/todo/ToDoTest_completed.java  |  58 ++
 .../java/dom/todo/ToDoTest_notYetCompleted.java |  51 ++
 .../java/fixture/todo/ToDoItemsFixture.java     |  82 +--
 .../fixture/todo/ToDoItemsFixturesService.java  |  67 ---
 .../integtests/logging.properties               |   2 +-
 .../archetype-resources/integtests/pom.xml      |  81 ++-
 .../java/integration/ToDoSystemInitializer.java |  88 +++
 .../integration/glue/BootstrappingGlue.java     |  59 ++
 .../integration/glue/CatalogOfFixturesGlue.java |  50 ++
 .../integration/glue/InMemoryDBForToDoApp.java  |  43 ++
 .../integration/glue/todoitem/ToDoItemGlue.java | 169 ++++++
 .../integration/specs/todoitem/RunSpecs.java    |  41 ++
 .../ToDoItemSpec_findAndComplete.feature        |  39 ++
 ...findCompletedAndMarkAsNotYetComplete.feature |  35 ++
 .../java/integration/tests/ToDoIntegTest.java   |  43 ++
 ...oDoItemContributionsTest_updateCategory.java | 102 ++++
 .../tests/actions/ToDoItemTest_completed.java   |  86 +++
 .../tests/actions/ToDoItemTest_duplicate.java   |  76 +++
 .../actions/ToDoItemTest_notYetCompleted.java   |  76 +++
 .../ToDoItemContributionsTest_similarTo.java    |  69 +++
 .../colls/ToDoItemTest_dependencies_add.java    |  92 +++
 .../colls/ToDoItemTest_dependencies_remove.java |  96 ++++
 .../ToDoItemContributionsTest_priority.java     |  71 +++
 .../tests/props/ToDoItemTest_attachment.java    |  81 +++
 .../tests/props/ToDoItemTest_category.java      |  56 ++
 .../tests/props/ToDoItemTest_cost.java          |  95 ++++
 .../tests/props/ToDoItemTest_description.java   |  94 ++++
 .../tests/props/ToDoItemTest_dueBy.java         |  99 ++++
 .../tests/props/ToDoItemTest_notes.java         |  73 +++
 .../tests/props/ToDoItemTest_ownedBy.java       |  59 ++
 .../tests/props/ToDoItemTest_subcategory.java   |  56 ++
 .../tests/repo/ToDoItemsTest_finders.java       |  78 +++
 .../repo/ToDoItemsTest_newToDo_and_delete.java  |  57 ++
 .../tests/smoke/ToDoItemTest_title.java         | 112 ++++
 .../test/java/integtests/AbstractIntegTest.java | 163 ------
 .../test/java/integtests/ToDoItem_title.java    | 119 ----
 .../integtests/actions/ToDoItem_completed.java  |  93 ----
 .../integtests/actions/ToDoItem_duplicate.java  |  81 ---
 .../actions/ToDoItem_notYetCompleted.java       |  83 ---
 .../colls/ToDoItem_dependencies_add.java        |  93 ----
 .../colls/ToDoItem_dependencies_remove.java     |  96 ----
 .../integtests/props/ToDoItem_attachment.java   |  86 ---
 .../integtests/props/ToDoItem_category.java     |  86 ---
 .../java/integtests/props/ToDoItem_cost.java    | 100 ----
 .../integtests/props/ToDoItem_description.java  |  87 ---
 .../java/integtests/props/ToDoItem_dueBy.java   | 105 ----
 .../java/integtests/props/ToDoItem_notes.java   |  81 ---
 .../java/integtests/props/ToDoItem_ownedBy.java |  53 --
 .../java/integtests/repo/ToDoItems_finders.java |  80 ---
 .../repo/ToDoItems_newToDo_and_delete.java      |  55 --
 .../archetype-resources/objstore-jdo/.gitignore |   2 -
 .../objstore-jdo/lib/.gitignore                 |   5 -
 .../archetype-resources/objstore-jdo/pom.xml    |  56 --
 .../java/objstore/jdo/todo/ToDoItemsJdo.java    |  91 ---
 .../main/resources/archetype-resources/pom.xml  |  60 +-
 .../launch/ToDoApp-no-fixtures-PROTOTYPE.launch |  26 +
 .../launch/ToDoApp-no-fixtures-SERVER.launch    |  22 +
 .../eclipse/launch/ToDoApp-with-fixtures.launch |  26 +
 ...cket_restful_jdo-webapp-with-fixtures.launch |  22 -
 .../quickstart_wicket_restful_jdo-webapp.launch |  21 -
 .../archetype-resources/webapp/pom.xml          |  32 +-
 .../ComponentFactoryRegistrarForQuickStart.java |  36 --
 .../main/java/app/QuickStartApplication.java    | 106 ----
 .../ComponentFactoryRegistrarForToDoApp.java    |  36 ++
 .../java/webapp/PageClassListForToDoApp.java    |  64 +++
 .../src/main/java/webapp/ToDoApplication.java   | 146 +++++
 .../webapp/prototyping/DeveloperUtilities.java  |  45 ++
 .../prototyping/ToDoItemsFixturesService.java   |  87 +++
 .../webapp/src/main/resources/app/welcome.html  |  31 --
 .../src/main/resources/webapp/welcome.html      |  38 ++
 .../src/main/webapp/WEB-INF/isis.properties     |  75 ++-
 .../src/main/webapp/WEB-INF/logging.properties  | 139 +++--
 .../main/webapp/WEB-INF/persistor.properties    | 107 ++++
 .../WEB-INF/persistor_datanucleus.properties    |  94 +---
 .../webapp/src/main/webapp/WEB-INF/shiro.ini    |  10 +-
 .../WEB-INF/viewer_restfulobjects.properties    |   5 +-
 .../webapp/WEB-INF/viewer_wicket.properties     |  14 +-
 .../webapp/src/main/webapp/WEB-INF/web.xml      |  25 +-
 .../webapp/src/main/webapp/about/index.html     |  57 +-
 .../webapp/src/main/webapp/css/application.css  |  43 ++
 .../src/main/webapp/images/spinning-icon.gif    | Bin 0 -> 5266 bytes
 .../projects/basic/archetype.properties         |   2 +-
 110 files changed, 4961 insertions(+), 2526 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/application/quickstart_wicket_restful_jdo/dom/pom.xml
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/dom/pom.xml b/example/application/quickstart_wicket_restful_jdo/dom/pom.xml
index 12bd977..88afaac 100644
--- a/example/application/quickstart_wicket_restful_jdo/dom/pom.xml
+++ b/example/application/quickstart_wicket_restful_jdo/dom/pom.xml
@@ -23,7 +23,7 @@
 	<parent>
     	<groupId>org.apache.isis.example.application</groupId>
     	<artifactId>quickstart_wicket_restful_jdo</artifactId>
-		<version>1.0.4-SNAPSHOT</version>
+		<version>1.3.0-SNAPSHOT</version>
 	</parent>
 
 	<artifactId>quickstart_wicket_restful_jdo-dom</artifactId>

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/application/quickstart_wicket_restful_jdo/fixture/pom.xml
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/fixture/pom.xml b/example/application/quickstart_wicket_restful_jdo/fixture/pom.xml
index 923ad96..f85a6a0 100644
--- a/example/application/quickstart_wicket_restful_jdo/fixture/pom.xml
+++ b/example/application/quickstart_wicket_restful_jdo/fixture/pom.xml
@@ -23,7 +23,7 @@
     <parent>
     	<groupId>org.apache.isis.example.application</groupId>
         <artifactId>quickstart_wicket_restful_jdo</artifactId>
-        <version>1.0.4-SNAPSHOT</version>
+        <version>1.3.0-SNAPSHOT</version>
     </parent>
 
 	<artifactId>quickstart_wicket_restful_jdo-fixture</artifactId>

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/application/quickstart_wicket_restful_jdo/integtests/pom.xml
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/pom.xml b/example/application/quickstart_wicket_restful_jdo/integtests/pom.xml
index dd33215..2e06937 100644
--- a/example/application/quickstart_wicket_restful_jdo/integtests/pom.xml
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/pom.xml
@@ -23,7 +23,7 @@
     <parent>
     	<groupId>org.apache.isis.example.application</groupId>
         <artifactId>quickstart_wicket_restful_jdo</artifactId>
-        <version>1.0.4-SNAPSHOT</version>
+        <version>1.3.0-SNAPSHOT</version>
     </parent>
 
 	<artifactId>quickstart_wicket_restful_jdo-integtests</artifactId>

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/application/quickstart_wicket_restful_jdo/pom.xml
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/pom.xml b/example/application/quickstart_wicket_restful_jdo/pom.xml
index 99d6f74..5164683 100644
--- a/example/application/quickstart_wicket_restful_jdo/pom.xml
+++ b/example/application/quickstart_wicket_restful_jdo/pom.xml
@@ -23,18 +23,18 @@
 
     <groupId>org.apache.isis.example.application</groupId>
     <artifactId>quickstart_wicket_restful_jdo</artifactId>
-    <version>1.0.4-SNAPSHOT</version>
+    <version>1.3.0-SNAPSHOT</version>
 
     <name>Quickstart Wicket/Restful/JDO App</name>
 
     <packaging>pom</packaging>
 
 	<properties>
-        <isis.version>1.3.0-SNAPSHOT</isis.version>
-		<isis-objectstore-jdo.version>1.2.0-SNAPSHOT</isis-objectstore-jdo.version>
-		<isis-viewer-wicket.version>1.3.0-SNAPSHOT</isis-viewer-wicket.version>
-		<isis-viewer-restfulobjects.version>2.1.0-SNAPSHOT</isis-viewer-restfulobjects.version>
-		<isis-security-shiro.version>1.1.2-SNAPSHOT</isis-security-shiro.version>
+        <isis.version>1.3.0</isis.version>
+		<isis-objectstore-jdo.version>1.3.0</isis-objectstore-jdo.version>
+		<isis-viewer-wicket.version>1.3.0</isis-viewer-wicket.version>
+		<isis-viewer-restfulobjects.version>2.1.0</isis-viewer-restfulobjects.version>
+		<isis-security-shiro.version>1.3.0</isis-security-shiro.version>
 
         <!-- must be consistent with the versions defined by the JDO Objectstore -->
         <datanucleus-core.version>3.2.7</datanucleus-core.version>

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/application/quickstart_wicket_restful_jdo/webapp/pom.xml
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/webapp/pom.xml b/example/application/quickstart_wicket_restful_jdo/webapp/pom.xml
index e9b4186..aad3a41 100644
--- a/example/application/quickstart_wicket_restful_jdo/webapp/pom.xml
+++ b/example/application/quickstart_wicket_restful_jdo/webapp/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.isis.example.application</groupId>
         <artifactId>quickstart_wicket_restful_jdo</artifactId>
-        <version>1.0.4-SNAPSHOT</version>
+        <version>1.3.0-SNAPSHOT</version>
     </parent>
 
     <artifactId>quickstart_wicket_restful_jdo-webapp</artifactId>

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/pom.xml
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/pom.xml b/example/archetype/quickstart_wicket_restful_jdo/pom.xml
index e33740e..d449259 100644
--- a/example/archetype/quickstart_wicket_restful_jdo/pom.xml
+++ b/example/archetype/quickstart_wicket_restful_jdo/pom.xml
@@ -17,11 +17,11 @@
   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/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.apache.isis.archetype</groupId>
   <artifactId>quickstart_wicket_restful_jdo-archetype</artifactId>
-  <version>1.0.4-SNAPSHOT</version>
+  <version>1.3.0-SNAPSHOT</version>
   <packaging>maven-archetype</packaging>
   <name>quickstart_wicket_restful_jdo-archetype</name>
   <build>
@@ -44,7 +44,7 @@
   <parent>
     <groupId>org.apache.isis.core</groupId>
     <artifactId>isis</artifactId>
-    <version>1.3.0-SNAPSHOT</version>
-    <relativePath>../../../core/pom.xml</relativePath>
+    <version>1.3.0</version>
+    <relativePath>../../../core/pom.xm</relativePath>
   </parent>
 </project>

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/META-INF/maven/archetype-metadata.xml
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/META-INF/maven/archetype-metadata.xml b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/META-INF/maven/archetype-metadata.xml
index 3dc69b7..8152952 100644
--- a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/META-INF/maven/archetype-metadata.xml
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/META-INF/maven/archetype-metadata.xml
@@ -29,37 +29,32 @@
           </includes>
         </fileSet>
         <fileSet encoding="UTF-8">
-          <directory>src/main/resources</directory>
+          <directory>src/main/java</directory>
           <includes>
-            <include>**/*.png</include>
-            <include>**/*.gif</include>
+            <include>**/*.json</include>
           </includes>
         </fileSet>
-        <fileSet filtered="true" encoding="UTF-8">
-          <directory/>
+        <fileSet encoding="UTF-8">
+          <directory>src/main/resources</directory>
           <includes>
-            <include>log4j.properties</include>
+            <include>**/*.png</include>
           </includes>
         </fileSet>
-      </fileSets>
-    </module>
-    <module id="${rootArtifactId}-fixture" dir="fixture" name="${rootArtifactId}-fixture">
-      <fileSets>
         <fileSet filtered="true" encoding="UTF-8">
-          <directory>src/main/java</directory>
+          <directory>src/test/java</directory>
           <includes>
             <include>**/*.java</include>
           </includes>
         </fileSet>
-        <fileSet encoding="UTF-8">
+        <fileSet filtered="true" encoding="UTF-8">
           <directory/>
           <includes>
-            <include>.gitignore</include>
+            <include>log4j.properties</include>
           </includes>
         </fileSet>
       </fileSets>
     </module>
-    <module id="${rootArtifactId}-objstore-jdo" dir="objstore-jdo" name="${rootArtifactId}-objstore-jdo">
+    <module id="${rootArtifactId}-fixture" dir="fixture" name="${rootArtifactId}-fixture">
       <fileSets>
         <fileSet filtered="true" encoding="UTF-8">
           <directory>src/main/java</directory>
@@ -68,12 +63,6 @@
           </includes>
         </fileSet>
         <fileSet encoding="UTF-8">
-          <directory>lib</directory>
-          <includes>
-            <include>**/*.gitignore</include>
-          </includes>
-        </fileSet>
-        <fileSet encoding="UTF-8">
           <directory/>
           <includes>
             <include>.gitignore</include>
@@ -89,6 +78,12 @@
             <include>**/*.java</include>
           </includes>
         </fileSet>
+        <fileSet encoding="UTF-8">
+          <directory>src/test/java</directory>
+          <includes>
+            <include>**/*.feature</include>
+          </includes>
+        </fileSet>
         <fileSet filtered="true" encoding="UTF-8">
           <directory/>
           <includes>
@@ -134,6 +129,7 @@
             <include>**/*.png</include>
             <include>**/*.js</include>
             <include>**/*.ini</include>
+            <include>**/*.gif</include>
             <include>**/*.css</include>
           </includes>
         </fileSet>

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/pom.xml
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/pom.xml b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/pom.xml
index 34893cf..97795bf 100644
--- a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/pom.xml
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/pom.xml
@@ -29,11 +29,39 @@
 	<name>Quickstart Wicket/Restful/JDO DOM</name>
 
 	<build>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+            </resource>
+            <resource>
+                <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>3.2.0-release</version>
+                <dependencies>
+                    <dependency>
+                        <!-- Force the enhancer to use the same version of core as the JDO objectstore -->
+                        <groupId>org.datanucleus</groupId>
+                        <artifactId>datanucleus-core</artifactId>
+                        <version>${datanucleus-core.version}</version>
+                    </dependency>
+                    <dependency>
+                        <!-- Force the enhancer to use the same version of jdo-api as the JDO objectstore -->
+                        <groupId>javax.jdo</groupId>
+                        <artifactId>jdo-api</artifactId>
+                        <version>${jdo-api.version}</version>
+                    </dependency>
+                </dependencies>
                 <configuration>
                 	<fork>false</fork>
                     <log4jConfiguration>${basedir}/log4j.properties</log4jConfiguration>
@@ -91,49 +119,38 @@
             <groupId>org.apache.isis.objectstore</groupId>
 			<artifactId>isis-objectstore-jdo-applib</artifactId>
 		</dependency>
+        
+		<dependency>
+            <groupId>org.apache.isis.core</groupId>
+			<artifactId>isis-core-unittestsupport</artifactId>
+            <scope>test</scope>
+		</dependency>
 
-
-		<!-- DataNucleus (horrid, but needed to run the enhancer)-->
+        <!-- Bytecode libraries (for mocking) -->
         <dependency>
-            <groupId>javax.jdo</groupId>
-            <artifactId>jdo-api</artifactId>
+            <groupId>asm</groupId>
+            <artifactId>asm</artifactId>
+            <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.datanucleus</groupId>
-            <artifactId>datanucleus-core</artifactId>
+            <groupId>org.objenesis</groupId>
+            <artifactId>objenesis</artifactId>
+            <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.datanucleus</groupId>
-            <artifactId>datanucleus-api-jdo</artifactId>
+            <groupId>cglib</groupId>
+            <artifactId>cglib-nodep</artifactId>
+            <scope>test</scope>
         </dependency>
-        
+
         <!--
         GMAP3: uncomment to use https://github.com/danhaywood/isis-wicket-gmap3 
         <dependency>
-            <groupId>com.danhaywood.isis.wicket.ui.components</groupId>
+            <groupId>com.danhaywood.isis.wicket</groupId>
             <artifactId>danhaywood-isis-wicket-gmap3-applib</artifactId>
         </dependency>
          -->
         
 	</dependencies>
-
-   <profiles>
-        <profile>
-            <id>not-m2e</id>
-            <activation>
-                <property>
-                    <name>!m2e.version</name>
-                </property>
-            </activation>
-            <dependencies>
-                <dependency>
-                    <groupId>org.datanucleus</groupId>
-                    <artifactId>datanucleus-core</artifactId>
-                    <version>(3.1.99, 3.2.99)</version>
-                    <scope>runtime</scope>
-                </dependency>
-            </dependencies>
-        </profile>
-    </profiles>
     
 </project>

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoAppDashboard.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoAppDashboard.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoAppDashboard.java
new file mode 100644
index 0000000..fa09398
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoAppDashboard.java
@@ -0,0 +1,93 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+/*
+ *  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;
+
+import java.util.List;
+
+import org.apache.isis.applib.AbstractViewModel;
+import org.apache.isis.applib.annotation.Disabled;
+import org.apache.isis.applib.annotation.Named;
+import org.apache.isis.applib.annotation.Render;
+import org.apache.isis.applib.annotation.Render.Type;
+
+public class ToDoAppDashboard extends AbstractViewModel {
+
+    public String title() {
+        return "Dashboard";
+    }
+    
+    public String iconName() {
+        return "Dashboard";
+    }
+    
+    // //////////////////////////////////////
+    // ViewModel contract
+    // //////////////////////////////////////
+
+    private String memento;
+    
+    @Override
+    public String viewModelMemento() {
+        return memento;
+    }
+
+    @Override
+    public void viewModelInit(String memento) {
+        this.memento = memento;
+    }
+
+
+    // //////////////////////////////////////
+    // getAnalysisByCategory
+    // //////////////////////////////////////
+
+    @Named("By Category")
+    @Render(Type.EAGERLY)
+    @Disabled
+    public List<ToDoItemsByCategoryViewModel> getAnalysisByCategory() {
+        return toDoItemAnalysis.toDoItemsByCategory();
+    }
+    
+    // //////////////////////////////////////
+    // getAnalysisByDateRange
+    // //////////////////////////////////////
+    
+    @Named("By Date Range")
+    @Render(Type.EAGERLY)
+    @Disabled
+    public List<ToDoItemsByDateRangeViewModel> getAnalysisByDateRange() {
+        return toDoItemAnalysis.toDoItemsByDateRange();
+    }
+    
+
+    // //////////////////////////////////////
+    // injected services
+    // //////////////////////////////////////
+    
+    private ToDoItemAnalysis toDoItemAnalysis;
+    
+    public void injectToDoItemAnalysis(ToDoItemAnalysis toDoItemAnalysis) {
+        this.toDoItemAnalysis = toDoItemAnalysis;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoAppDashboard.layout.json
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoAppDashboard.layout.json b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoAppDashboard.layout.json
new file mode 100644
index 0000000..3421543
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoAppDashboard.layout.json
@@ -0,0 +1,26 @@
+{
+  "columns": [
+    {
+      "span": 0,
+      "memberGroups": {}
+    },
+    {
+      "span": 0,
+      "memberGroups": {}
+    },
+    {
+      "span": 0,
+      "memberGroups": {}
+    },
+    {
+      "span": 12,
+      "collections": {
+        "analysisByCategory": {}
+      }
+    }
+  ],
+  "actions": {
+    "downloadLayout": {},
+    "refreshLayout": {}
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoAppDashboardService.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoAppDashboardService.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoAppDashboardService.java
new file mode 100644
index 0000000..14ff4b7
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoAppDashboardService.java
@@ -0,0 +1,52 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+/*
+ *  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;
+
+import org.apache.isis.applib.AbstractService;
+import org.apache.isis.applib.annotation.ActionSemantics;
+import org.apache.isis.applib.annotation.ActionSemantics.Of;
+import org.apache.isis.applib.annotation.Hidden;
+import org.apache.isis.applib.annotation.HomePage;
+
+@Hidden
+public class ToDoAppDashboardService extends AbstractService {
+
+    private static final String ID = "dashboard";
+
+    public String getId() {
+        return ID;
+    }
+
+    public String iconName() {
+        return ID;
+    }
+
+    // //////////////////////////////////////
+
+    @ActionSemantics(Of.SAFE)
+    @HomePage
+    public ToDoAppDashboard lookup() {
+        return newViewModelInstance(ToDoAppDashboard.class, ID);
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemAnalysis.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemAnalysis.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemAnalysis.java
new file mode 100644
index 0000000..90705c4
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemAnalysis.java
@@ -0,0 +1,127 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+/*
+ *  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;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import dom.todo.ToDoItem.Category;
+
+import org.apache.isis.applib.AbstractFactoryAndRepository;
+import org.apache.isis.applib.annotation.ActionSemantics;
+import org.apache.isis.applib.annotation.ActionSemantics.Of;
+import org.apache.isis.applib.annotation.Bookmarkable;
+import org.apache.isis.applib.annotation.MemberOrder;
+import org.apache.isis.applib.annotation.Named;
+import org.apache.isis.applib.annotation.Programmatic;
+
+@Named("Analysis")
+public class ToDoItemAnalysis extends AbstractFactoryAndRepository {
+
+    // //////////////////////////////////////
+    // Identification in the UI
+    // //////////////////////////////////////
+
+    @Override
+    public String getId() {
+        return "analysis";
+    }
+
+    public String iconName() {
+        return "ToDoItem";
+    }
+
+    // //////////////////////////////////////
+    // ByCategory (action)
+    // //////////////////////////////////////
+    
+    @Named("By Category")
+    @Bookmarkable
+    @ActionSemantics(Of.SAFE)
+    @MemberOrder(sequence = "1")
+    public List<ToDoItemsByCategoryViewModel> toDoItemsByCategory() {
+        final List<Category> categories = Arrays.asList(Category.values());
+        return Lists.newArrayList(Iterables.transform(categories, byCategory()));
+    }
+
+    private Function<Category, ToDoItemsByCategoryViewModel> byCategory() {
+        return new Function<Category, ToDoItemsByCategoryViewModel>(){
+             @Override
+             public ToDoItemsByCategoryViewModel apply(final Category category) {
+                 final ToDoItemsByCategoryViewModel byCategory = 
+                     getContainer().newViewModelInstance(ToDoItemsByCategoryViewModel.class, category.name());
+                 byCategory.setCategory(category);
+                 return byCategory;
+             }
+         };
+    }
+
+    // //////////////////////////////////////
+    // ByDateRange (action)
+    // //////////////////////////////////////
+    
+    public enum DateRange {
+        OverDue,
+        Today,
+        Tomorrow,
+        ThisWeek,
+        Later,
+        Unknown,
+    }
+    
+    @Named("By Date Range")
+    @Bookmarkable
+    @ActionSemantics(Of.SAFE)
+    @MemberOrder(sequence = "1")
+    public List<ToDoItemsByDateRangeViewModel> toDoItemsByDateRange() {
+        final List<DateRange> dateRanges = Arrays.asList(DateRange.values());
+        return Lists.newArrayList(Iterables.transform(dateRanges, byDateRange()));
+    }
+
+    private Function<DateRange, ToDoItemsByDateRangeViewModel> byDateRange() {
+        return new Function<DateRange, ToDoItemsByDateRangeViewModel>(){
+             @Override
+             public ToDoItemsByDateRangeViewModel apply(final DateRange dateRange) {
+                 final ToDoItemsByDateRangeViewModel byDateRange = 
+                     getContainer().newViewModelInstance(ToDoItemsByDateRangeViewModel.class, dateRange.name());
+                 byDateRange.setDateRange(dateRange);
+                 return byDateRange;
+             }
+         };
+    }
+    
+    
+    // //////////////////////////////////////
+    // ForCategory (programmatic)
+    // //////////////////////////////////////
+
+    @Programmatic
+    public ToDoItemsByCategoryViewModel toDoItemsForCategory(Category category) {
+        return byCategory().apply(category);
+    }
+    
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemAnalysisContributions.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemAnalysisContributions.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemAnalysisContributions.java
new file mode 100644
index 0000000..37b60d7
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemAnalysisContributions.java
@@ -0,0 +1,58 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+/*
+ *  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;
+
+import dom.todo.ToDoItem;
+
+import org.apache.isis.applib.AbstractFactoryAndRepository;
+import org.apache.isis.applib.annotation.ActionSemantics;
+import org.apache.isis.applib.annotation.NotContributed;
+import org.apache.isis.applib.annotation.NotInServiceMenu;
+import org.apache.isis.applib.annotation.ActionSemantics.Of;
+import org.apache.isis.applib.annotation.NotContributed.As;
+import org.apache.isis.applib.annotation.Hidden;
+
+@Hidden
+public class ToDoItemAnalysisContributions extends AbstractFactoryAndRepository {
+
+
+    // //////////////////////////////////////
+    // AnalyseCategory
+    // //////////////////////////////////////
+
+    @NotInServiceMenu
+    @NotContributed(As.ASSOCIATION)
+    @ActionSemantics(Of.SAFE)
+    public ToDoItemsByCategoryViewModel analyseCategory(final ToDoItem item) {
+        return toDoAppAnalysis.toDoItemsForCategory(item.getCategory());
+    }
+
+    
+    // //////////////////////////////////////
+    // injected services
+    // //////////////////////////////////////
+
+    private ToDoItemAnalysis toDoAppAnalysis;
+    public void injectToDoAppAnalysis(ToDoItemAnalysis toDoAppAnalysis) {
+        this.toDoAppAnalysis = toDoAppAnalysis;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByCategoryViewModel.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByCategoryViewModel.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByCategoryViewModel.java
new file mode 100644
index 0000000..79da2f2
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByCategoryViewModel.java
@@ -0,0 +1,191 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+/*
+ *  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;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.google.common.base.Function;
+import com.google.common.base.Joiner;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import dom.todo.ToDoItem;
+import dom.todo.ToDoItem.Category;
+import dom.todo.ToDoItem.Subcategory;
+import dom.todo.ToDoItems;
+
+import org.apache.isis.applib.AbstractViewModel;
+import org.apache.isis.applib.Identifier;
+import org.apache.isis.applib.annotation.Bookmarkable;
+import org.apache.isis.applib.annotation.Bounded;
+import org.apache.isis.applib.annotation.Disabled;
+import org.apache.isis.applib.annotation.MultiLine;
+import org.apache.isis.applib.annotation.Named;
+import org.apache.isis.applib.annotation.Render;
+import org.apache.isis.applib.annotation.Render.Type;
+import org.apache.isis.applib.annotation.Title;
+import org.apache.isis.applib.util.ObjectContracts;
+
+@Named("By Category")
+@Bookmarkable
+public class ToDoItemsByCategoryViewModel 
+        extends AbstractViewModel 
+        implements Comparable<ToDoItemsByCategoryViewModel> {
+
+    
+    // //////////////////////////////////////
+    // ViewModel implementation
+    // //////////////////////////////////////
+
+    @Override
+    public String viewModelMemento() {
+        return getCategory().name();
+    }
+
+    @Override
+    public void viewModelInit(String memento) {
+        setCategory(Category.valueOf(memento));
+    }
+
+    // //////////////////////////////////////
+    // Category
+    // //////////////////////////////////////
+
+    private Category category;
+
+    /**
+     * Used as {@link ${symbol_pound}viewModelMemento() memento}
+     */
+    @Title
+    public Category getCategory() {
+        return category;
+    }
+
+    public void setCategory(final Category category) {
+        this.category = category;
+    }
+
+
+    // //////////////////////////////////////
+    // NotYetComplete, Complete
+    // //////////////////////////////////////
+
+    @MultiLine(numberOfLines=5)
+    public String getNotYetComplete() {
+        final List<ToDoItem> notYetComplete = getItemsNotYetComplete();
+        return Joiner.on(", ").join(
+            Iterables.transform(subcategories(), summarizeBySubcategory(notYetComplete)));
+    }
+
+    // //////////////////////////////////////
+
+    @MultiLine(numberOfLines=5)
+    public String getComplete() {
+        final List<ToDoItem> completeInCategory = getItemsComplete();
+        return Joiner.on(", ").join(
+            Iterables.transform(subcategories(), summarizeBySubcategory(completeInCategory)));
+    }
+
+    // //////////////////////////////////////
+
+    private Iterable<Subcategory> subcategories() {
+        return Iterables.filter(Arrays.asList(Subcategory.values()), Subcategory.thoseFor(getCategory()));
+    }
+
+    private Function<Subcategory, String> summarizeBySubcategory(final Iterable<ToDoItem> itemsInCategory) {
+        return new Function<Subcategory, String>() {
+            @Override
+            public String apply(final Subcategory subcategory) {
+                return subcategory + ": " + countIn(itemsInCategory, subcategory);
+            }
+        };
+    }
+
+    private static int countIn(final Iterable<ToDoItem> items, final Subcategory subcategory) {
+        return Iterables.size(Iterables.filter(items, 
+                ToDoItem.Predicates.thoseSubcategorised(subcategory)));
+    }
+
+    
+    // //////////////////////////////////////
+    // getItemsNotYetComplete, getItemsComplete
+    // //////////////////////////////////////
+
+    /**
+     * All those items {@link ToDoItems${symbol_pound}notYetComplete() not yet complete}, for this {@link ${symbol_pound}getCategory() category}.
+     */
+    @Render(Type.EAGERLY)
+    public List<ToDoItem> getItemsNotYetComplete() {
+        final List<ToDoItem> notYetComplete = toDoItems.notYetCompleteNoUi();
+        return Lists.newArrayList(Iterables.filter(notYetComplete, ToDoItem.Predicates.thoseCategorised(getCategory())));
+    }
+
+    // //////////////////////////////////////
+
+    /**
+     * All those items {@link ToDoItems${symbol_pound}complete() complete}, for this {@link ${symbol_pound}getCategory() category}.
+     */
+    @Render(Type.EAGERLY)
+    public List<ToDoItem> getItemsComplete() {
+        final List<ToDoItem> complete = toDoItems.completeNoUi();
+        return Lists.newArrayList(Iterables.filter(complete, ToDoItem.Predicates.thoseCategorised(getCategory())));
+    }
+
+    
+    // //////////////////////////////////////
+    // DeleteCompleted (action)
+    // //////////////////////////////////////
+
+    @Named("Delete")
+    public ToDoItemsByCategoryViewModel deleteCompleted() {
+        for (ToDoItem item : getItemsComplete()) {
+            removeIfNotAlready(item);
+        }
+        // force reload of page
+        return this;
+    }
+    
+    
+
+    // //////////////////////////////////////
+    // compareTo
+    // //////////////////////////////////////
+
+    @Override
+    public int compareTo(ToDoItemsByCategoryViewModel other) {
+        return ObjectContracts.compare(this, other, "category");
+    }
+
+    
+    // //////////////////////////////////////
+    // injected services
+    // //////////////////////////////////////
+    
+    private ToDoItems toDoItems;
+
+    public void injectedToDoItems(final ToDoItems toDoItems) {
+        this.toDoItems = toDoItems;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByCategoryViewModel.layout.json
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByCategoryViewModel.layout.json b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByCategoryViewModel.layout.json
new file mode 100644
index 0000000..c87b554
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByCategoryViewModel.layout.json
@@ -0,0 +1,43 @@
+{
+  "columns": [
+    {
+      "span": 4,
+      "memberGroups": {
+        "General": {
+          "members": {
+            "category": {}
+          }
+        },
+        "Analysis": {
+          "members": {
+            "notYetComplete": {},
+            "complete": {}
+          }
+        }
+      }
+    },
+    {
+      "span": 0,
+      "memberGroups": {}
+    },
+    {
+      "span": 0,
+      "memberGroups": {}
+    },
+    {
+      "span": 8,
+      "collections": {
+        "itemsNotYetComplete": {},
+        "itemsComplete": {
+          "actions": {
+            "deleteCompleted": {}
+          }
+        }
+      }
+    }
+  ],
+  "actions": {
+    "downloadLayout": {},
+    "refreshLayout": {}
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByDateRangeViewModel.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByDateRangeViewModel.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByDateRangeViewModel.java
new file mode 100644
index 0000000..6d9b1fd
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByDateRangeViewModel.java
@@ -0,0 +1,166 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+/*
+ *  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;
+
+import java.util.List;
+
+import app.ToDoItemAnalysis.DateRange;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import dom.todo.ToDoItem;
+import dom.todo.ToDoItems;
+
+import org.joda.time.DateTime;
+
+import org.apache.isis.applib.AbstractViewModel;
+import org.apache.isis.applib.annotation.Bookmarkable;
+import org.apache.isis.applib.annotation.Named;
+import org.apache.isis.applib.annotation.Render;
+import org.apache.isis.applib.annotation.Render.Type;
+import org.apache.isis.applib.annotation.Title;
+import org.apache.isis.applib.util.ObjectContracts;
+
+import services.ClockService;
+
+@Named("By Date Range")
+@Bookmarkable
+public class ToDoItemsByDateRangeViewModel 
+        extends AbstractViewModel 
+        implements Comparable<ToDoItemsByDateRangeViewModel> {
+
+    
+    // //////////////////////////////////////
+    // ViewModel implementation
+    // //////////////////////////////////////
+
+    @Override
+    public String viewModelMemento() {
+        return getDateRange().name();
+    }
+
+    @Override
+    public void viewModelInit(String memento) {
+        setDateRange(DateRange.valueOf(memento));
+    }
+
+    // //////////////////////////////////////
+    // DateRange
+    // //////////////////////////////////////
+
+    private DateRange dateRange;
+
+    /**
+     * Used as {@link ${symbol_pound}viewModelMemento() memento}
+     */
+    @Title
+    public DateRange getDateRange() {
+        return dateRange;
+    }
+
+    public void setDateRange(final DateRange dateRange) {
+        this.dateRange = dateRange;
+    }
+
+
+    // //////////////////////////////////////
+    // Count
+    // //////////////////////////////////////
+
+    public int getCount() {
+        return getItemsNotYetComplete().size();
+    }
+    
+    // //////////////////////////////////////
+    // getItemsNotYetComplete
+    // //////////////////////////////////////
+
+    /**
+     * All those items {@link ToDoItems${symbol_pound}notYetComplete() not yet complete}, for this {@link ${symbol_pound}getCategory() category}.
+     */
+    @Render(Type.EAGERLY)
+    public List<ToDoItem> getItemsNotYetComplete() {
+        final List<ToDoItem> notYetComplete = toDoItems.notYetCompleteNoUi();
+        return Lists.newArrayList(Iterables.filter(notYetComplete, thoseInDateRange()));
+    }
+
+    private Predicate<ToDoItem> thoseInDateRange() {
+        return new Predicate<ToDoItem>() {
+            @Override
+            public boolean apply(ToDoItem t) {
+                return Objects.equal(dateRangeFor(t), getDateRange());
+            }
+        };
+    }
+    
+    private DateRange dateRangeFor(final ToDoItem t) {
+        if(t.getDueBy() == null) {
+            return DateRange.Unknown;
+        }
+        final DateTime dueBy = t.getDueBy().toDateTimeAtStartOfDay();
+        final DateTime today = clockService.now().toDateTimeAtStartOfDay();
+        
+        if(dueBy.isBefore(today)) {
+            return DateRange.OverDue;
+        }
+        if(dueBy.isBefore(today.plusDays(1))) {
+            return DateRange.Today;
+        }
+        if(dueBy.isBefore(today.plusDays(2))) {
+            return DateRange.Tomorrow;
+        }
+        if(dueBy.isBefore(today.plusDays(7))) {
+            return DateRange.ThisWeek;
+        }
+        return DateRange.Later;
+    }
+
+
+    // //////////////////////////////////////
+    // compareTo
+    // //////////////////////////////////////
+
+    @Override
+    public int compareTo(ToDoItemsByDateRangeViewModel other) {
+        return ObjectContracts.compare(this, other, "dateRange");
+    }
+
+    
+    // //////////////////////////////////////
+    // injected services
+    // //////////////////////////////////////
+    
+    private ToDoItems toDoItems;
+
+    public void injectedToDoItems(final ToDoItems toDoItems) {
+        this.toDoItems = toDoItems;
+    }
+
+    private ClockService clockService;
+    public void injectClockService(ClockService clockService) {
+        this.clockService = clockService;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByDateRangeViewModel.layout.json
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByDateRangeViewModel.layout.json b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByDateRangeViewModel.layout.json
new file mode 100644
index 0000000..648e146
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/app/ToDoItemsByDateRangeViewModel.layout.json
@@ -0,0 +1,33 @@
+{
+  "columns": [
+    {
+      "span": 4,
+      "memberGroups": {
+        "General": {
+          "members": {
+            "dateRange": {},
+            "count": {}
+          }
+        }
+      }
+    },
+    {
+      "span": 0,
+      "memberGroups": {}
+    },
+    {
+      "span": 0,
+      "memberGroups": {}
+    },
+    {
+      "span": 8,
+      "collections": {
+        "itemsNotYetComplete": {}
+      }
+    }
+  ],
+  "actions": {
+    "downloadLayout": {},
+    "refreshLayout": {}
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.java
index b854ae2..446e560 100644
--- a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.java
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.java
@@ -22,18 +22,22 @@
 package dom.todo;
 
 import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 import java.util.SortedSet;
 import java.util.TreeSet;
 
 import javax.jdo.JDOHelper;
-import javax.jdo.annotations.Column;
 import javax.jdo.annotations.IdentityType;
 import javax.jdo.annotations.VersionStrategy;
 import javax.jdo.spi.PersistenceCapable;
 
 import com.google.common.base.Objects;
-import com.google.common.collect.Lists;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Ordering;
 
 import org.joda.time.LocalDate;
 
@@ -42,13 +46,13 @@ import org.apache.isis.applib.annotation.Audited;
 import org.apache.isis.applib.annotation.AutoComplete;
 import org.apache.isis.applib.annotation.Bookmarkable;
 import org.apache.isis.applib.annotation.Bulk;
+import org.apache.isis.applib.annotation.Bulk.InteractionContext;
+import org.apache.isis.applib.annotation.CssClass;
 import org.apache.isis.applib.annotation.Disabled;
 import org.apache.isis.applib.annotation.Hidden;
-import org.apache.isis.applib.annotation.MemberGroups;
-import org.apache.isis.applib.annotation.MemberOrder;
+import org.apache.isis.applib.annotation.MinLength;
 import org.apache.isis.applib.annotation.MultiLine;
 import org.apache.isis.applib.annotation.Named;
-import org.apache.isis.applib.annotation.NotPersisted;
 import org.apache.isis.applib.annotation.ObjectType;
 import org.apache.isis.applib.annotation.Optional;
 import org.apache.isis.applib.annotation.Programmatic;
@@ -57,49 +61,76 @@ import org.apache.isis.applib.annotation.PublishedObject;
 import org.apache.isis.applib.annotation.RegEx;
 import org.apache.isis.applib.annotation.Render;
 import org.apache.isis.applib.annotation.Render.Type;
+import org.apache.isis.applib.annotation.SortedBy;
 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;
 
+import services.ClockService;
+
 @javax.jdo.annotations.PersistenceCapable(identityType=IdentityType.DATASTORE)
-@javax.jdo.annotations.DatastoreIdentity(strategy=javax.jdo.annotations.IdGeneratorStrategy.IDENTITY)
+@javax.jdo.annotations.DatastoreIdentity(
+        strategy=javax.jdo.annotations.IdGeneratorStrategy.IDENTITY,
+         column="id")
+@javax.jdo.annotations.Version(
+        strategy=VersionStrategy.VERSION_NUMBER, 
+        column="version")
+@javax.jdo.annotations.Uniques({
+    @javax.jdo.annotations.Unique(
+            name="ToDoItem_description_must_be_unique", 
+            members={"ownedBy","description"})
+})
 @javax.jdo.annotations.Queries( {
     @javax.jdo.annotations.Query(
-            name="todo_all", language="JDOQL",  
-            value="SELECT FROM dom.todo.ToDoItem WHERE ownedBy == :ownedBy"),
+            name = "todo_all", language = "JDOQL",
+            value = "SELECT "
+                    + "FROM dom.todo.ToDoItem "
+                    + "WHERE ownedBy == :ownedBy"),
     @javax.jdo.annotations.Query(
-        name="todo_notYetComplete", language="JDOQL",  
-        value="SELECT FROM dom.todo.ToDoItem WHERE ownedBy == :ownedBy && complete == false"),
+            name = "todo_notYetComplete", language = "JDOQL",
+            value = "SELECT "
+                    + "FROM dom.todo.ToDoItem "
+                    + "WHERE ownedBy == :ownedBy "
+                    + "   && complete == false"),
     @javax.jdo.annotations.Query(
-            name="todo_complete", language="JDOQL",  
-            value="SELECT FROM dom.todo.ToDoItem WHERE ownedBy == :ownedBy && complete == true"),
+            name = "todo_complete", language = "JDOQL",
+            value = "SELECT "
+                    + "FROM dom.todo.ToDoItem "
+                    + "WHERE ownedBy == :ownedBy "
+                    + "&& complete == true"),
     @javax.jdo.annotations.Query(
-        name="todo_similarTo", language="JDOQL",  
-        value="SELECT FROM dom.todo.ToDoItem WHERE ownedBy == :ownedBy && category == :category"),
+            name = "todo_similarTo", language = "JDOQL",
+            value = "SELECT "
+                    + "FROM dom.todo.ToDoItem "
+                    + "WHERE ownedBy == :ownedBy "
+                    + "&& category == :category"),
     @javax.jdo.annotations.Query(
-            name="todo_autoComplete", language="JDOQL",  
-            value="SELECT FROM dom.todo.ToDoItem WHERE ownedBy == :ownedBy && description.indexOf(:description) >= 0")
+            name = "todo_autoComplete", language = "JDOQL",
+            value = "SELECT "
+                    + "FROM dom.todo.ToDoItem "
+                    + "WHERE ownedBy == :ownedBy && "
+                    + "description.indexOf(:description) >= 0")
 })
-@javax.jdo.annotations.Version(strategy=VersionStrategy.VERSION_NUMBER, column="VERSION")
-@javax.jdo.annotations.Unique(name="ToDoItem_description_must_be_unique", members={"ownedBy","description"})
 @ObjectType("TODO")
 @Audited
 @PublishedObject(ToDoItemChangedPayloadFactory.class)
-@AutoComplete(repository=ToDoItems.class, action="autoComplete")
-@MemberGroups({"General", "Detail"})
+@AutoComplete(repository=ToDoItems.class, action="autoComplete") // default unless overridden by autoCompleteNXxx() method
+//@Bounded - if there were a small number of instances only (overrides autoComplete functionality)
 @Bookmarkable
 public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3: uncomment to use https://github.com/danhaywood/isis-wicket-gmap3
 
-	private static final long ONE_WEEK_IN_MILLIS = 7 * 24 * 60 * 60 * 1000L;
-
-    public static enum Category {
-        Professional, Domestic, Other;
-    }
+    /**
+     * It isn't common for entities to log, but they can if required.  
+     * Isis uses the slf4j internally, and is the recommended API to use. 
+     */
+    private final static org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(ToDoItem.class);
+    
+    // //////////////////////////////////////
+    // Identification in the UI
+    // //////////////////////////////////////
 
-    // {{ Identification on the UI
     public String title() {
         final TitleBuffer buf = new TitleBuffer();
         buf.append(getDescription());
@@ -112,15 +143,19 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
         }
         return buf.toString();
     }
-    // }}
+    
+    public String iconName() {
+        return "ToDoItem-" + (!isComplete() ? "todo" : "done");
+    }
 
+    // //////////////////////////////////////
+    // Description (property)
+    // //////////////////////////////////////
     
-    // {{ Description
     private String description;
 
-    @RegEx(validation = "${symbol_escape}${symbol_escape}w[@&:${symbol_escape}${symbol_escape}-${symbol_escape}${symbol_escape},${symbol_escape}${symbol_escape}.${symbol_escape}${symbol_escape}+ ${symbol_escape}${symbol_escape}w]*")
-    // words, spaces and selected punctuation
-    @MemberOrder(sequence = "1")
+    @javax.jdo.annotations.Column(allowsNull="false", length=30)
+    @RegEx(validation = "${symbol_escape}${symbol_escape}w[@&:${symbol_escape}${symbol_escape}-${symbol_escape}${symbol_escape},${symbol_escape}${symbol_escape}.${symbol_escape}${symbol_escape}+ ${symbol_escape}${symbol_escape}w]*") 
     public String getDescription() {
         return description;
     }
@@ -128,15 +163,16 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
     public void setDescription(final String description) {
         this.description = description;
     }
-    // }}
 
+    // //////////////////////////////////////
+    // DueBy (property)
+    // //////////////////////////////////////
 
-    // {{ DueBy (property)
     @javax.jdo.annotations.Persistent(defaultFetchGroup="true")
     private LocalDate dueBy;
 
-    @MemberOrder(name="Detail", sequence = "3")
-    @Optional
+    @javax.jdo.annotations.Column(allowsNull="true")
+    @CssClass("x-key")
     public LocalDate getDueBy() {
         return dueBy;
     }
@@ -154,13 +190,71 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
         }
         return isMoreThanOneWeekInPast(dueBy) ? "Due by date cannot be more than one week old" : null;
     }
-    // }}
 
-    
-    // {{ Category
+    // //////////////////////////////////////
+    // Category and Subcategory (property)
+    // //////////////////////////////////////
+
+    public static enum Category {
+        Professional {
+            @Override
+            public List<Subcategory> subcategories() {
+                return Arrays.asList(Subcategory.OpenSource, Subcategory.Consulting, Subcategory.Education);
+            }
+        }, Domestic {
+            @Override
+            public List<Subcategory> subcategories() {
+                return Arrays.asList(Subcategory.Shopping, Subcategory.Housework, Subcategory.Garden, Subcategory.Chores);
+            }
+        }, Other {
+            @Override
+            public List<Subcategory> subcategories() {
+                return Arrays.asList(Subcategory.Other);
+            }
+        };
+        
+        public abstract List<Subcategory> subcategories();
+    }
+
+    public static enum Subcategory {
+        // professional
+        OpenSource, Consulting, Education, Marketing,
+        // domestic
+        Shopping, Housework, Garden, Chores,
+        // other
+        Other;
+
+        public static List<Subcategory> listFor(Category category) {
+            return category != null? category.subcategories(): Collections.<Subcategory>emptyList();
+        }
+
+        static String validate(final Category category, final Subcategory subcategory) {
+            if(category == null) {
+                return "Enter category first";
+            }
+            return !category.subcategories().contains(subcategory) 
+                    ? "Invalid subcategory for category '" + category + "'" 
+                    : null;
+        }
+        
+        public static Predicate<Subcategory> thoseFor(final Category category) {
+            return new Predicate<Subcategory>() {
+
+                @Override
+                public boolean apply(Subcategory subcategory) {
+                    return category.subcategories().contains(subcategory);
+                }
+            };
+        }
+    }
+
+    // //////////////////////////////////////
+
+
     private Category category;
 
-    @MemberOrder(sequence = "2")
+    @javax.jdo.annotations.Column(allowsNull="false")
+    @Disabled(reason="Use action to update both category and subcategory")
     public Category getCategory() {
         return category;
     }
@@ -168,14 +262,29 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
     public void setCategory(final Category category) {
         this.category = category;
     }
-    // }}
+
+    // //////////////////////////////////////
+
+    private Subcategory subcategory;
+
+    @javax.jdo.annotations.Column(allowsNull="false")
+    @Disabled(reason="Use action to update both category and subcategory")
+    public Subcategory getSubcategory() {
+        return subcategory;
+    }
+    public void setSubcategory(final Subcategory subcategory) {
+        this.subcategory = subcategory;
+    }
 
     
-    // {{ OwnedBy (property)
+    // //////////////////////////////////////
+    // OwnedBy (property)
+    // //////////////////////////////////////
+    
     private String ownedBy;
 
+    @javax.jdo.annotations.Column(allowsNull="false")
     @Hidden
-    // not shown in the UI
     public String getOwnedBy() {
         return ownedBy;
     }
@@ -184,14 +293,15 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
         this.ownedBy = ownedBy;
     }
 
-    // }}
 
-    // {{ Complete (property), Done (action), Undo (action)
+    // //////////////////////////////////////
+    // Complete (property), 
+    // Done (action), Undo (action)
+    // //////////////////////////////////////
+
     private boolean complete;
 
     @Disabled
-    // cannot be edited as a property
-    @MemberOrder(sequence = "4")
     public boolean isComplete() {
         return complete;
     }
@@ -200,69 +310,87 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
         this.complete = complete;
     }
 
-
     @Named("Done")
     @PublishedAction
     @Bulk
-    @MemberOrder(name="complete", sequence = "1")
+    @CssClass("x-highlight")
     public ToDoItem completed() {
         setComplete(true);
+        
+        // demonstrating the use of ... 
+        final InteractionContext ctxt = InteractionContext.current.get();
+        @SuppressWarnings("unused")
+        List<Object> allObjects = ctxt.getDomainObjects();
+        
+        LOG.debug("completed: "
+                + ctxt.getIndex() +
+                " [" + ctxt.getSize() + "]"
+                + (ctxt.isFirst() ? " (first)" : "")
+                + (ctxt.isLast() ? " (last)" : ""));
+
         return this;
     }
     // disable action dependent on state of object
     public String disableCompleted() {
-        return complete ? "Already completed" : null;
+        return isComplete() ? "Already completed" : null;
     }
 
-
-    @Named("Undo")
+    @Named("Not done")
     @PublishedAction
-    @MemberOrder(name="complete", sequence = "2")
+    @Bulk
     public ToDoItem notYetCompleted() {
         setComplete(false);
+
         return this;
     }
     // disable action dependent on state of object
     public String disableNotYetCompleted() {
         return !complete ? "Not yet completed" : null;
     }
-    // }}
 
+    // //////////////////////////////////////
+    // Cost (property), UpdateCost (action)
+    // //////////////////////////////////////
 
-    // {{ Cost (property), updateCost (action)
     private BigDecimal cost;
 
-    @Column(scale = 2)
-    @Optional
-    @MemberOrder(sequence = "4.1")
+    @javax.jdo.annotations.Column(allowsNull="true", scale=2)
+    @Disabled(reason="Update using action")
     public BigDecimal getCost() {
         return cost;
     }
 
     public void setCost(final BigDecimal cost) {
-        this.cost = cost;
+        this.cost = cost!=null?cost.setScale(2):null;
     }
     
     @Named("Update")
-    @MemberOrder(name="cost", sequence = "1")
-    public ToDoItem updateCost(@Named("New cost") final BigDecimal cost) {
+    public ToDoItem updateCost(@Named("New cost") @Optional final BigDecimal cost) {
+        LOG.debug("%s: cost updated: %s -> %s", this.container.titleOf(this), getCost(), cost);
         setCost(cost);
         return this;
     }
-    // provide a default value
+
+    // provide a default value for argument ${symbol_pound}0
     public BigDecimal default0UpdateCost() {
         return getCost();
     }
-    // }}
+    
+    // validate action arguments
+    public String validateUpdateCost(final BigDecimal proposedCost) {
+        if(proposedCost == null) { return null; }
+        return proposedCost.compareTo(BigDecimal.ZERO) < 0? "Cost must be positive": null;
+    }
 
+    // //////////////////////////////////////
+    // Notes (property)
+    // //////////////////////////////////////
 
-    // {{ Notes (property)
     private String notes;
 
+    @javax.jdo.annotations.Column(allowsNull="true", length=400)
     @Hidden(where=Where.ALL_TABLES)
-    @Optional
     @MultiLine(numberOfLines=5)
-    @MemberOrder(name="Detail", sequence = "6")
     public String getNotes() {
         return notes;
     }
@@ -270,15 +398,15 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
     public void setNotes(final String notes) {
         this.notes = notes;
     }
-    // }}
 
+    // //////////////////////////////////////
+    // Attachment (property)
+    // //////////////////////////////////////
 
-    // {{ Attachment (property)
     private Blob attachment;
 
     @javax.jdo.annotations.Persistent(defaultFetchGroup="false")
-    @Optional
-    @MemberOrder(name="Detail", sequence = "7")
+    @javax.jdo.annotations.Column(allowsNull="true")
     @Hidden(where=Where.STANDALONE_TABLES)
     public Blob getAttachment() {
         return attachment;
@@ -287,15 +415,13 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
     public void setAttachment(final Blob attachment) {
         this.attachment = attachment;
     }
-    // }}
-
-
 
+    // //////////////////////////////////////
+    // Version (derived property)
+    // //////////////////////////////////////
 
-    // {{ Version (derived property)
     @Hidden(where=Where.ALL_TABLES)
     @Disabled
-    @MemberOrder(name="Detail", sequence = "99")
     @Named("Version")
     public Long getVersionSequence() {
         if(!(this instanceof PersistenceCapable)) {
@@ -309,17 +435,36 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
     public boolean hideVersionSequence() {
         return !(this instanceof PersistenceCapable);
     }
-    // }}
 
+    // //////////////////////////////////////
+    // Dependencies (collection), 
+    // Add (action), Remove (action)
+    // //////////////////////////////////////
+
+    // overrides the natural ordering
+    public static class DependenciesComparator implements Comparator<ToDoItem> {
+        @Override
+        public int compare(ToDoItem p, ToDoItem q) {
+            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);
+        }
+    }
+
+    
 
-    // {{ dependencies (Collection)
-    @javax.jdo.annotations.Persistent(table="TODO_DEPENDENCIES")
-    @javax.jdo.annotations.Join(column="DEPENDING_TODO_ID")
-    @javax.jdo.annotations.Element(column="DEPENDENT_TODO_ID")
+    @javax.jdo.annotations.Persistent(table="ToDoItemDependencies")
+    @javax.jdo.annotations.Join(column="dependingId")
+    @javax.jdo.annotations.Element(column="dependentId")
     private SortedSet<ToDoItem> dependencies = new TreeSet<ToDoItem>();
 
+    @SortedBy(DependenciesComparator.class)
     @Disabled
-    @MemberOrder(sequence = "1")
     @Render(Type.EAGERLY)
     public SortedSet<ToDoItem> getDependencies() {
         return dependencies;
@@ -328,15 +473,19 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
     public void setDependencies(final SortedSet<ToDoItem> dependencies) {
         this.dependencies = dependencies;
     }
-    // }}
 
-    // {{ add (action)
     @PublishedAction
-    @MemberOrder(name="dependencies", sequence = "3")
     public ToDoItem add(final ToDoItem toDoItem) {
         getDependencies().add(toDoItem);
         return this;
     }
+    public List<ToDoItem> autoComplete0Add(final @MinLength(2) String search) {
+        final List<ToDoItem> list = toDoItems.autoComplete(search);
+        list.removeAll(getDependencies());
+        list.remove(this);
+        return list;
+    }
+
     public String disableAdd(final ToDoItem toDoItem) {
         if(isComplete()) {
             return "Cannot add dependencies for items that are complete";
@@ -353,10 +502,8 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
         }
         return null;
     }
-    // }}
 
-    // {{ remove (action)
-    @MemberOrder(name="dependencies", sequence = "4")
+    @CssClass("x-caution")
     public ToDoItem remove(final ToDoItem toDoItem) {
         getDependencies().remove(toDoItem);
         return this;
@@ -376,16 +523,17 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
         return null;
     }
     // provide a drop-down
-    public List<ToDoItem> choices0Remove() {
-        return Lists.newArrayList(getDependencies());
+    public Collection<ToDoItem> choices0Remove() {
+        return getDependencies();
     }
-    // }}
+    
 
+    // //////////////////////////////////////
+    // Clone (action)
+    // //////////////////////////////////////
 
-    // {{ clone (action)
     @Named("Clone")
     // the name of the action in the UI
-    @MemberOrder(sequence = "3")
     // nb: method is not called "clone()" is inherited by java.lang.Object and
     // (a) has different semantics and (b) is in any case automatically ignored
     // by the framework
@@ -394,13 +542,15 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
             String description,
             @Named("Category")
             ToDoItem.Category category, 
+            @Named("Subcategory")
+            ToDoItem.Subcategory subcategory, 
             @Named("Due by") 
             @Optional
             LocalDate dueBy,
             @Named("Cost") 
             @Optional
             BigDecimal cost) {
-        return toDoItems.newToDo(description, category, dueBy, cost);
+        return toDoItems.newToDo(description, category, subcategory, dueBy, cost);
     }
     public String default0Duplicate() {
         return getDescription() + " - Copy";
@@ -408,25 +558,32 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
     public Category default1Duplicate() {
         return getCategory();
     }
-    public LocalDate default2Duplicate() {
+    public Subcategory default2Duplicate() {
+        return getSubcategory();
+    }
+    public LocalDate default3Duplicate() {
         return getDueBy();
     }
-    // }}
 
-    
-    // {{ delete (action)
+    // //////////////////////////////////////
+    // Delete (action)
+    // //////////////////////////////////////
+
     @Bulk
-    @MemberOrder(sequence = "4")
+    @CssClass("x-caution")
     public List<ToDoItem> delete() {
         container.removeIfNotAlready(this);
         container.informUser("Deleted " + container.titleOf(this));
         // invalid to return 'this' (cannot render a deleted object)
         return toDoItems.notYetComplete(); 
     }
-    // }}
 
+    // //////////////////////////////////////
+    // Programmatic Helpers
+    // //////////////////////////////////////
+
+    private static final long ONE_WEEK_IN_MILLIS = 7 * 24 * 60 * 60 * 1000L;
 
-    // {{ isDue (programmatic)
     @Programmatic // excluded from the framework's metamodel
     public boolean isDue() {
         if (getDueBy() == null) {
@@ -435,119 +592,140 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
         return !isMoreThanOneWeekInPast(getDueBy());
     }
 
-    // }}
-
-
-    // {{ SimilarItems (derived collection)
-    @MemberOrder(sequence = "5")
-    @NotPersisted
-    @Render(Type.LAZILY)
-    public List<ToDoItem> getSimilarItems() {
-        return toDoItems.similarTo(this);
+    private static boolean isMoreThanOneWeekInPast(final LocalDate dueBy) {
+        return dueBy.toDateTimeAtStartOfDay().getMillis() < Clock.getTime() - ONE_WEEK_IN_MILLIS;
     }
 
-    // }}
-
+    // //////////////////////////////////////
+    // Predicates
+    // //////////////////////////////////////
 
-
-    // {{ compareTo (programmatic)
-    /**
-     * by complete flag, then due by date, then description.
-     * 
-     * <p>
-     * Required because {@link ${symbol_pound}getDependencies()} is of type {@link SortedSet}. 
-     */
-    @Override
-    public int compareTo(final ToDoItem other) {
-        if (isComplete() && !other.isComplete()) {
-            return +1;
+    public static class Predicates {
+        
+        public static Predicate<ToDoItem> thoseOwnedBy(final String currentUser) {
+            return new Predicate<ToDoItem>() {
+                @Override
+                public boolean apply(final ToDoItem toDoItem) {
+                    return Objects.equal(toDoItem.getOwnedBy(), currentUser);
+                }
+            };
         }
-        if (!isComplete() && other.isComplete()) {
-            return -1;
+
+        public static Predicate<ToDoItem> thoseNotYetComplete() {
+            return com.google.common.base.Predicates.not(thoseComplete());
         }
-        if (getDueBy() == null && other.getDueBy() != null) {
-            return +1;
+
+        public static Predicate<ToDoItem> thoseComplete() {
+            return new Predicate<ToDoItem>() {
+                @Override
+                public boolean apply(final ToDoItem t) {
+                    return t.isComplete();
+                }
+            };
         }
-        if (getDueBy() != null && other.getDueBy() == null) {
-            return -1;
+
+        public static Predicate<ToDoItem> thoseWithSimilarDescription(final String description) {
+            return new Predicate<ToDoItem>() {
+                @Override
+                public boolean apply(final ToDoItem t) {
+                    return t.getDescription().contains(description);
+                }
+            };
         }
-        if (getDueBy() == null && other.getDueBy() == null || getDueBy().equals(this.getDueBy())) {
-            return getDescription().compareTo(other.getDescription());
+
+        @SuppressWarnings("unchecked")
+        public static Predicate<ToDoItem> thoseSimilarTo(final ToDoItem toDoItem) {
+            return com.google.common.base.Predicates.and(
+                    thoseNot(toDoItem),
+                    thoseOwnedBy(toDoItem.getOwnedBy()),
+                    thoseCategorised(toDoItem.getCategory()));
         }
-        return getDueBy().compareTo(getDueBy());
-    }
-    // }}
 
-    // {{ helpers
-    private static boolean isMoreThanOneWeekInPast(final LocalDate dueBy) {
-        return dueBy.toDateTimeAtStartOfDay().getMillis() < Clock.getTime() - ONE_WEEK_IN_MILLIS;
-    }
+        public static Predicate<ToDoItem> thoseNot(final ToDoItem toDoItem) {
+            return new Predicate<ToDoItem>() {
+                @Override
+                public boolean apply(final ToDoItem t) {
+                    return t != toDoItem;
+                }
+            };
+        }
 
-    // }}
+        public static Predicate<ToDoItem> thoseCategorised(final Category category) {
+            return new Predicate<ToDoItem>() {
+                @Override
+                public boolean apply(final ToDoItem toDoItem) {
+                    return Objects.equal(toDoItem.getCategory(), category);
+                }
+            };
+        }
 
-    // {{ filters (programmatic)
-    @SuppressWarnings("unchecked")
-    public static Filter<ToDoItem> thoseDue() {
-        return Filters.and(Filters.not(thoseComplete()), new Filter<ToDoItem>() {
-            @Override
-            public boolean accept(final ToDoItem t) {
-                return t.isDue();
-            }
-        });
-    }
+        public static Predicate<ToDoItem> thoseSubcategorised(
+                final Subcategory subcategory) {
+            return new Predicate<ToDoItem>() {
+                @Override
+                public boolean apply(final ToDoItem t) {
+                    return Objects.equal(t.getSubcategory(), subcategory);
+                }
+            };
+        }
 
-    public static Filter<ToDoItem> thoseComplete() {
-        return new Filter<ToDoItem>() {
-            @Override
-            public boolean accept(final ToDoItem t) {
-                return t.isComplete();
-            }
-        };
+        public static Predicate<ToDoItem> thoseCategorised(
+                final Category category, final Subcategory subcategory) {
+            return com.google.common.base.Predicates.and(
+                    thoseCategorised(category), 
+                    thoseSubcategorised(subcategory)); 
+        }
     }
+    
+    // //////////////////////////////////////
+    // toString
+    // //////////////////////////////////////
 
-    public static Filter<ToDoItem> thoseOwnedBy(final String currentUser) {
-        return new Filter<ToDoItem>() {
-            @Override
-            public boolean accept(final ToDoItem toDoItem) {
-                return Objects.equal(toDoItem.getOwnedBy(), currentUser);
-            }
-
-        };
+    @Override
+    public String toString() {
+        return ObjectContracts.toString(this, "description,complete,dueBy,ownedBy");
     }
+        
+    // //////////////////////////////////////
+    // compareTo
+    // //////////////////////////////////////
 
-    public static Filter<ToDoItem> thoseSimilarTo(final ToDoItem toDoItem) {
-        return new Filter<ToDoItem>() {
-            @Override
-            public boolean accept(final ToDoItem eachToDoItem) {
-                return Objects.equal(toDoItem.getCategory(), eachToDoItem.getCategory()) && 
-                       Objects.equal(toDoItem.getOwnedBy(), eachToDoItem.getOwnedBy()) &&
-                       eachToDoItem != toDoItem;
-            }
-
-        };
+    /**
+     * Required so can store in {@link SortedSet sorted set}s (eg {@link ${symbol_pound}getDependencies()}). 
+     */
+    @Override
+    public int compareTo(final ToDoItem other) {
+        return ObjectContracts.compare(this, other, "complete,dueBy,description");
     }
-    // }}
 
-    
+    // //////////////////////////////////////
+    // Injected Services
+    // //////////////////////////////////////
 
-    // {{ injected: DomainObjectContainer
     private DomainObjectContainer container;
 
     public void injectDomainObjectContainer(final DomainObjectContainer container) {
         this.container = container;
     }
-    // }}
 
-    // {{ injected: ToDoItems
     private ToDoItems toDoItems;
 
     public void injectToDoItems(final ToDoItems toDoItems) {
         this.toDoItems = toDoItems;
     }
-    // }}
 
-// GMAP3: uncomment to use https://github.com/danhaywood/isis-wicket-gmap3    
-//    // {{
+    private ClockService clockService;
+    public void injectClockService(ClockService clockService) {
+        this.clockService = clockService;
+    }
+    
+    // //////////////////////////////////////
+    // Extensions
+    // //////////////////////////////////////
+
+    
+// GMAP3: uncomment to use https://github.com/danhaywood/isis-wicket-gmap3
+//
 //    @Persistent
 //    private Location location;
 //    
@@ -559,14 +737,5 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
 //    public void setLocation(Location location) {
 //        this.location = location;
 //    }
-//    // }}
-
 
-    
-    public ToDoItem updateDueBy(
-            //@RenderedAdjusted
-            LocalDate dueBy) {
-        setDueBy(dueBy);
-        return this;
-    }
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.layout.json
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.layout.json b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.layout.json
new file mode 100644
index 0000000..fa63299
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.layout.json
@@ -0,0 +1,92 @@
+/**
+ *  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.
+ */
+{
+    columns: [
+    {
+        span: 6,
+        memberGroups: {
+            General: {
+                members: {
+                    description: {},
+                    category: {
+                    },
+                    subcategory: {
+                        actions: {
+                            updateCategory: {},
+                            analyseCategory: {}
+                        }
+                    },
+                    complete: {
+                        actions: {
+                            completed: {},
+                            notYetCompleted: {}
+                        }
+                    }
+                }
+            },
+            Misc: {
+                members: {
+                    versionSequence: {}
+                }
+            }
+        }
+    },
+    {
+        span: 6,
+        memberGroups: {
+            Detail: {
+                members: {
+                    priority: {
+                        actions: {
+                            previous: {},
+                            next: {}
+                        }
+                    },
+                    dueBy: {},
+                    cost: {
+                        actions: {
+                            updateCost:{}
+                        }
+                    },
+                    notes: {},
+                    attachment: {}
+                }
+            }
+        }
+    },
+    {
+        span: 0
+    },
+    {
+        span: 6,
+        collections: {
+            dependencies: {
+                actions: {
+                    add:{},
+                    remove: {}
+                }
+            },
+            similarTo: {}
+        }
+    }
+    ],
+    actions: {
+        duplicate: {},
+        delete: {}
+    }
+}
+ 
\ No newline at end of file