You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2014/03/06 18:14:27 UTC
[28/31] ISIS-695: recreating quickstart archetype
http://git-wip-us.apache.org/repos/asf/isis/blob/10242866/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.java b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.java
new file mode 100644
index 0000000..2cfc4b3
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.java
@@ -0,0 +1,863 @@
+#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.math.BigDecimal;
+import java.net.MalformedURLException;
+import java.net.URL;
+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.IdentityType;
+import javax.jdo.annotations.VersionStrategy;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Ordering;
+
+import org.joda.time.LocalDate;
+
+import org.apache.isis.applib.DomainObjectContainer;
+import org.apache.isis.applib.NonRecoverableException;
+import org.apache.isis.applib.RecoverableException;
+import org.apache.isis.applib.annotation.ActionSemantics;
+import org.apache.isis.applib.annotation.ActionSemantics.Of;
+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.AppliesTo;
+import org.apache.isis.applib.annotation.Bulk.InteractionContext.InvokedAs;
+import org.apache.isis.applib.annotation.Command;
+import org.apache.isis.applib.annotation.Command.ExecuteIn;
+import org.apache.isis.applib.annotation.Disabled;
+import org.apache.isis.applib.annotation.Hidden;
+import org.apache.isis.applib.annotation.MinLength;
+import org.apache.isis.applib.annotation.Named;
+import org.apache.isis.applib.annotation.ObjectType;
+import org.apache.isis.applib.annotation.Optional;
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.annotation.Prototype;
+import org.apache.isis.applib.annotation.PublishedAction;
+import org.apache.isis.applib.annotation.PublishedObject;
+import org.apache.isis.applib.annotation.RegEx;
+import org.apache.isis.applib.annotation.SortedBy;
+import org.apache.isis.applib.annotation.TypicalLength;
+import org.apache.isis.applib.clock.Clock;
+import org.apache.isis.applib.services.background.BackgroundService;
+import org.apache.isis.applib.services.clock.ClockService;
+import org.apache.isis.applib.services.command.CommandContext;
+import org.apache.isis.applib.services.scratchpad.Scratchpad;
+import org.apache.isis.applib.util.ObjectContracts;
+import org.apache.isis.applib.util.TitleBuffer;
+import org.apache.isis.applib.value.Blob;
+
+@javax.jdo.annotations.PersistenceCapable(identityType=IdentityType.DATASTORE)
+@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 = "findByOwnedBy", language = "JDOQL",
+ value = "SELECT "
+ + "FROM dom.todo.ToDoItem "
+ + "WHERE ownedBy == :ownedBy"),
+ @javax.jdo.annotations.Query(
+ name = "findByOwnedByAndCompleteIsFalse", language = "JDOQL",
+ value = "SELECT "
+ + "FROM dom.todo.ToDoItem "
+ + "WHERE ownedBy == :ownedBy "
+ + " && complete == false"),
+ @javax.jdo.annotations.Query(
+ name = "findByOwnedByAndCompleteIsTrue", language = "JDOQL",
+ value = "SELECT "
+ + "FROM dom.todo.ToDoItem "
+ + "WHERE ownedBy == :ownedBy "
+ + "&& complete == true"),
+ @javax.jdo.annotations.Query(
+ name = "findByOwnedByAndCategory", language = "JDOQL",
+ value = "SELECT "
+ + "FROM dom.todo.ToDoItem "
+ + "WHERE ownedBy == :ownedBy "
+ + "&& category == :category"),
+ @javax.jdo.annotations.Query(
+ name = "findByOwnedByAndDescriptionContains", language = "JDOQL",
+ value = "SELECT "
+ + "FROM dom.todo.ToDoItem "
+ + "WHERE ownedBy == :ownedBy && "
+ + "description.indexOf(:description) >= 0")
+})
+@ObjectType("TODO")
+@Audited
+@PublishedObject(ToDoItemChangedPayloadFactory.class)
+@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> {
+
+ /**
+ * It isn't common for entities to log, but they can if required.
+ * Isis uses slf4j API internally (with log4j as implementation), and is the recommended API to use.
+ */
+ private final static org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(ToDoItem.class);
+
+ // //////////////////////////////////////
+ // Identification in the UI
+ // //////////////////////////////////////
+
+ public String title() {
+ final TitleBuffer buf = new TitleBuffer();
+ buf.append(getDescription());
+ if (isComplete()) {
+ buf.append("- Completed!");
+ } else {
+ if (getDueBy() != null) {
+ buf.append(" due by", getDueBy());
+ }
+ }
+ return buf.toString();
+ }
+
+ public String iconName() {
+ return "ToDoItem-" + (!isComplete() ? "todo" : "done");
+ }
+
+ // //////////////////////////////////////
+ // Description (property)
+ // //////////////////////////////////////
+
+ private String description;
+
+ @javax.jdo.annotations.Column(allowsNull="false", length=100)
+ @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]*")
+ @TypicalLength(50)
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(final String description) {
+ this.description = description;
+ }
+
+
+
+ // //////////////////////////////////////
+ // DueBy (property)
+ // //////////////////////////////////////
+
+ @javax.jdo.annotations.Persistent(defaultFetchGroup="true")
+ private LocalDate dueBy;
+
+ @javax.jdo.annotations.Column(allowsNull="true")
+ public LocalDate getDueBy() {
+ return dueBy;
+ }
+
+ public void setDueBy(final LocalDate dueBy) {
+ this.dueBy = dueBy;
+ }
+ public void clearDueBy() {
+ setDueBy(null);
+ }
+ // proposed new value is validated before setting
+ public String validateDueBy(final LocalDate dueBy) {
+ if (dueBy == null) {
+ return null;
+ }
+ return isMoreThanOneWeekInPast(dueBy) ? "Due by date cannot be more than one week old" : null;
+ }
+
+ // //////////////////////////////////////
+ // Category and Subcategory (property)
+ // //////////////////////////////////////
+
+ public static enum Category {
+ Professional {
+ @Override
+ public List<Subcategory> subcategories() {
+ return Arrays.asList(null, Subcategory.OpenSource, Subcategory.Consulting, Subcategory.Education);
+ }
+ }, Domestic {
+ @Override
+ public List<Subcategory> subcategories() {
+ return Arrays.asList(null, Subcategory.Shopping, Subcategory.Housework, Subcategory.Garden, Subcategory.Chores);
+ }
+ }, Other {
+ @Override
+ public List<Subcategory> subcategories() {
+ return Arrays.asList(null, 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;
+
+ @javax.jdo.annotations.Column(allowsNull="false")
+ public Category getCategory() {
+ return category;
+ }
+
+ public void setCategory(final Category category) {
+ this.category = category;
+ }
+
+ // //////////////////////////////////////
+
+ private Subcategory subcategory;
+
+ @javax.jdo.annotations.Column(allowsNull="true")
+ public Subcategory getSubcategory() {
+ return subcategory;
+ }
+ public void setSubcategory(final Subcategory subcategory) {
+ this.subcategory = subcategory;
+ }
+
+
+ // //////////////////////////////////////
+ // OwnedBy (property)
+ // //////////////////////////////////////
+
+ private String ownedBy;
+
+ @javax.jdo.annotations.Column(allowsNull="false")
+ public String getOwnedBy() {
+ return ownedBy;
+ }
+
+ public void setOwnedBy(final String ownedBy) {
+ this.ownedBy = ownedBy;
+ }
+
+
+ // //////////////////////////////////////
+ // Complete (property),
+ // Done (action), Undo (action)
+ // //////////////////////////////////////
+
+ private boolean complete;
+
+ @Disabled
+ public boolean isComplete() {
+ return complete;
+ }
+
+ public void setComplete(final boolean complete) {
+ this.complete = complete;
+ }
+
+ @Command
+ @PublishedAction
+ @Bulk
+ public ToDoItem completed() {
+ setComplete(true);
+
+ //
+ // remainder of method just demonstrates the use of the Bulk.InteractionContext service
+ //
+ @SuppressWarnings("unused")
+ final List<Object> allObjects = bulkInteractionContext.getDomainObjects();
+
+ LOG.debug("completed: "
+ + bulkInteractionContext.getIndex() +
+ " [" + bulkInteractionContext.getSize() + "]"
+ + (bulkInteractionContext.isFirst() ? " (first)" : "")
+ + (bulkInteractionContext.isLast() ? " (last)" : ""));
+
+ // if invoked as a regular action, return this object;
+ // otherwise (if invoked as bulk), return null (so go back to the list)
+ return bulkInteractionContext.getInvokedAs() == InvokedAs.REGULAR? this: null;
+ }
+ // disable action dependent on state of object
+ public String disableCompleted() {
+ return isComplete() ? "Already completed" : null;
+ }
+
+ @Command
+ @PublishedAction
+ @Bulk
+ public ToDoItem notYetCompleted() {
+ setComplete(false);
+
+ return this;
+ }
+ // disable action dependent on state of object
+ public String disableNotYetCompleted() {
+ return !complete ? "Not yet completed" : null;
+ }
+
+ // //////////////////////////////////////
+ // completeSlowly
+ // //////////////////////////////////////
+
+ @Hidden
+ public void completeSlowly(int millis) {
+ try {
+ Thread.sleep(millis);
+ } catch (InterruptedException e) {
+ }
+ setComplete(true);
+ }
+
+
+ // //////////////////////////////////////
+ // Cost (property), UpdateCost (action)
+ // //////////////////////////////////////
+
+ private BigDecimal cost;
+
+ @javax.jdo.annotations.Column(allowsNull="true", scale=2)
+ @javax.validation.constraints.Digits(integer=10, fraction=2)
+ @Disabled(reason="Update using action")
+ public BigDecimal getCost() {
+ return cost;
+ }
+
+ public void setCost(final BigDecimal cost) {
+ this.cost = cost!=null?cost.setScale(2):null;
+ }
+
+ public ToDoItem updateCost(
+ @Named("New cost")
+ @javax.validation.constraints.Digits(integer=10, fraction=2)
+ @Optional
+ final BigDecimal cost) {
+ LOG.debug("%s: cost updated: %s -> %s", container.titleOf(this), getCost(), cost);
+
+ // just to simulate a long-running action
+ try {
+ Thread.sleep(3000);
+ } catch (InterruptedException e) {
+ }
+
+ setCost(cost);
+ return this;
+ }
+
+ // 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)
+ // //////////////////////////////////////
+
+ private String notes;
+
+ @javax.jdo.annotations.Column(allowsNull="true", length=400)
+ public String getNotes() {
+ return notes;
+ }
+
+ public void setNotes(final String notes) {
+ this.notes = notes;
+ }
+
+ // //////////////////////////////////////
+ // Attachment (property)
+ // //////////////////////////////////////
+
+ private Blob attachment;
+
+ @javax.jdo.annotations.Persistent(defaultFetchGroup="false")
+ @javax.jdo.annotations.Column(allowsNull="true")
+ public Blob getAttachment() {
+ return attachment;
+ }
+
+ public void setAttachment(final Blob attachment) {
+ this.attachment = attachment;
+ }
+
+ // //////////////////////////////////////
+ // Version (derived property)
+ // //////////////////////////////////////
+
+ public Long getVersionSequence() {
+ if(!(this instanceof javax.jdo.spi.PersistenceCapable)) {
+ return null;
+ }
+ javax.jdo.spi.PersistenceCapable persistenceCapable = (javax.jdo.spi.PersistenceCapable) this;
+ final Long version = (Long) JDOHelper.getVersion(persistenceCapable);
+ return version;
+ }
+ // hide property (imperatively, based on state of object)
+ public boolean hideVersionSequence() {
+ return !(this instanceof javax.jdo.spi.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);
+ }
+ }
+
+
+
+ @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)
+ public SortedSet<ToDoItem> getDependencies() {
+ return dependencies;
+ }
+
+ public void setDependencies(final SortedSet<ToDoItem> dependencies) {
+ this.dependencies = dependencies;
+ }
+
+
+ @PublishedAction
+ public ToDoItem add(
+ @TypicalLength(20)
+ 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";
+ }
+ return null;
+ }
+ // validate the provided argument prior to invoking action
+ public String validateAdd(final ToDoItem toDoItem) {
+ if(getDependencies().contains(toDoItem)) {
+ return "Already a dependency";
+ }
+ if(toDoItem == this) {
+ return "Can't set up a dependency to self";
+ }
+ return null;
+ }
+
+ public ToDoItem remove(
+ @TypicalLength(20)
+ final ToDoItem toDoItem) {
+ getDependencies().remove(toDoItem);
+ return this;
+ }
+ // disable action dependent on state of object
+ public String disableRemove(final ToDoItem toDoItem) {
+ if(isComplete()) {
+ return "Cannot remove dependencies for items that are complete";
+ }
+ return getDependencies().isEmpty()? "No dependencies to remove": null;
+ }
+ // validate the provided argument prior to invoking action
+ public String validateRemove(final ToDoItem toDoItem) {
+ if(!getDependencies().contains(toDoItem)) {
+ return "Not a dependency";
+ }
+ return null;
+ }
+ // provide a drop-down
+ public Collection<ToDoItem> choices0Remove() {
+ return getDependencies();
+ }
+
+
+ // //////////////////////////////////////
+ // Clone (action)
+ // //////////////////////////////////////
+
+ // the name of the action in the UI
+ // 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
+ public ToDoItem duplicate(
+ 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) {
+ return toDoItems.newToDo(description, category, subcategory, dueBy, cost);
+ }
+ public String default0Duplicate() {
+ return getDescription() + " - Copy";
+ }
+ public Category default1Duplicate() {
+ return getCategory();
+ }
+ public Subcategory default2Duplicate() {
+ return getSubcategory();
+ }
+ public LocalDate default3Duplicate() {
+ return getDueBy();
+ }
+ public List<Subcategory> choices2Duplicate(
+ final String description, final Category category) {
+ return toDoItems.choices2NewToDo(description, category);
+ }
+ public String validateDuplicate(
+ final String description,
+ final Category category, final Subcategory subcategory,
+ final LocalDate dueBy, final BigDecimal cost) {
+ return toDoItems.validateNewToDo(description, category, subcategory, dueBy, cost);
+ }
+
+ // //////////////////////////////////////
+ // Delete (action)
+ // //////////////////////////////////////
+
+ @Bulk
+ 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();
+ }
+
+
+ // //////////////////////////////////////
+ // totalCost
+ // //////////////////////////////////////
+
+ @ActionSemantics(Of.SAFE)
+ @Bulk(AppliesTo.BULK_ONLY)
+ public BigDecimal totalCost() {
+ BigDecimal total = (BigDecimal) scratchpad.get("runningTotal");
+ if(getCost() != null) {
+ total = total != null ? total.add(getCost()) : getCost();
+ scratchpad.put("runningTotal", total);
+ }
+ return total.setScale(2);
+ }
+
+
+
+ // //////////////////////////////////////
+ // scheduleExplicitly
+ // scheduleImplicitly
+ // //////////////////////////////////////
+
+ @ActionSemantics(Of.IDEMPOTENT)
+ @Prototype
+ public ToDoItem scheduleExplicitly() {
+ backgroundService.execute(this).completeSlowly(2000);
+ container.informUser("Task '" + getDescription() + "' scheduled for completion");
+ return this;
+ }
+
+ // //////////////////////////////////////
+
+ @ActionSemantics(Of.IDEMPOTENT)
+ @Command(executeIn=ExecuteIn.BACKGROUND)
+ @Prototype
+ public ToDoItem scheduleImplicitly() {
+ completeSlowly(3000);
+ return this;
+ }
+
+
+
+ // //////////////////////////////////////
+ // OpenSourceCodeOnGithub (action)
+ // //////////////////////////////////////
+
+ @Prototype
+ @ActionSemantics(Of.SAFE)
+ public URL openSourceCodeOnGithub() throws MalformedURLException {
+ return new URL("https://github.com/apache/isis/tree/master/example/application/${parentArtifactId}/dom/src/main/java/dom/todo/ToDoItem.java");
+ }
+
+
+ // //////////////////////////////////////
+ // Throw exception
+ // //////////////////////////////////////
+
+ static enum DemoExceptionType {
+ RecoverableException,
+ RecoverableExceptionAutoEscalated,
+ NonRecoverableException;
+ }
+
+ @Prototype
+ @ActionSemantics(Of.SAFE)
+ public void demoException(final @Named("Type") DemoExceptionType type) {
+ switch(type) {
+ case NonRecoverableException:
+ throw new NonRecoverableException("Demo throwing " + type.name());
+ case RecoverableException:
+ throw new RecoverableException("Demo throwing " + type.name());
+ case RecoverableExceptionAutoEscalated:
+ try {
+ // this will trigger an exception (because subcategory cannot be null), causing the xactn to be aborted
+ setSubcategory(null);
+ container.flush();
+ } catch(Exception e) {
+ // it's a programming mistake to throw only a recoverable exception here, because of the xactn's state.
+ // the framework should instead auto-escalate this to a non-recoverable exception
+ throw new RecoverableException("Demo throwing " + type.name(), e);
+ }
+ }
+ }
+
+
+ // //////////////////////////////////////
+ // Object-level validation
+ // //////////////////////////////////////
+
+ /**
+ * In a real app, if this were actually a rule, then we'd expect that
+ * invoking the {@link ${symbol_pound}completed() done} action would clear the {@link ${symbol_pound}getDueBy() dueBy}
+ * property (rather than require the user to have to clear manually).
+ */
+ public String validate() {
+ if(isComplete() && getDueBy() != null) {
+ return "Due by date must be set to null if item has been completed";
+ }
+ return null;
+ }
+
+ // //////////////////////////////////////
+ // Programmatic Helpers
+ // //////////////////////////////////////
+
+ private static final long ONE_WEEK_IN_MILLIS = 7 * 24 * 60 * 60 * 1000L;
+
+ @Programmatic // excluded from the framework's metamodel
+ public boolean isDue() {
+ if (getDueBy() == null) {
+ return false;
+ }
+ return !isMoreThanOneWeekInPast(getDueBy());
+ }
+
+ private static boolean isMoreThanOneWeekInPast(final LocalDate dueBy) {
+ return dueBy.toDateTimeAtStartOfDay().getMillis() < Clock.getTime() - ONE_WEEK_IN_MILLIS;
+ }
+
+ // //////////////////////////////////////
+ // Predicates
+ // //////////////////////////////////////
+
+ 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);
+ }
+ };
+ }
+
+ public static Predicate<ToDoItem> thoseCompleted(
+ final boolean completed) {
+ return new Predicate<ToDoItem>() {
+ @Override
+ public boolean apply(final ToDoItem t) {
+ return Objects.equal(t.isComplete(), completed);
+ }
+ };
+ }
+
+ public static Predicate<ToDoItem> thoseWithSimilarDescription(final String description) {
+ return new Predicate<ToDoItem>() {
+ @Override
+ public boolean apply(final ToDoItem t) {
+ return t.getDescription().contains(description);
+ }
+ };
+ }
+
+ @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()));
+ }
+
+ 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);
+ }
+ };
+ }
+
+ 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 Predicate<ToDoItem> thoseCategorised(
+ final Category category, final Subcategory subcategory) {
+ return com.google.common.base.Predicates.and(
+ thoseCategorised(category),
+ thoseSubcategorised(subcategory));
+ }
+
+ }
+
+ // //////////////////////////////////////
+ // toString
+ // //////////////////////////////////////
+
+ @Override
+ public String toString() {
+ return ObjectContracts.toString(this, "description,complete,dueBy,ownedBy");
+ }
+
+ // //////////////////////////////////////
+ // compareTo
+ // //////////////////////////////////////
+
+ /**
+ * 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
+ // //////////////////////////////////////
+
+ @javax.inject.Inject
+ private DomainObjectContainer container;
+
+ @javax.inject.Inject
+ private ToDoItems toDoItems;
+
+ @javax.inject.Inject
+ @SuppressWarnings("unused")
+ private ClockService clockService;
+
+ private Bulk.InteractionContext bulkInteractionContext;
+ public void injectBulkInteractionContext(Bulk.InteractionContext bulkInteractionContext) {
+ this.bulkInteractionContext = bulkInteractionContext;
+ }
+
+ @SuppressWarnings("unused")
+ @javax.inject.Inject
+ private CommandContext commandContext;
+
+ @javax.inject.Inject
+ private BackgroundService backgroundService;
+
+ private Scratchpad scratchpad;
+ public void injectScratchpad(Scratchpad scratchpad) {
+ this.scratchpad = scratchpad;
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/10242866/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.layout.json
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.layout.json b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.layout.json
new file mode 100644
index 0000000..81cdea3
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItem.layout.json
@@ -0,0 +1,177 @@
+/**
+ * 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: {
+ typicalLength: { value: 50 }
+ },
+ category: {
+ disabled: {
+ reason: "Use action to update both category and subcategory"
+ }
+ },
+ subcategory: {
+ disabled: {
+ reason: "Use action to update both category and subcategory"
+ },
+ actions: {
+ updateCategory: {
+ named: {
+ value: "Update"
+ }
+ },
+ analyseCategory: {}
+ }
+ },
+ ownedBy: {
+ hidden: {}
+ },
+ complete: {
+ actions: {
+ completed: {
+ named: { value: "Done" },
+ describedAs: {
+ value: "Mark this todo item as having been completed"
+ },
+ cssClass: { value: "x-highlight" }
+ },
+ scheduleExplicitly: {
+ },
+ scheduleImplicitly: {
+ },
+ notYetCompleted: {
+ named: { value: "Not done" }
+ }
+ },
+ describedAs: {
+ value: "Whether this todo item has been completed"
+ }
+ }
+ }
+ },
+ Misc: {
+ members: {
+ versionSequence: {
+ named: {
+ value: "Version"
+ },
+ disabled: {},
+ hidden: {
+ where: ALL_TABLES
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ span: 6,
+ memberGroups: {
+ Priority: {
+ members: {
+ relativePriority: {
+ actions: {
+ previous: {},
+ next: {}
+ }
+ },
+ dueBy: {
+ cssClass: { value: "x-key" }
+ }
+ }
+ },
+ Other: {
+ members: {
+ cost: {
+ actions: {
+ updateCost:{
+ named: {
+ value: "Update"
+ }
+ }
+ }
+ },
+ notes: {
+ multiLine: {
+ numberOfLines: 5
+ },
+ hidden: {
+ where: ALL_TABLES
+ }
+ },
+ attachment: {
+ hidden: {
+ where: STANDALONE_TABLES
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ span: 0
+ },
+ {
+ span: 6,
+ collections: {
+ dependencies: {
+ disabled: {},
+ actions: {
+ add:{},
+ remove: {
+ cssClass: { value: "x-caution" }
+ }
+ },
+ paged: {
+ value: 5
+ },
+ render: {
+ value: EAGERLY
+ }
+ },
+ similarTo: {
+ disabled: {},
+ paged: {
+ value: 3
+ },
+ render: {
+ value: LAZILY
+ }
+ }
+ }
+ }
+ ],
+ actions: {
+ totalCost: {},
+ delete: {
+ cssClass: { value: "x-caution" }
+ },
+ duplicate: {
+ named: {
+ value: "Clone"
+ },
+ describedAs: {
+ value: "Create a new todo item from this one"
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/10242866/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemChangedPayloadFactory.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemChangedPayloadFactory.java b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemChangedPayloadFactory.java
new file mode 100644
index 0000000..7c03f19
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemChangedPayloadFactory.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 dom.todo;
+
+import org.apache.isis.applib.annotation.PublishedObject.ChangeKind;
+import org.apache.isis.applib.annotation.PublishedObject.PayloadFactory;
+import org.apache.isis.applib.services.publish.EventPayload;
+import org.apache.isis.applib.services.publish.EventPayloadForObjectChanged;
+
+public class ToDoItemChangedPayloadFactory implements PayloadFactory{
+
+ public static class ToDoItemPayload extends EventPayloadForObjectChanged<ToDoItem> {
+
+ public ToDoItemPayload(ToDoItem changed) {
+ super(changed);
+ }
+
+ /**
+ * Expose the item's {@link ToDoItem${symbol_pound}getDescription() description} more explicitly
+ * in the payload.
+ */
+ public String getDescription() {
+ return getChanged().getDescription();
+ }
+ }
+ @Override
+ public EventPayload payloadFor(Object changedObject, ChangeKind changeKind) {
+ return new ToDoItemPayload((ToDoItem) changedObject);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/10242866/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemContributions.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemContributions.java b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemContributions.java
new file mode 100644
index 0000000..816b9d8
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItemContributions.java
@@ -0,0 +1,258 @@
+#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 java.util.concurrent.Callable;
+
+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.Optional;
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.applib.query.QueryDefault;
+import org.apache.isis.applib.services.queryresultscache.QueryResultsCache;
+
+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) // ie contributed as association
+ @Hidden(where=Where.ALL_TABLES)
+ @Disabled(reason="Relative priority, derived from due date")
+ public Integer relativePriority(final ToDoItem toDoItem) {
+ return queryResultsCache.execute(new Callable<Integer>(){
+ @Override
+ public Integer call() throws Exception {
+ 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;
+ }}, ToDoItemContributions.class, "relativePriority", toDoItem);
+ }
+
+
+ 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) // ie contributed as action
+ public ToDoItem next(final ToDoItem item) {
+ final Integer priority = relativePriority(item);
+ if(priority == null) {
+ return item;
+ }
+ int priorityOfNext = priority != null ? priority + 1 : 0;
+ return itemWithPriorityElse(priorityOfNext, item);
+ }
+ public String disableNext(final ToDoItem toDoItem) {
+ if (toDoItem.isComplete()) {
+ return "Completed";
+ }
+ if(next(toDoItem) == null) {
+ return "No next item";
+ }
+ return null;
+ }
+
+ // //////////////////////////////////////
+
+ @DescribedAs("The previous item not yet completed")
+ @NotInServiceMenu
+ @ActionSemantics(Of.SAFE)
+ @NotContributed(As.ASSOCIATION) // ie contributed as action
+ public ToDoItem previous(final ToDoItem item) {
+ final Integer priority = relativePriority(item);
+ if(priority == null) {
+ return item;
+ }
+ int priorityOfPrevious = priority != null? priority - 1 : 0;
+ return itemWithPriorityElse(priorityOfPrevious, item);
+ }
+ public String disablePrevious(final ToDoItem toDoItem) {
+ if (toDoItem.isComplete()) {
+ return "Completed";
+ }
+ if(previous(toDoItem) == null) {
+ return "No previous item";
+ }
+ return null;
+ }
+
+ // //////////////////////////////////////
+
+ /**
+ * @param priority : 1-based priority
+ */
+ private ToDoItem itemWithPriorityElse(int priority, final ToDoItem itemElse) {
+ if(priority < 1) {
+ return null;
+ }
+ final List<ToDoItem> items = sortedNotYetComplete();
+ if(priority > items.size()) {
+ return null;
+ }
+ return priority>=0 && items.size()>=priority? items.get(priority-1): itemElse;
+ }
+
+ // //////////////////////////////////////
+ // SimilarTo (contributed collection)
+ // //////////////////////////////////////
+
+ @NotInServiceMenu
+ @ActionSemantics(Of.SAFE)
+ @NotContributed(As.ACTION)
+ public List<ToDoItem> similarTo(final ToDoItem toDoItem) {
+ final List<ToDoItem> similarToDoItems = allMatches(
+ new QueryDefault<ToDoItem>(ToDoItem.class,
+ "findByOwnedByAndCategory",
+ "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)
+ // //////////////////////////////////////
+
+ @DescribedAs("Update category and subcategory")
+ @NotInServiceMenu
+ @ActionSemantics(Of.IDEMPOTENT)
+ public ToDoItem updateCategory(
+ final ToDoItem item,
+ final @Named("Category") Category category,
+ final @Optional @Named("Subcategory") Subcategory subcategory) {
+ item.setCategory(category);
+ item.setSubcategory(subcategory);
+ return item;
+ }
+
+ public Category default1UpdateCategory(
+ final ToDoItem item) {
+ return item != null? item.getCategory(): null;
+ }
+ public Subcategory default2UpdateCategory(
+ final ToDoItem item) {
+ return item != null? item.getSubcategory(): null;
+ }
+
+ 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();
+ }
+
+
+ // //////////////////////////////////////
+ // Injected services
+ // //////////////////////////////////////
+
+ @javax.inject.Inject
+ private ToDoItems toDoItems;
+
+ @javax.inject.Inject
+ private QueryResultsCache queryResultsCache;
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/10242866/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItems.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItems.java b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItems.java
new file mode 100644
index 0000000..fdc9ade
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/java/dom/todo/ToDoItems.java
@@ -0,0 +1,260 @@
+#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.math.BigDecimal;
+import java.util.List;
+
+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.DomainObjectContainer;
+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.Optional;
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.annotation.RegEx;
+import org.apache.isis.applib.query.QueryDefault;
+import org.apache.isis.applib.services.clock.ClockService;
+
+@Named("ToDos")
+public class ToDoItems {
+
+ public ToDoItems() {
+ }
+
+ // //////////////////////////////////////
+ // Identification in the UI
+ // //////////////////////////////////////
+
+ public String getId() {
+ return "toDoItems";
+ }
+
+ public String iconName() {
+ return "ToDoItem";
+ }
+
+ // //////////////////////////////////////
+ // NotYetComplete (action)
+ // //////////////////////////////////////
+
+ @Bookmarkable
+ @ActionSemantics(Of.SAFE)
+ @MemberOrder(sequence = "1")
+ public List<ToDoItem> notYetComplete() {
+ final List<ToDoItem> items = notYetCompleteNoUi();
+ if(items.isEmpty()) {
+ container.informUser("All to-do items have been completed :-)");
+ }
+ return items;
+ }
+
+ @Programmatic
+ public List<ToDoItem> notYetCompleteNoUi() {
+ return container.allMatches(
+ new QueryDefault<ToDoItem>(ToDoItem.class,
+ "findByOwnedByAndCompleteIsFalse",
+ "ownedBy", currentUserName()));
+ }
+
+
+ // //////////////////////////////////////
+ // Complete (action)
+ // //////////////////////////////////////
+
+ @ActionSemantics(Of.SAFE)
+ @MemberOrder(sequence = "3")
+ public List<ToDoItem> complete() {
+ final List<ToDoItem> items = completeNoUi();
+ if(items.isEmpty()) {
+ container.informUser("No to-do items have yet been completed :-(");
+ }
+ return items;
+ }
+
+ @Programmatic
+ public List<ToDoItem> completeNoUi() {
+ return container.allMatches(
+ new QueryDefault<ToDoItem>(ToDoItem.class,
+ "findByOwnedByAndCompleteIsTrue",
+ "ownedBy", currentUserName()));
+ }
+
+
+ // //////////////////////////////////////
+ // categorized (action)
+ // //////////////////////////////////////
+
+ @SuppressWarnings("unchecked")
+ @Bookmarkable
+ @ActionSemantics(Of.SAFE)
+ @MemberOrder(sequence = "30")
+ public List<ToDoItem> categorized(
+ @Named("Category") final Category category,
+ @Named("Subcategory") final Subcategory subcategory,
+ @Named("Completed?") final boolean completed) {
+ // an example "naive" implementation (filtered in Java code, not DBMS)
+ return container.allMatches(ToDoItem.class,
+ Predicates.and(
+ ToDoItem.Predicates.thoseOwnedBy(currentUserName()),
+ ToDoItem.Predicates.thoseCompleted(completed),
+ ToDoItem.Predicates.thoseCategorised(category, subcategory)));
+ }
+ public Category default0Categorized() {
+ return Category.Professional;
+ }
+ public Subcategory default1Categorized() {
+ return default0Categorized().subcategories().get(0);
+ }
+ public boolean default2Categorized() {
+ return false;
+ }
+ public List<Subcategory> choices1Categorized(
+ final Category category) {
+ return Subcategory.listFor(category);
+ }
+ public String validateCategorized(
+ final Category category,
+ final Subcategory subcategory,
+ final boolean completed) {
+ return Subcategory.validate(category, subcategory);
+ }
+
+
+ // //////////////////////////////////////
+ // NewToDo (action)
+ // //////////////////////////////////////
+
+ @MemberOrder(sequence = "40")
+ public ToDoItem newToDo(
+ 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) {
+ return newToDo(description, category, subcategory, currentUserName(), 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 String validateNewToDo(
+ final String description,
+ final Category category, final Subcategory subcategory,
+ final LocalDate dueBy, final BigDecimal cost) {
+ return Subcategory.validate(category, subcategory);
+ }
+
+ // //////////////////////////////////////
+ // AllToDos (action)
+ // //////////////////////////////////////
+
+ // findByOwnedBy
+
+ @ActionSemantics(Of.SAFE)
+ @MemberOrder(sequence = "50")
+ public List<ToDoItem> allToDos() {
+ final List<ToDoItem> items = container.allMatches(
+ new QueryDefault<ToDoItem>(ToDoItem.class,
+ "findByOwnedBy",
+ "ownedBy", currentUserName()));
+ 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) {
+ return container.allMatches(
+ new QueryDefault<ToDoItem>(ToDoItem.class,
+ "findByOwnedByAndDescriptionContains",
+ "ownedBy", currentUserName(),
+ "description", description));
+ }
+
+ // //////////////////////////////////////
+ // Programmatic Helpers
+ // //////////////////////////////////////
+
+ @Programmatic // for use by fixtures
+ public ToDoItem newToDo(
+ final String description,
+ final Category category,
+ 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);
+
+ container.persist(toDoItem);
+ container.flush();
+
+ return toDoItem;
+ }
+
+ private String currentUserName() {
+ return container.getUser().getName();
+ }
+
+
+ // //////////////////////////////////////
+ // Injected Services
+ // //////////////////////////////////////
+
+ @javax.inject.Inject
+ private DomainObjectContainer container;
+
+ @javax.inject.Inject
+ private ClockService clockService;
+
+ // //////////////////////////////////////
+
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/10242866/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/resources/images/Dashboard.png
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/resources/images/Dashboard.png b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/resources/images/Dashboard.png
new file mode 100644
index 0000000..c22ab2b
Binary files /dev/null and b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/resources/images/Dashboard.png differ
http://git-wip-us.apache.org/repos/asf/isis/blob/10242866/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem-done.png
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem-done.png b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem-done.png
new file mode 100644
index 0000000..b0fc6e8
Binary files /dev/null and b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem-done.png differ
http://git-wip-us.apache.org/repos/asf/isis/blob/10242866/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem-todo.png
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem-todo.png b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem-todo.png
new file mode 100644
index 0000000..99a9fed
Binary files /dev/null and b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem-todo.png differ
http://git-wip-us.apache.org/repos/asf/isis/blob/10242866/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem.png
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem.png b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem.png
new file mode 100644
index 0000000..99a9fed
Binary files /dev/null and b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/main/resources/images/ToDoItem.png differ
http://git-wip-us.apache.org/repos/asf/isis/blob/10242866/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/test/java/dom/todo/ToDoTest_completed.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/test/java/dom/todo/ToDoTest_completed.java b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/test/java/dom/todo/ToDoTest_completed.java
new file mode 100644
index 0000000..235c164
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/archetype/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.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.nullValue;
+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);
+
+ Bulk.InteractionContext interactionContext = Bulk.InteractionContext.regularAction(toDoItem);
+ toDoItem.injectBulkInteractionContext(interactionContext);
+ }
+
+ @Test
+ public void happyCase() throws Exception {
+ // given
+ assertThat(toDoItem.disableCompleted(), is(nullValue()));
+
+ // when
+ toDoItem.completed();
+
+ // then
+ assertThat(toDoItem.isComplete(), is(true));
+ assertThat(toDoItem.disableCompleted(), is(not(nullValue())));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/10242866/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/test/java/dom/todo/ToDoTest_notYetCompleted.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/dom/src/test/java/dom/todo/ToDoTest_notYetCompleted.java b/example/archetype/quickstart_wicket_restful_jdo/archetype/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/archetype/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/10242866/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/fixture/.gitignore
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/fixture/.gitignore b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/fixture/.gitignore
new file mode 100644
index 0000000..a48e45b
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/fixture/.gitignore
@@ -0,0 +1 @@
+/target-ide
http://git-wip-us.apache.org/repos/asf/isis/blob/10242866/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/fixture/pom.xml
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/fixture/pom.xml b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/fixture/pom.xml
new file mode 100644
index 0000000..1872775
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/fixture/pom.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>${groupId}</groupId>
+ <artifactId>${rootArtifactId}</artifactId>
+ <version>${version}</version>
+ </parent>
+
+ <artifactId>${artifactId}</artifactId>
+ <name>Quickstart Wicket/Restful/JDO Fixtures</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>${rootArtifactId}-dom</artifactId>
+ </dependency>
+ </dependencies>
+
+</project>
http://git-wip-us.apache.org/repos/asf/isis/blob/10242866/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/fixture/src/main/java/fixture/todo/ToDoItemsFixture.java
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/fixture/src/main/java/fixture/todo/ToDoItemsFixture.java b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/fixture/src/main/java/fixture/todo/ToDoItemsFixture.java
new file mode 100644
index 0000000..818bfab
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/fixture/src/main/java/fixture/todo/ToDoItemsFixture.java
@@ -0,0 +1,105 @@
+#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.math.BigDecimal;
+
+import dom.todo.ToDoItem;
+import dom.todo.ToDoItem.Category;
+import dom.todo.ToDoItem.Subcategory;
+import dom.todo.ToDoItems;
+
+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() {
+
+ 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(ownedBy);
+
+ getContainer().flush();
+ }
+
+ private void installFor(String user) {
+
+ 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();
+ }
+
+
+ // //////////////////////////////////////
+
+ 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) {
+ final LocalDate date = new LocalDate(Clock.getTimeAsDateTime());
+ return date.plusDays(i);
+ }
+
+
+ // //////////////////////////////////////
+ // Injected services
+ // //////////////////////////////////////
+
+ @javax.inject.Inject
+ private ToDoItems toDoItems;
+
+ @javax.inject.Inject
+ private IsisJdoSupport isisJdoSupport;
+
+}
http://git-wip-us.apache.org/repos/asf/isis/blob/10242866/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/integtests/logging.properties
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/integtests/logging.properties b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/integtests/logging.properties
new file mode 100644
index 0000000..f49afbf
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/integtests/logging.properties
@@ -0,0 +1,104 @@
+#set( $symbol_pound = '#' )
+#set( $symbol_dollar = '$' )
+#set( $symbol_escape = '\' )
+${symbol_pound} Licensed to the Apache Software Foundation (ASF) under one
+${symbol_pound} or more contributor license agreements. See the NOTICE file
+${symbol_pound} distributed with this work for additional information
+${symbol_pound} regarding copyright ownership. The ASF licenses this file
+${symbol_pound} to you under the Apache License, Version 2.0 (the
+${symbol_pound} "License"); you may not use this file except in compliance
+${symbol_pound} with the License. You may obtain a copy of the License at
+${symbol_pound}
+${symbol_pound} http://www.apache.org/licenses/LICENSE-2.0
+${symbol_pound}
+${symbol_pound} Unless required by applicable law or agreed to in writing,
+${symbol_pound} software distributed under the License is distributed on an
+${symbol_pound} "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+${symbol_pound} KIND, either express or implied. See the License for the
+${symbol_pound} specific language governing permissions and limitations
+${symbol_pound} under the License.
+
+
+${symbol_pound}
+${symbol_pound} Isis uses log4j is used to provide system logging
+${symbol_pound}
+log4j.rootCategory=INFO, Console
+
+${symbol_pound} The console appender
+log4j.appender.Console=org.apache.log4j.ConsoleAppender
+log4j.appender.Console.target=System.out
+log4j.appender.Console.layout=org.apache.log4j.PatternLayout
+log4j.appender.Console.layout.ConversionPattern=%d{ABSOLUTE} [%-20c{1} %-10t %-5p] %m%n
+
+log4j.appender.File=org.apache.log4j.RollingFileAppender
+log4j.appender.File.file=isis.log
+log4j.appender.File.append=false
+log4j.appender.File.layout=org.apache.log4j.PatternLayout
+log4j.appender.File.layout.ConversionPattern=%d [%-20c{1} %-10t %-5p] %m%n
+
+! turn on the internal log4j debugging flag so we can see what it is doing
+${symbol_pound}log4j.debug=true
+
+${symbol_pound} DataNucleus
+${symbol_pound} the first two log the DML and DDL (if set to DEBUG)
+log4j.logger.DataNucleus.Datastore.Native=WARN, Console
+log4j.logger.DataNucleus.Datastore.Schema=DEBUG, Console
+${symbol_pound} the remainder can probably be left to WARN
+log4j.logger.DataNucleus.Persistence=WARN, Console
+log4j.logger.DataNucleus.Transaction=WARN, Console
+log4j.logger.DataNucleus.Connection=WARN, Console
+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.Persist=WARN, Console
+log4j.logger.DataNucleus.Datastore.Retrieve=WARN, Console
+log4j.logger.DataNucleus.General=WARN, Console
+log4j.logger.DataNucleus.Lifecycle=WARN, Console
+log4j.logger.DataNucleus.ValueGeneration=WARN, Console
+log4j.logger.DataNucleus.Enhancer=WARN, Console
+log4j.logger.DataNucleus.SchemaTool=ERROR, Console
+log4j.logger.DataNucleus.JDO=WARN, Console
+log4j.logger.DataNucleus.JPA=ERROR, Console
+log4j.logger.DataNucleus.JCA=WARN, Console
+log4j.logger.DataNucleus.IDE=ERROR, Console
+
+log4j.additivity.DataNucleus.Datastore.Native=false
+log4j.additivity.DataNucleus.Datastore.Schema=false
+log4j.additivity.DataNucleus.Datastore.Persistence=false
+log4j.additivity.DataNucleus.Datastore.Transaction=false
+log4j.additivity.DataNucleus.Datastore.Connection=false
+log4j.additivity.DataNucleus.Datastore.Query=false
+log4j.additivity.DataNucleus.Datastore.Cache=false
+log4j.additivity.DataNucleus.Datastore.MetaData=false
+log4j.additivity.DataNucleus.Datastore.Datastore=false
+log4j.additivity.DataNucleus.Datastore.Datastore.Persist=false
+log4j.additivity.DataNucleus.Datastore.Datastore.Retrieve=false
+log4j.additivity.DataNucleus.Datastore.General=false
+log4j.additivity.DataNucleus.Datastore.Lifecycle=false
+log4j.additivity.DataNucleus.Datastore.ValueGeneration=false
+log4j.additivity.DataNucleus.Datastore.Enhancer=false
+log4j.additivity.DataNucleus.Datastore.SchemaTool=false
+log4j.additivity.DataNucleus.Datastore.JDO=false
+log4j.additivity.DataNucleus.Datastore.JPA=false
+log4j.additivity.DataNucleus.Datastore.JCA=false
+log4j.additivity.DataNucleus.Datastore.IDE=false
+
+
+
+
+${symbol_pound} if using log4jdbc-remix as JDBC driver
+${symbol_pound}log4j.logger.jdbc.sqlonly=DEBUG, sql, Console
+${symbol_pound}log4j.additivity.jdbc.sqlonly=false
+${symbol_pound}log4j.logger.jdbc.resultsettable=DEBUG, jdbc, Console
+${symbol_pound}log4j.additivity.jdbc.resultsettable=false
+
+${symbol_pound}log4j.logger.jdbc.audit=WARN,jdbc, Console
+${symbol_pound}log4j.additivity.jdbc.audit=false
+${symbol_pound}log4j.logger.jdbc.resultset=WARN,jdbc
+${symbol_pound}log4j.additivity.jdbc.resultset=false
+${symbol_pound}log4j.logger.jdbc.sqltiming=WARN,sqltiming
+${symbol_pound}log4j.additivity.jdbc.sqltiming=false
+${symbol_pound}log4j.logger.jdbc.connection=FATAL,connection
+${symbol_pound}log4j.additivity.jdbc.connection=false
+
http://git-wip-us.apache.org/repos/asf/isis/blob/10242866/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/integtests/pom.xml
----------------------------------------------------------------------
diff --git a/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/integtests/pom.xml b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/integtests/pom.xml
new file mode 100644
index 0000000..93dbfee
--- /dev/null
+++ b/example/archetype/quickstart_wicket_restful_jdo/archetype/src/main/resources/archetype-resources/integtests/pom.xml
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>${groupId}</groupId>
+ <artifactId>${rootArtifactId}</artifactId>
+ <version>${version}</version>
+ </parent>
+
+ <artifactId>${artifactId}</artifactId>
+ <name>Quickstart Wicket/Restful/JDO Integration Tests</name>
+
+ <build>
+ <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>
+
+ <!-- other modules in this project -->
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>${rootArtifactId}-fixture</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.isis.core</groupId>
+ <artifactId>isis-core-unittestsupport</artifactId>
+ </dependency>
+
+ <dependency>
+ <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>