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:48 UTC

[4/7] ISIS-437: updating quickstart archetype

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/ToDoItemChangedPayloadFactory.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemChangedPayloadFactory.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemChangedPayloadFactory.java
index f3bd7b1..7c03f19 100644
--- a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemChangedPayloadFactory.java
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemChangedPayloadFactory.java
@@ -34,6 +34,10 @@ public class ToDoItemChangedPayloadFactory implements PayloadFactory{
             super(changed);
         }
         
+        /**
+         * Expose the item's {@link ToDoItem${symbol_pound}getDescription() description} more explicitly
+         * in the payload.
+         */
         public String getDescription() {
             return getChanged().getDescription();
         }

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/ToDoItemContributions.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemContributions.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemContributions.java
new file mode 100644
index 0000000..ef54ed8
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemContributions.java
@@ -0,0 +1,218 @@
+#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 dom.todo;
+
+import java.util.List;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
+
+import dom.todo.ToDoItem.Category;
+import dom.todo.ToDoItem.Subcategory;
+
+import org.joda.time.LocalDate;
+
+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.DescribedAs;
+import org.apache.isis.applib.annotation.Disabled;
+import org.apache.isis.applib.annotation.Hidden;
+import org.apache.isis.applib.annotation.Named;
+import org.apache.isis.applib.annotation.NotContributed;
+import org.apache.isis.applib.annotation.NotContributed.As;
+import org.apache.isis.applib.annotation.NotInServiceMenu;
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.applib.query.QueryDefault;
+
+public class ToDoItemContributions extends AbstractFactoryAndRepository {
+
+    
+    // //////////////////////////////////////
+    // priority (contributed property)
+    // //////////////////////////////////////
+    
+    @DescribedAs("The relative priority of this item compared to others not yet complete (using 'due by' date)")
+    @NotInServiceMenu
+    @ActionSemantics(Of.SAFE)
+    @NotContributed(As.ACTION)
+    @Hidden(where=Where.ALL_TABLES)
+    @Disabled(reason="Relative priority, derived from due date")
+    public Integer priority(final ToDoItem toDoItem) {
+        if(toDoItem.isComplete()) {
+            return null;
+        }
+
+        // sort items, then locate this one
+        int i=1;
+        for (ToDoItem each : sortedNotYetComplete()) {
+            if(each == toDoItem) {
+                return i;
+            }
+            i++;
+        }
+        return null;
+    }
+
+
+    private List<ToDoItem> sortedNotYetComplete() {
+        return ORDERING_DUE_BY
+        .compound(ORDERING_DESCRIPTION)
+        .sortedCopy(toDoItems.notYetComplete());
+    }
+
+    private static Ordering<ToDoItem> ORDERING_DUE_BY = 
+        Ordering.natural().nullsLast().onResultOf(new Function<ToDoItem, LocalDate>(){
+            @Override
+            public LocalDate apply(ToDoItem input) {
+                return input.getDueBy();
+            }
+        });
+    
+    private static Ordering<ToDoItem> ORDERING_DESCRIPTION = 
+        Ordering.natural().nullsLast().onResultOf(new Function<ToDoItem, String>(){
+            @Override
+            public String apply(ToDoItem input) {
+                return input.getDescription();
+            }
+        });
+
+
+    // //////////////////////////////////////
+    // Next, Previous (contributed actions)
+    // //////////////////////////////////////
+
+    @DescribedAs("The next item not yet completed")
+    @NotInServiceMenu
+    @ActionSemantics(Of.SAFE)
+    @NotContributed(As.ASSOCIATION)
+    public ToDoItem next(final ToDoItem item) {
+        final Integer priority = priority(item);
+        int priorityOfNext = priority != null ? priority + 1 : 0;
+        return itemWithPriorityElse(priorityOfNext, item);
+    }
+    
+    @DescribedAs("The previous item not yet completed")
+    @NotInServiceMenu
+    @ActionSemantics(Of.SAFE)
+    @NotContributed(As.ASSOCIATION)
+    public ToDoItem previous(final ToDoItem item) {
+        final Integer priority = priority(item);
+        int priorityOfPrevious = priority != null? priority - 1 : 0;
+        return itemWithPriorityElse(priorityOfPrevious, item);
+    }
+
+
+    private ToDoItem itemWithPriorityElse(int idx, final ToDoItem itemElse) {
+        final List<ToDoItem> items = sortedNotYetComplete();
+        return idx>=0 && items.size()>=idx? items.get(idx-1): itemElse;
+    }
+
+    
+    // //////////////////////////////////////
+    // SimilarTo (contributed collection)
+    // //////////////////////////////////////
+    
+    @NotInServiceMenu
+    @ActionSemantics(Of.SAFE)
+    @NotContributed(As.ACTION)
+    public List<ToDoItem> similarTo(final ToDoItem toDoItem) {
+        if(false) {
+            // the naive implementation ...
+            return allMatches(ToDoItem.class, ToDoItem.Predicates.thoseSimilarTo(toDoItem));
+        } else {
+            // the JDO implementation ...
+            final List<ToDoItem> similarToDoItems = allMatches(
+                    new QueryDefault<ToDoItem>(ToDoItem.class, 
+                            "todo_similarTo", 
+                            "ownedBy", currentUserName(), 
+                            "category", toDoItem.getCategory()));
+            return Lists.newArrayList(Iterables.filter(similarToDoItems, excluding(toDoItem)));
+        }
+    }
+
+
+    private static Predicate<ToDoItem> excluding(final ToDoItem toDoItem) {
+        return new Predicate<ToDoItem>() {
+            @Override
+            public boolean apply(ToDoItem input) {
+                return input != toDoItem;
+            }
+        };
+    }
+
+    
+    // //////////////////////////////////////
+    // UpdateCategory (contributed action)
+    // //////////////////////////////////////
+
+    @Named("Update")
+    @DescribedAs("Update category and subcategory")
+    @NotInServiceMenu
+    @ActionSemantics(Of.IDEMPOTENT)
+    public ToDoItem updateCategory(
+            final ToDoItem item, 
+            final @Named("Category") Category category,
+            final @Named("Subcategory") Subcategory subcategory) {
+        item.setCategory(category);
+        item.setSubcategory(subcategory);
+        return item;
+    }
+
+    public Category default1UpdateCategory(
+            final ToDoItem item) {
+        return item.getCategory();
+    }
+    public Subcategory default2UpdateCategory(
+            final ToDoItem item) {
+        return item.getSubcategory();
+    }
+
+    public List<Subcategory> choices2UpdateCategory(
+            final ToDoItem item, final Category category) {
+        return Subcategory.listFor(category);
+    }
+    
+    public String validateUpdateCategory(
+            final ToDoItem item, final Category category, final Subcategory subcategory) {
+        return Subcategory.validate(category, subcategory);
+    }
+
+    
+    // //////////////////////////////////////
+    // helpers
+    // //////////////////////////////////////
+    
+    protected String currentUserName() {
+        return getContainer().getUser().getName();
+    }
+
+    // //////////////////////////////////////
+
+    private ToDoItems toDoItems;
+    public void injectToDoItems(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/dom/todo/ToDoItems.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItems.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItems.java
index 4ece800..a1b17ab 100644
--- a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItems.java
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItems.java
@@ -25,30 +25,34 @@ import java.math.BigDecimal;
 import java.util.Collections;
 import java.util.List;
 
-import com.google.common.base.Objects;
+import com.google.common.base.Predicates;
 
 import dom.todo.ToDoItem.Category;
+import dom.todo.ToDoItem.Subcategory;
 
 import org.joda.time.LocalDate;
 
-import org.apache.isis.applib.AbstractFactoryAndRepository;
+import org.apache.isis.applib.DomainObjectContainer;
 import org.apache.isis.applib.annotation.ActionSemantics;
 import org.apache.isis.applib.annotation.ActionSemantics.Of;
-import org.apache.isis.applib.annotation.Hidden;
+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.NotInServiceMenu;
 import org.apache.isis.applib.annotation.Optional;
 import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.annotation.RegEx;
 import org.apache.isis.applib.clock.Clock;
-import org.apache.isis.applib.filter.Filter;
+import org.apache.isis.applib.query.QueryDefault;
+
+import services.ClockService;
 
 @Named("ToDos")
-public class ToDoItems extends AbstractFactoryAndRepository {
+public class ToDoItems {
+
+    // //////////////////////////////////////
+    // Identification in the UI
+    // //////////////////////////////////////
 
-    // {{ Id, iconName
-    @Override
     public String getId() {
         return "toDoItems";
     }
@@ -56,103 +60,164 @@ public class ToDoItems extends AbstractFactoryAndRepository {
     public String iconName() {
         return "ToDoItem";
     }
-    // }}
 
-    // {{ notYetComplete (action)
+    // //////////////////////////////////////
+    // NotYetComplete (action)
+    // //////////////////////////////////////
+    
+    @Bookmarkable
     @ActionSemantics(Of.SAFE)
     @MemberOrder(sequence = "1")
     public List<ToDoItem> notYetComplete() {
-        List<ToDoItem> items = doNotYetComplete();
+        final List<ToDoItem> items = notYetCompleteNoUi();
         if(items.isEmpty()) {
-            getContainer().informUser("All to-do items have been completed :-)");
+            container.informUser("All to-do items have been completed :-)");
         }
         return items;
     }
 
-    protected List<ToDoItem> doNotYetComplete() {
-        return allMatches(ToDoItem.class, new Filter<ToDoItem>() {
-            @Override
-            public boolean accept(final ToDoItem t) {
-                return ownedByCurrentUser(t) && !t.isComplete();
-            }
-        });
+    @Programmatic
+    public List<ToDoItem> notYetCompleteNoUi() {
+        final List<ToDoItem> items;
+        if(false) {
+            // the naive implementation ...
+            items = container.allMatches(ToDoItem.class, 
+                    Predicates.and(
+                        ToDoItem.Predicates.thoseOwnedBy(currentUserName()), 
+                        ToDoItem.Predicates.thoseNotYetComplete()));
+        } else {
+            // the JDO implementation ...
+            items = container.allMatches(
+                    new QueryDefault<ToDoItem>(ToDoItem.class, 
+                            "todo_notYetComplete", 
+                            "ownedBy", currentUserName()));
+        }
+        return items;
     }
-    // }}
 
-    // {{ complete (action)
+    
+    // //////////////////////////////////////
+    // Complete (action)
+    // //////////////////////////////////////
+    
     @ActionSemantics(Of.SAFE)
     @MemberOrder(sequence = "2")
     public List<ToDoItem> complete() {
-        List<ToDoItem> items = doComplete();
+        final List<ToDoItem> items = completeNoUi();
         if(items.isEmpty()) {
-            getContainer().informUser("No to-do items have yet been completed :-(");
+            container.informUser("No to-do items have yet been completed :-(");
         }
         return items;
     }
 
-    protected List<ToDoItem> doComplete() {
-        return allMatches(ToDoItem.class, new Filter<ToDoItem>() {
-            @Override
-            public boolean accept(final ToDoItem t) {
-                return ownedByCurrentUser(t) && t.isComplete();
-            }
-        });
+    @Programmatic
+    public List<ToDoItem> completeNoUi() {
+        final List<ToDoItem> items;
+        if(false) {
+            // the naive implementation ...
+            items = container.allMatches(ToDoItem.class, 
+                    Predicates.and(
+                        ToDoItem.Predicates.thoseOwnedBy(currentUserName()), 
+                        ToDoItem.Predicates.thoseComplete()));
+        } else {
+            // the JDO implementation ...
+            items = container.allMatches(
+                    new QueryDefault<ToDoItem>(ToDoItem.class, 
+                            "todo_complete", 
+                            "ownedBy", currentUserName()));
+        }
+        return items;
     }
-    // }}
 
-    
-    // {{ newToDo  (action)
+
+    // //////////////////////////////////////
+    // NewToDo (action)
+    // //////////////////////////////////////
+
     @MemberOrder(sequence = "3")
     public ToDoItem newToDo(
-            @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
-            @Named("Description") String description, 
-            @Named("Category") Category category,
-            @Optional
-            @Named("Due by") LocalDate dueBy,
-            @Optional
-            @Named("Cost") BigDecimal cost) {
+            final @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]*") @Named("Description") String description, 
+            final @Named("Category") Category category,
+            final @Named("Subcategory") Subcategory subcategory,
+            final @Optional @Named("Due by") LocalDate dueBy,
+            final @Optional @Named("Cost") BigDecimal cost) {
         final String ownedBy = currentUserName();
-        return newToDo(description, category, ownedBy, dueBy, cost);
+        return newToDo(description, category, subcategory, ownedBy, dueBy, cost);
+    }
+    public Category default1NewToDo() {
+        return Category.Professional;
+    }
+    public Subcategory default2NewToDo() {
+        return Category.Professional.subcategories().get(0);
+    }
+    public LocalDate default3NewToDo() {
+        return clockService.now().plusDays(14);
+    }
+    public List<Subcategory> choices2NewToDo(
+            final String description, final Category category) {
+        return Subcategory.listFor(category);
     }
-    public LocalDate default2NewToDo() {
-        return new LocalDate(Clock.getTime()).plusDays(14);
+    public String validateNewToDo(
+            final String description, 
+            final Category category, final Subcategory subcategory, 
+            final LocalDate dueBy, final BigDecimal cost) {
+        return Subcategory.validate(category, subcategory);
     }
-    // }}
 
+    // //////////////////////////////////////
+    // AllToDos (action)
+    // //////////////////////////////////////
 
-    // {{ allToDos (action)
     @ActionSemantics(Of.SAFE)
     @MemberOrder(sequence = "4")
     public List<ToDoItem> allToDos() {
-        return allToDos(NotifyUserIfNone.YES);
-    }
-
-    public enum NotifyUserIfNone { YES, NO }
-    
-    @Programmatic
-    public List<ToDoItem> allToDos(NotifyUserIfNone notifyUser) {
         final String currentUser = currentUserName();
-        final List<ToDoItem> items = allMatches(ToDoItem.class, ToDoItem.thoseOwnedBy(currentUser));
+        final List<ToDoItem> items = container.allMatches(ToDoItem.class, ToDoItem.Predicates.thoseOwnedBy(currentUser));
         Collections.sort(items);
-        if(notifyUser == NotifyUserIfNone.YES && items.isEmpty()) {
-            getContainer().warnUser("No to-do items found.");
+        if(items.isEmpty()) {
+            container.warnUser("No to-do items found.");
         }
         return items;
     }
-    // }}
 
+    // //////////////////////////////////////
+    // AutoComplete
+    // //////////////////////////////////////
+
+    @Programmatic // not part of metamodel
+    public List<ToDoItem> autoComplete(final String description) {
+        if(false) {
+            // the naive implementation ...
+            return container.allMatches(ToDoItem.class, 
+                    Predicates.and(
+                        ToDoItem.Predicates.thoseOwnedBy(currentUserName()), 
+                        ToDoItem.Predicates.thoseWithSimilarDescription(description)));
+        } else {
+            // the JDO implementation ...
+            return container.allMatches(
+                    new QueryDefault<ToDoItem>(ToDoItem.class, 
+                            "todo_autoComplete", 
+                            "ownedBy", currentUserName(), 
+                            "description", description));
+        }
+    }
+
+
+    // //////////////////////////////////////
+    // Programmatic Helpers
+    // //////////////////////////////////////
 
-    // {{ newToDo  (hidden)
-    @Hidden // for use by fixtures
+    @Programmatic // for use by fixtures
     public ToDoItem newToDo(
             final String description, 
             final Category category, 
-            final String userName,
-            final LocalDate dueBy, 
-            final BigDecimal cost) {
-        final ToDoItem toDoItem = newTransientInstance(ToDoItem.class);
+            final Subcategory subcategory,
+            final String userName, 
+            final LocalDate dueBy, final BigDecimal cost) {
+        final ToDoItem toDoItem = container.newTransientInstance(ToDoItem.class);
         toDoItem.setDescription(description);
         toDoItem.setCategory(category);
+        toDoItem.setSubcategory(subcategory);
         toDoItem.setOwnedBy(userName);
         toDoItem.setDueBy(dueBy);
         toDoItem.setCost(cost);
@@ -163,53 +228,34 @@ public class ToDoItems extends AbstractFactoryAndRepository {
         //    new Location(51.5172+random(-0.05, +0.05), 0.1182 + random(-0.05, +0.05)));
         //
         
-        persist(toDoItem);
+        container.persist(toDoItem);
         return toDoItem;
     }
     
     private static double random(double from, double to) {
         return Math.random() * (to-from) + from;
     }
-    // }}
 
+    private String currentUserName() {
+        return container.getUser().getName();
+    }
 
     
-    // {{ similarTo (action)
-    @NotInServiceMenu
-    @ActionSemantics(Of.SAFE)
-    @MemberOrder(sequence = "5")
-    public List<ToDoItem> similarTo(final ToDoItem toDoItem) {
-        return allMatches(ToDoItem.class, new Filter<ToDoItem>() {
-            @Override
-            public boolean accept(ToDoItem t) {
-                return t != toDoItem && Objects.equal(toDoItem.getCategory(), t.getCategory()) && Objects.equal(toDoItem.getOwnedBy(), t.getOwnedBy());
-            }
-        });
-    }
-    // }}
-    
+    // //////////////////////////////////////
+    // Injected Services
+    // //////////////////////////////////////
+
     
-    // {{ autoComplete (hidden)
-    @Hidden
-    public List<ToDoItem> autoComplete(final String description) {
-        return allMatches(ToDoItem.class, new Filter<ToDoItem>() {
-            @Override
-            public boolean accept(final ToDoItem t) {
-                return ownedByCurrentUser(t) && t.getDescription().contains(description);
-            }
+    private DomainObjectContainer container;
 
-        });
+    public void injectDomainObjectContainer(final DomainObjectContainer container) {
+        this.container = container;
     }
-    // }}
 
-    // {{ helpers
-    protected boolean ownedByCurrentUser(final ToDoItem t) {
-        return Objects.equal(t.getOwnedBy(), currentUserName());
-    }
-    protected String currentUserName() {
-        return getContainer().getUser().getName();
+    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/services/ClockService.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/services/ClockService.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/services/ClockService.java
new file mode 100644
index 0000000..6311d76
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/java/services/ClockService.java
@@ -0,0 +1,36 @@
+#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 services;
+
+import org.joda.time.LocalDate;
+
+import org.apache.isis.applib.annotation.Hidden;
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.clock.Clock;
+
+@Hidden
+public class ClockService {
+    
+    @Programmatic
+    public LocalDate now() {
+        return Clock.getTimeAsLocalDate();
+    }
+
+}

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/resources/images/Dashboard.png
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/resources/images/Dashboard.png b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/resources/images/Dashboard.png
new file mode 100644
index 0000000..66cb925
Binary files /dev/null and b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/resources/images/Dashboard.png differ

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/resources/images/ToDoItem-done.png
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem-done.png b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem-done.png
new file mode 100644
index 0000000..e71398f
Binary files /dev/null and b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem-done.png differ

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/resources/images/ToDoItem-todo.png
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem-todo.png b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem-todo.png
new file mode 100644
index 0000000..a2c5c0f
Binary files /dev/null and b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem-todo.png differ

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/resources/images/ToDoItem.gif
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem.gif b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem.gif
deleted file mode 100644
index cc536e1..0000000
Binary files a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem.gif and /dev/null differ

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/resources/images/ToDoItem.png
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem.png b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem.png
new file mode 100644
index 0000000..11586b9
Binary files /dev/null and b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem.png differ

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/test/java/dom/todo/ToDoTest_completed.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/test/java/dom/todo/ToDoTest_completed.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/test/java/dom/todo/ToDoTest_completed.java
new file mode 100644
index 0000000..e0ef805
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/test/java/dom/todo/ToDoTest_completed.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 dom.todo;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.isis.applib.annotation.Bulk;
+
+public class ToDoTest_completed {
+
+    private ToDoItem toDoItem;
+
+    @Before
+    public void setUp() throws Exception {
+        toDoItem = new ToDoItem();
+        toDoItem.setComplete(false);
+    }
+    
+    @Test
+    public void happyCase() throws Exception {
+        // given
+        assertThat(toDoItem.disableCompleted(), is(nullValue()));
+        
+        // when
+        Bulk.InteractionContext.with(new Runnable() {
+            @Override
+            public void run() {
+                toDoItem.completed();
+            }
+        }, toDoItem);
+        
+        // then
+        assertThat(toDoItem.isComplete(), is(true));
+        assertThat(toDoItem.disableCompleted(), is(not(nullValue())));
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/test/java/dom/todo/ToDoTest_notYetCompleted.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/test/java/dom/todo/ToDoTest_notYetCompleted.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/test/java/dom/todo/ToDoTest_notYetCompleted.java
new file mode 100644
index 0000000..4e83ddc
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/dom/src/test/java/dom/todo/ToDoTest_notYetCompleted.java
@@ -0,0 +1,51 @@
+#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 dom.todo;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class ToDoTest_notYetCompleted {
+
+    private ToDoItem toDoItem;
+
+    @Before
+    public void setUp() throws Exception {
+        toDoItem = new ToDoItem();
+        toDoItem.setComplete(true);
+    }
+    
+    @Test
+    public void happyCase() throws Exception {
+        // given
+        assertThat(toDoItem.disableNotYetCompleted(), is(nullValue()));
+        
+        // when
+        toDoItem.notYetCompleted();
+        
+        // then
+        assertThat(toDoItem.isComplete(), is(false));
+        assertThat(toDoItem.disableNotYetCompleted(), is(not(nullValue())));
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/fixture/src/main/java/fixture/todo/ToDoItemsFixture.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/fixture/src/main/java/fixture/todo/ToDoItemsFixture.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/fixture/src/main/java/fixture/todo/ToDoItemsFixture.java
index 4fd97db..25bcb84 100644
--- a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/fixture/src/main/java/fixture/todo/ToDoItemsFixture.java
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/fixture/src/main/java/fixture/todo/ToDoItemsFixture.java
@@ -23,60 +23,67 @@
 package fixture.todo;
 
 import java.math.BigDecimal;
-import java.util.List;
-
-import org.apache.isis.applib.clock.Clock;
-import org.apache.isis.applib.fixtures.AbstractFixture;
-import org.joda.time.LocalDate;
 
 import dom.todo.ToDoItem;
 import dom.todo.ToDoItem.Category;
+import dom.todo.ToDoItem.Subcategory;
 import dom.todo.ToDoItems;
-import dom.todo.ToDoItems.NotifyUserIfNone;
+
+import org.joda.time.LocalDate;
+
+import org.apache.isis.applib.clock.Clock;
+import org.apache.isis.applib.fixtures.AbstractFixture;
+import org.apache.isis.objectstore.jdo.applib.service.support.IsisJdoSupport;
 
 public class ToDoItemsFixture extends AbstractFixture {
 
+    private final String user;
+
+    public ToDoItemsFixture() {
+        this(null);
+    }
+    
+    public ToDoItemsFixture(String ownedBy) {
+        this.user = ownedBy;
+    }
+    
     @Override
     public void install() {
 
-        removeAllToDosForCurrentUser();
+        final String ownedBy = this.user != null? this.user : getContainer().getUser().getName();
+        
+        isisJdoSupport.executeUpdate("delete from ${symbol_escape}"ToDoItem${symbol_escape}" where ${symbol_escape}"ownedBy${symbol_escape}" = '" + ownedBy + "'");
 
-        installFor(getContainer().getUser().getName());
+        installFor(ownedBy);
         
         getContainer().flush();
     }
 
-    public void installFor(String user) {
-
-        removeAllToDosFor(user);
+    private void installFor(String user) {
 
-        createToDoItemForUser("Buy milk", Category.Domestic, user, daysFromToday(0), new BigDecimal("1.50"));
-        createToDoItemForUser("Buy stamps", Category.Domestic, user, daysFromToday(0), new BigDecimal("10.00"));
-        createToDoItemForUser("Pick up laundry", Category.Other, user, daysFromToday(6), new BigDecimal("7.50"));
-        createToDoItemForUser("Write blog post", Category.Professional, user, null, null);
-        createToDoItemForUser("Organize brown bag", Category.Professional, user, daysFromToday(14), null);
+        createToDoItemForUser("Buy milk", Category.Domestic, Subcategory.Shopping, user, daysFromToday(0), new BigDecimal("0.75"));
+        createToDoItemForUser("Buy bread", Category.Domestic, Subcategory.Shopping, user, daysFromToday(0), new BigDecimal("1.75"));
+        createToDoItemForUser("Buy stamps", Category.Domestic, Subcategory.Shopping, user, daysFromToday(0), new BigDecimal("10.00")).setComplete(true);
+        createToDoItemForUser("Pick up laundry", Category.Domestic, Subcategory.Chores, user, daysFromToday(6), new BigDecimal("7.50"));
+        createToDoItemForUser("Mow lawn", Category.Domestic, Subcategory.Garden, user, daysFromToday(6), null);
+        createToDoItemForUser("Vacuum house", Category.Domestic, Subcategory.Housework, user, daysFromToday(3), null);
+        createToDoItemForUser("Sharpen knives", Category.Domestic, Subcategory.Chores, user, daysFromToday(14), null);
+        
+        createToDoItemForUser("Write to penpal", Category.Other, Subcategory.Other, user, null, null);
+        
+        createToDoItemForUser("Write blog post", Category.Professional, Subcategory.Marketing, user, daysFromToday(7), null).setComplete(true);
+        createToDoItemForUser("Organize brown bag", Category.Professional, Subcategory.Consulting, user, daysFromToday(14), null);
+        createToDoItemForUser("Submit conference session", Category.Professional, Subcategory.Education, user, daysFromToday(21), null);
+        createToDoItemForUser("Stage Isis release", Category.Professional, Subcategory.OpenSource, user, null, null);
 
         getContainer().flush();
     }
 
-    // {{ helpers
-    private void removeAllToDosForCurrentUser() {
-        
-        final List<ToDoItem> allToDos = toDoItems.allToDos(NotifyUserIfNone.NO);
-        for (final ToDoItem toDoItem : allToDos) {
-            getContainer().remove(toDoItem);
-        }
-    }
 
-    private void removeAllToDosFor(String user) {
-        final List<ToDoItem> items = allMatches(ToDoItem.class, ToDoItem.thoseOwnedBy(user));
-        for (final ToDoItem toDoItem : items) {
-            getContainer().remove(toDoItem);
-        }
-    }
+    // //////////////////////////////////////
 
-    private ToDoItem createToDoItemForUser(final String description, final Category category, String user, final LocalDate dueBy, final BigDecimal cost) {
-        return toDoItems.newToDo(description, category, user, dueBy, cost);
+    private ToDoItem createToDoItemForUser(final String description, final Category category, Subcategory subcategory, String user, final LocalDate dueBy, final BigDecimal cost) {
+        return toDoItems.newToDo(description, category, subcategory, user, dueBy, cost);
     }
 
     private static LocalDate daysFromToday(final int i) {
@@ -84,15 +91,20 @@ public class ToDoItemsFixture extends AbstractFixture {
         return date.plusDays(i);
     }
 
-    // }}
+    
+    // //////////////////////////////////////
+
 
-    // {{ injected: ToDoItems
     private ToDoItems toDoItems;
 
     public void setToDoItems(final ToDoItems toDoItems) {
         this.toDoItems = toDoItems;
     }
-    // }}
+
     
+    private IsisJdoSupport isisJdoSupport;
+    public void injectIsisJdoSupport(IsisJdoSupport isisJdoSupport) {
+        this.isisJdoSupport = isisJdoSupport;
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/fixture/src/main/java/fixture/todo/ToDoItemsFixturesService.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/fixture/src/main/java/fixture/todo/ToDoItemsFixturesService.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/fixture/src/main/java/fixture/todo/ToDoItemsFixturesService.java
deleted file mode 100644
index 00deb70..0000000
--- a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/fixture/src/main/java/fixture/todo/ToDoItemsFixturesService.java
+++ /dev/null
@@ -1,67 +0,0 @@
-#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 fixture.todo;
-
-import java.util.List;
-
-import org.apache.isis.applib.AbstractService;
-import org.apache.isis.applib.annotation.Named;
-
-import com.google.common.collect.Lists;
-
-import dom.todo.ToDoItems;
-
-/**
- * Enables fixtures to be installed from the application.
- */
-@Named("Fixtures")
-public class ToDoItemsFixturesService extends AbstractService {
-
-    public String install() {
-        final ToDoItemsFixture fixture = new ToDoItemsFixture();
-        fixture.setContainer(getContainer());
-        fixture.setToDoItems(toDoItems);
-        fixture.install();
-        return "Example fixtures installed";
-    }
-
-    public String installFor(@Named("User") String user) {
-        final ToDoItemsFixture fixture = new ToDoItemsFixture();
-        fixture.setContainer(getContainer());
-        fixture.setToDoItems(toDoItems);
-        fixture.installFor(user);
-        return "Example fixtures installed for " + user;
-    }
-    public String default0InstallFor() {
-        return "guest";
-    }
-    public List<String> choices0InstallFor() {
-        return Lists.newArrayList("guest", "dick", "bob", "joe");
-    }
-
-    
-    private ToDoItems toDoItems;
-    public void setToDoItems(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/integtests/logging.properties
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/logging.properties b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/logging.properties
index aaa4c52..234ed51 100644
--- a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/logging.properties
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/logging.properties
@@ -41,6 +41,7 @@ ${symbol_pound}log4j.debug=true
 
 ${symbol_pound} DataNucleus
 log4j.logger.DataNucleus.Datastore.Native=DEBUG, Console
+log4j.logger.DataNucleus.Datastore.Schema=DEBUG, Console
 
 log4j.logger.DataNucleus.Persistence=WARN, Console
 log4j.logger.DataNucleus.Transaction=WARN, Console
@@ -49,7 +50,6 @@ log4j.logger.DataNucleus.Query=WARN, Console
 log4j.logger.DataNucleus.Cache=WARN, Console
 log4j.logger.DataNucleus.MetaData=WARN, Console
 log4j.logger.DataNucleus.Datastore=WARN, Console
-log4j.logger.DataNucleus.Datastore.Schema=WARN, Console
 log4j.logger.DataNucleus.Datastore.Persist=WARN, Console
 log4j.logger.DataNucleus.Datastore.Retrieve=WARN, Console
 log4j.logger.DataNucleus.General=WARN, Console

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/pom.xml
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/pom.xml b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/pom.xml
index b7a8d8d..93dbfee 100644
--- a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/pom.xml
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/pom.xml
@@ -29,33 +29,28 @@
 	<name>Quickstart Wicket/Restful/JDO Integration Tests</name>
 
     <build>
-        <pluginManagement>
-            <plugins>
-                <plugin>
-                    <artifactId>maven-surefire-plugin</artifactId>
-                    <configuration>
-                        <includes>
-                            <include>**/*.java</include>
-                        </includes>
-                        <excludes>
-                            <exclude>**/*Abstract*.java</exclude>
-                        </excludes>
-                    </configuration>
-                </plugin>
-            </plugins>
-        </pluginManagement>
+        <testResources>
+            <testResource>
+                <directory>src/test/resources</directory>
+            </testResource>
+            <testResource>
+                <directory>src/test/java</directory>
+                <includes>
+                    <include>**</include>
+                </includes>
+                <excludes>
+                    <exclude>**/*.java</exclude>
+                </excludes>
+            </testResource>
+        </testResources>  
     </build>
-	<dependencies>
+  	<dependencies>
 	
 		<!-- other modules in this project -->
 		<dependency>
 			<groupId>${project.groupId}</groupId>
 			<artifactId>${rootArtifactId}-fixture</artifactId>
 		</dependency>
-		<dependency>
-			<groupId>${project.groupId}</groupId>
-			<artifactId>${rootArtifactId}-objstore-jdo</artifactId>
-		</dependency>
 
         <dependency>
             <groupId>org.apache.isis.core</groupId>
@@ -66,18 +61,62 @@
             <groupId>org.apache.isis.core</groupId>
             <artifactId>isis-core-integtestsupport</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.isis.core</groupId>
+            <artifactId>isis-core-specsupport</artifactId>
+        </dependency>
+        
+        <dependency>
+            <groupId>org.hamcrest</groupId>
+            <artifactId>hamcrest-library</artifactId>
+        </dependency>
 
         <dependency>
             <groupId>org.apache.isis.core</groupId>
             <artifactId>isis-core-wrapper</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.isis.objectstore</groupId>
+            <artifactId>isis-objectstore-jdo-datanucleus</artifactId>
+        </dependency>
 
         <dependency>
             <groupId>org.hsqldb</groupId>
             <artifactId>hsqldb</artifactId>
         </dependency>
 
-		
+        <!-- 
+        uncomment to enable enhanced cucumber-jvm reporting
+        http://www.masterthought.net/section/cucumber-reporting
+        <dependency>  
+            <groupId>com.googlecode.totallylazy</groupId>  
+            <artifactId>totallylazy</artifactId>  
+            <version>991</version>  
+        </dependency>
+
+        <dependency>
+            <groupId>net.masterthought</groupId>
+            <artifactId>cucumber-reporting</artifactId>
+            <version>0.0.21</version>
+        </dependency>
+        <dependency>
+            <groupId>net.masterthought</groupId>
+            <artifactId>maven-cucumber-reporting</artifactId>
+            <version>0.0.4</version>
+        </dependency>  
+        -->
 	</dependencies>
 
+    <!-- 
+    uncomment for enhanced cucumber-jvm reporting
+    http://www.masterthought.net/section/cucumber-reporting
+    <repositories>  
+        <repository>  
+            <id>repo.bodar.com</id>  
+            <url>http://repo.bodar.com</url>  
+        </repository>  
+    </repositories>  
+     -->
+  
+
 </project>

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/ToDoSystemInitializer.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/ToDoSystemInitializer.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/ToDoSystemInitializer.java
new file mode 100644
index 0000000..16e2c50
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/ToDoSystemInitializer.java
@@ -0,0 +1,88 @@
+#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 integration;
+
+import app.ToDoItemAnalysis;
+import dom.todo.ToDoItemContributions;
+import dom.todo.ToDoItems;
+
+import org.apache.isis.core.commons.config.IsisConfiguration;
+import org.apache.isis.core.commons.config.IsisConfigurationDefault;
+import org.apache.isis.core.integtestsupport.IsisSystemForTest;
+import org.apache.isis.core.wrapper.WrapperFactoryDefault;
+import org.apache.isis.objectstore.jdo.datanucleus.DataNucleusObjectStore;
+import org.apache.isis.objectstore.jdo.datanucleus.DataNucleusPersistenceMechanismInstaller;
+import org.apache.isis.objectstore.jdo.datanucleus.service.support.IsisJdoSupportImpl;
+import org.apache.isis.objectstore.jdo.service.RegisterEntities;
+
+/**
+ * Holds an instance of an {@link IsisSystemForTest} as a {@link ThreadLocal} on the current thread,
+ * initialized with ToDo app's domain services. 
+ */
+public class ToDoSystemInitializer {
+    
+    private ToDoSystemInitializer(){}
+
+    public static IsisSystemForTest initIsft() {
+        IsisSystemForTest isft = IsisSystemForTest.getElseNull();
+        if(isft == null) {
+            isft = new ToDoSystemBuilder().build().setUpSystem();
+            IsisSystemForTest.set(isft);
+        }
+        return isft;
+    }
+
+    private static class ToDoSystemBuilder extends IsisSystemForTest.Builder {
+
+        public ToDoSystemBuilder() {
+            //withFixtures( ... reference data fixtures ...); // if we had any...
+            withLoggingAt(org.apache.log4j.Level.INFO);
+            with(testConfiguration());
+            with(new DataNucleusPersistenceMechanismInstaller());
+            
+            withServices(
+                    new ToDoItems(),
+                    new ToDoItemAnalysis(),
+                    new ToDoItemContributions(),
+                    new WrapperFactoryDefault(),
+                    new RegisterEntities(),
+                    new IsisJdoSupportImpl()
+                    );
+        }
+
+        private IsisConfiguration testConfiguration() {
+            final IsisConfigurationDefault testConfiguration = new IsisConfigurationDefault();
+
+            testConfiguration.add("isis.persistor.datanucleus.RegisterEntities.packagePrefix", "dom");
+            testConfiguration.add("isis.persistor.datanucleus.impl.javax.jdo.option.ConnectionURL", "jdbc:hsqldb:mem:test");
+            
+            testConfiguration.add("isis.persistor.datanucleus.impl.datanucleus.defaultInheritanceStrategy", "TABLE_PER_CLASS");
+            testConfiguration.add(DataNucleusObjectStore.INSTALL_FIXTURES_KEY , "true");
+            
+            testConfiguration.add("isis.persistor.datanucleus.impl.datanucleus.cache.level2.type","none");
+
+            testConfiguration.add("isis.persistor.datanucleus.impl.datanucleus.identifier.case", "PreserveCase");
+
+            return testConfiguration;
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/glue/BootstrappingGlue.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/glue/BootstrappingGlue.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/glue/BootstrappingGlue.java
new file mode 100644
index 0000000..f800e25
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/glue/BootstrappingGlue.java
@@ -0,0 +1,59 @@
+#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 integration.glue;
+
+import integration.ToDoSystemInitializer;
+import cucumber.api.java.After;
+import cucumber.api.java.Before;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.isis.core.specsupport.scenarios.ScenarioExecutionScope;
+import org.apache.isis.core.specsupport.specs.CukeGlueAbstract;
+
+public class BootstrappingGlue extends CukeGlueAbstract {
+
+    // //////////////////////////////////////
+    
+    @Before(value={"@unit"}, order=100)
+    public void beforeScenarioUnitScope() {
+        before(ScenarioExecutionScope.UNIT);
+    }
+
+    @Before(value={"@integration"}, order=100)
+    public void beforeScenarioIntegrationScope() {
+        org.apache.log4j.PropertyConfigurator.configure("logging.properties");
+        ToDoSystemInitializer.initIsft();
+        
+        before(ScenarioExecutionScope.INTEGRATION);
+    }
+
+    @After
+    public void afterScenario(cucumber.api.Scenario sc) {
+        assertMocksSatisfied();
+        after(sc);
+    }
+
+    // //////////////////////////////////////
+    
+
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/glue/CatalogOfFixturesGlue.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/glue/CatalogOfFixturesGlue.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/glue/CatalogOfFixturesGlue.java
new file mode 100644
index 0000000..c826d30
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/glue/CatalogOfFixturesGlue.java
@@ -0,0 +1,50 @@
+#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 integration.glue;
+
+import cucumber.api.java.Before;
+import dom.todo.ToDoItem;
+import fixture.todo.ToDoItemsFixture;
+
+import org.apache.isis.core.specsupport.scenarios.InMemoryDB;
+import org.apache.isis.core.specsupport.specs.CukeGlueAbstract;
+
+public class CatalogOfFixturesGlue extends CukeGlueAbstract {
+
+    
+    @Before(value={"@unit", "@ToDoItemsFixture"}, order=20000)
+    public void unitFixtures() throws Throwable {
+        final InMemoryDB inMemoryDB = new InMemoryDBForToDoApp(this.scenarioExecution());
+        inMemoryDB.getElseCreate(ToDoItem.class, "Write blog post");
+        inMemoryDB.getElseCreate(ToDoItem.class, "Pick up bread");
+        final ToDoItem t3 = inMemoryDB.getElseCreate(ToDoItem.class, "Pick up butter");
+        t3.setComplete(true);
+        putVar("isis", "in-memory-db", inMemoryDB);
+    }
+
+    // //////////////////////////////////////
+
+    @Before(value={"@integration", "@ToDoItemsFixture"}, order=20000)
+    public void integrationFixtures() throws Throwable {
+        scenarioExecution().install(new ToDoItemsFixture());
+    }
+    
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/glue/InMemoryDBForToDoApp.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/glue/InMemoryDBForToDoApp.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/glue/InMemoryDBForToDoApp.java
new file mode 100644
index 0000000..4d8af87
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/glue/InMemoryDBForToDoApp.java
@@ -0,0 +1,43 @@
+#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 integration.glue;
+
+import dom.todo.ToDoItem;
+
+import org.apache.isis.core.specsupport.scenarios.InMemoryDB;
+import org.apache.isis.core.specsupport.scenarios.ScenarioExecution;
+
+public class InMemoryDBForToDoApp extends InMemoryDB {
+    
+    public InMemoryDBForToDoApp(ScenarioExecution scenarioExecution) {
+        super(scenarioExecution);
+    }
+    
+    /**
+     * Hook to initialize if possible.
+     */
+    @Override
+    protected void init(Object obj, String str) {
+        if(obj instanceof ToDoItem) {
+            ToDoItem toDoItem = (ToDoItem) obj;
+            toDoItem.setDescription(str);
+        }
+    }
+}
\ 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/integtests/src/test/java/integration/glue/todoitem/ToDoItemGlue.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/glue/todoitem/ToDoItemGlue.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/glue/todoitem/ToDoItemGlue.java
new file mode 100644
index 0000000..9cfffd1
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/glue/todoitem/ToDoItemGlue.java
@@ -0,0 +1,169 @@
+#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 integration.glue.todoitem;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.util.List;
+
+import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+import cucumber.api.java.en.Given;
+import cucumber.api.java.en.Then;
+import cucumber.api.java.en.When;
+import dom.todo.ToDoItem;
+import dom.todo.ToDoItems;
+
+import org.jmock.Expectations;
+import org.junit.Assert;
+
+import org.apache.isis.applib.annotation.Bulk;
+import org.apache.isis.core.specsupport.scenarios.InMemoryDB;
+import org.apache.isis.core.specsupport.specs.CukeGlueAbstract;
+
+public class ToDoItemGlue extends CukeGlueAbstract {
+
+    @Given("^there are a number of incomplete ToDo items${symbol_dollar}")
+    public void there_are_a_number_of_incomplete_ToDo_items() throws Throwable {
+        if(supportsMocks()) {
+            checking(new Expectations() {
+                {
+                    allowing(service(ToDoItems.class)).notYetComplete();
+                    will(returnValue(notYetCompleteItems()));
+                }
+            });
+        }
+        try {
+            final List<ToDoItem> notYetComplete = service(ToDoItems.class).notYetComplete();
+            assertThat(notYetComplete.isEmpty(), is(false));
+            putVar("list", "notYetCompleteItems", notYetComplete);
+            
+        } finally {
+            assertMocksSatisfied();
+        }
+    }
+    
+    @When("^I choose the first of the incomplete items${symbol_dollar}")
+    public void I_choose_the_first_one() throws Throwable {
+        @SuppressWarnings("unchecked")
+        List<ToDoItem> notYetComplete = getVar(null, "notYetCompleteItems", List.class);
+        assertThat(notYetComplete.isEmpty(), is(false));
+        
+        putVar("todo", "toDoItem", notYetComplete.get(0));
+    }
+    
+    @When("^mark the item as complete${symbol_dollar}")
+    public void mark_it_as_complete() throws Throwable {
+        final ToDoItem toDoItem = getVar(null, "toDoItem", ToDoItem.class);
+        if(supportsMocks()) {
+            Bulk.InteractionContext.with(new Runnable(){
+                @Override
+                public void run() {
+                    toDoItem.completed();
+                }
+            }, toDoItem);
+        } else {
+            // can just call directly; 
+            // framework will take care of setting the Bulk.InteractionContext.
+            wrap(toDoItem).completed();
+        }
+    }
+    
+    @Then("^the item is no longer listed as incomplete${symbol_dollar}")
+    public void the_item_is_no_longer_listed_as_incomplete() throws Throwable {
+        ToDoItem toDoItem = getVar(null, "toDoItem", ToDoItem.class);
+        whetherNotYetCompletedContains(toDoItem, false);
+    }
+
+    @Given("^.*completed .*item${symbol_dollar}")
+    public void a_completed_ToDo_item() throws Throwable {
+        if(supportsMocks()) {
+            checking(new Expectations(){{
+                allowing(service(ToDoItems.class)).allToDos();
+                will(returnValue(findItems(Predicates.<ToDoItem>alwaysTrue()) ));
+            }});
+        }
+        try {
+            final List<ToDoItem> allToDos = service(ToDoItems.class).allToDos();
+            for (ToDoItem toDoItem : allToDos) {
+                if(toDoItem.isComplete()) {
+                    putVar("todo", "toDoItem", toDoItem);
+                    return;
+                }
+            }
+            Assert.fail("could not locate any completed ToDo items");
+        } finally {
+            assertMocksSatisfied();
+        }
+    }
+
+    @When("^I mark the .*item as not yet complete${symbol_dollar}")
+    public void I_mark_it_as_not_yet_complete() throws Throwable {
+        ToDoItem toDoItem = getVar(null, "toDoItem", ToDoItem.class);
+        assertThat(toDoItem.isComplete(), is(true));
+        
+        toDoItem.setComplete(false);
+    }
+
+    @Then("^the .*item is listed as incomplete${symbol_dollar}")
+    public void the_item_is_listed_as_incomplete() throws Throwable {
+        ToDoItem toDoItem = getVar(null, "toDoItem", ToDoItem.class);
+        whetherNotYetCompletedContains(toDoItem, true);
+    }
+
+    private void whetherNotYetCompletedContains(ToDoItem toDoItem, final boolean whetherContained) {
+        if(supportsMocks()) {
+            final List<ToDoItem> notYetCompleteItems = notYetCompleteItems();
+            checking(new Expectations() {
+                {
+                    oneOf(service(ToDoItems.class)).notYetComplete();
+                    will(returnValue(notYetCompleteItems));
+                }
+            });
+        }
+        try {
+            final List<ToDoItem> notYetComplete = service(ToDoItems.class).notYetComplete();
+            assertThat(notYetComplete.contains(toDoItem), is(whetherContained));
+        } finally {
+            assertMocksSatisfied();
+        }
+    }
+
+
+    // helper
+    private List<ToDoItem> notYetCompleteItems() {
+        return findItems(new Predicate<ToDoItem>(){
+            @Override
+            public boolean apply(ToDoItem input) {
+                return !input.isComplete();
+            }
+        });
+    }
+
+    private List<ToDoItem> findItems(final Predicate<ToDoItem> predicate) {
+        final InMemoryDB inMemoryDB = getVar("isis", "in-memory-db", InMemoryDB.class);
+        final List<ToDoItem> items = inMemoryDB.findAll(ToDoItem.class);
+        return Lists.newArrayList(Iterables.filter(items, predicate));
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/specs/todoitem/RunSpecs.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/specs/todoitem/RunSpecs.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/specs/todoitem/RunSpecs.java
new file mode 100644
index 0000000..a0d30e2
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/specs/todoitem/RunSpecs.java
@@ -0,0 +1,41 @@
+#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 integration.specs.todoitem;
+
+import cucumber.api.junit.Cucumber;
+
+import org.junit.runner.RunWith;
+
+
+/**
+ * Runs scenarios in all <tt>.feature</tt> files (this package and any subpackages). 
+ */
+@RunWith(Cucumber.class)
+@Cucumber.Options(
+        format = {
+                "html:target/cucumber-html-report"
+                ,"json:target/cucumber.json"
+        },
+        glue={"classpath:integration.glue"},
+        strict = true,
+        tags = { "~@backlog", "~@ignore" })
+public class RunSpecs {
+    // intentionally empty 
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findAndComplete.feature
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findAndComplete.feature b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findAndComplete.feature
new file mode 100644
index 0000000..9fc1596
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findAndComplete.feature
@@ -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.
+#
+@ToDoItemsFixture
+Feature: Find And Complete ToDo Items
+
+  # the scenario is listed twice here just to demonstrate that it
+  # can be run either at @unit-level scope (using mocks) or
+  # at @integration-level scope (against the running system).
+  
+  @unit
+  Scenario: Todo items once completed are no longer listed
+    Given there are a number of incomplete ToDo items
+    When  I choose the first of the incomplete items
+    And   mark the item as complete
+    Then  the item is no longer listed as incomplete 
+
+
+  @integration
+  Scenario: Todo items once completed are no longer listed
+    Given there are a number of incomplete ToDo items
+    When  I choose the first of the incomplete items
+    And   mark the item as complete
+    Then  the item is no longer listed as incomplete 
+
+    
\ 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/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findCompletedAndMarkAsNotYetComplete.feature
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findCompletedAndMarkAsNotYetComplete.feature b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findCompletedAndMarkAsNotYetComplete.feature
new file mode 100644
index 0000000..1f5f73e
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/specs/todoitem/ToDoItemSpec_findCompletedAndMarkAsNotYetComplete.feature
@@ -0,0 +1,35 @@
+#
+#  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.
+#
+@ToDoItemsFixture
+Feature: Find completed ToDoItem and mark as not yet complete
+
+  # the scenario is listed twice here just to demonstrate that it
+  # can be run either at @unit-level scope (using mocks) or
+  # at @integration-level scope (against the running system).
+  
+  @integration
+  Scenario: Todo items can be uncompleted
+    Given a completed item
+    When  I mark the item as not yet complete
+    Then  the item is listed as incomplete 
+
+ 
+  @unit
+  Scenario: Todo items can be uncompleted
+    Given a completed ToDo item
+    When  I mark the item as not yet complete
+    Then  the item is listed as incomplete 

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/tests/ToDoIntegTest.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/tests/ToDoIntegTest.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/tests/ToDoIntegTest.java
new file mode 100644
index 0000000..4e60a9b
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/tests/ToDoIntegTest.java
@@ -0,0 +1,43 @@
+#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 integration.tests;
+
+import integration.ToDoSystemInitializer;
+
+import org.junit.BeforeClass;
+
+import org.apache.isis.core.integtestsupport.IntegrationTestAbstract;
+import org.apache.isis.core.integtestsupport.scenarios.ScenarioExecutionForIntegration;
+
+public abstract class ToDoIntegTest extends IntegrationTestAbstract {
+
+    
+    @BeforeClass
+    public static void initClass() {
+        org.apache.log4j.PropertyConfigurator.configure("logging.properties");
+        ToDoSystemInitializer.initIsft();
+        
+        // instantiating will install onto ThreadLocal
+        new ScenarioExecutionForIntegration();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/c742898c/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/tests/actions/ToDoItemContributionsTest_updateCategory.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/tests/actions/ToDoItemContributionsTest_updateCategory.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/tests/actions/ToDoItemContributionsTest_updateCategory.java
new file mode 100644
index 0000000..e81eccd
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/tests/actions/ToDoItemContributionsTest_updateCategory.java
@@ -0,0 +1,102 @@
+#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 integration.tests.actions;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.assertThat;
+import integration.tests.ToDoIntegTest;
+
+import java.util.List;
+
+import dom.todo.ToDoItem;
+import dom.todo.ToDoItemContributions;
+import dom.todo.ToDoItems;
+import dom.todo.ToDoItem.Category;
+import dom.todo.ToDoItem.Subcategory;
+import fixture.todo.ToDoItemsFixture;
+
+import org.joda.time.LocalDate;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.apache.isis.applib.clock.Clock;
+
+public class ToDoItemContributionsTest_updateCategory extends ToDoIntegTest {
+
+    private ToDoItem toDoItem;
+    private ToDoItemContributions toDoItemContributions;
+
+    @Before
+    public void setUp() throws Exception {
+        scenarioExecution().install(new ToDoItemsFixture());
+
+        final ToDoItems toDoItems = wrap(service(ToDoItems.class));
+        toDoItemContributions = wrap(service(ToDoItemContributions.class));
+        final List<ToDoItem> all = toDoItems.notYetComplete();
+        toDoItem = wrap(all.get(0));
+    }
+
+    @Test
+    public void happyCase() throws Exception {
+        
+        // when
+        toDoItemContributions.updateCategory(toDoItem, Category.Professional, Subcategory.Consulting);
+        
+        // then
+        assertThat(toDoItem.getCategory(), is(Category.Professional));
+        assertThat(toDoItem.getSubcategory(), is(Subcategory.Consulting));
+        
+        // when
+        toDoItemContributions.updateCategory(toDoItem, Category.Domestic, Subcategory.Chores);
+        
+        // then
+        assertThat(toDoItem.getCategory(), is(Category.Domestic));
+        assertThat(toDoItem.getSubcategory(), is(Subcategory.Chores));
+    }
+
+
+    @Test
+    public void categoryCannotBeNull() throws Exception {
+        
+        // when, then
+        expectedExceptions.expectMessage("Category is mandatory");
+        toDoItemContributions.updateCategory(toDoItem, null, Subcategory.Chores);
+    }
+
+    @Test
+    public void subcategoryCannotBeNull() throws Exception {
+        
+        // when, then
+        expectedExceptions.expectMessage("Subcategory is mandatory");
+        toDoItemContributions.updateCategory(toDoItem, Category.Professional, null);
+    }
+    
+    @Test
+    public void subcategoryMustBelongToCategory() throws Exception {
+        
+        // when, then
+        expectedExceptions.expectMessage(containsString("Invalid subcategory"));
+        toDoItemContributions.updateCategory(toDoItem, Category.Professional, Subcategory.Chores);
+    }
+    
+}
\ 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/integtests/src/test/java/integration/tests/actions/ToDoItemTest_completed.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/tests/actions/ToDoItemTest_completed.java b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/tests/actions/ToDoItemTest_completed.java
new file mode 100644
index 0000000..7f31f74
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/src/main/resources/archetype-resources/integtests/src/test/java/integration/tests/actions/ToDoItemTest_completed.java
@@ -0,0 +1,86 @@
+#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 integration.tests.actions;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+import integration.tests.ToDoIntegTest;
+
+import java.util.List;
+
+import dom.todo.ToDoItem;
+import dom.todo.ToDoItems;
+import fixture.todo.ToDoItemsFixture;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class ToDoItemTest_completed extends ToDoIntegTest {
+
+    private ToDoItem toDoItem;
+
+    @Before
+    public void setUp() throws Exception {
+        scenarioExecution().install(new ToDoItemsFixture());
+
+        final List<ToDoItem> all = wrap(service(ToDoItems.class)).notYetComplete();
+        toDoItem = wrap(all.get(0));
+    }
+
+
+    @Test
+    public void happyCase() throws Exception {
+        
+        // given
+        assertThat(toDoItem.isComplete(), is(false));
+        
+        // when
+        toDoItem.completed();
+        
+        // then
+        assertThat(toDoItem.isComplete(), is(true));
+    }
+
+
+    @Test
+    public void cannotCompleteIfAlreadyCompleted() throws Exception {
+        
+        // given
+        unwrap(toDoItem).setComplete(true);
+
+        // when, then should fail
+        expectedExceptions.expectMessage("Already completed");
+        toDoItem.completed();
+    }
+
+
+    @Test
+    public void cannotSetPropertyDirectly() throws Exception {
+        
+        // given
+
+        // when, then should fail
+        expectedExceptions.expectMessage("Always disabled");
+        toDoItem.setComplete(true);
+    }
+
+}
\ No newline at end of file