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 2015/03/03 21:23:11 UTC

[19/20] isis git commit: Merge commit 'f7284d8fb4fbe58479e819b37e7ee3cc731d57ad' into ISIS-789a

http://git-wip-us.apache.org/repos/asf/isis/blob/e2dffa84/mothballed/example/application/todoapp/integtests/src/test/java/integration/tests/ToDoItemIntegTest.java
----------------------------------------------------------------------
diff --cc mothballed/example/application/todoapp/integtests/src/test/java/integration/tests/ToDoItemIntegTest.java
index 5bb2f0f,0000000..f71b6ea
mode 100644,000000..100644
--- a/mothballed/example/application/todoapp/integtests/src/test/java/integration/tests/ToDoItemIntegTest.java
+++ b/mothballed/example/application/todoapp/integtests/src/test/java/integration/tests/ToDoItemIntegTest.java
@@@ -1,1057 -1,0 +1,1057 @@@
 +/*
 + *  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 dom.todo.ToDoItem;
 +import dom.todo.ToDoItemSubscriptions;
 +import dom.todo.ToDoItems;
 +import fixture.todo.scenarios.ToDoItemsRecreateAndCompleteSeveral;
 +
 +import java.math.BigDecimal;
 +import java.nio.charset.Charset;
 +import java.util.EventObject;
 +import java.util.List;
 +import javax.activation.MimeType;
 +import javax.inject.Inject;
 +import org.hamcrest.Description;
 +import org.hamcrest.Matcher;
 +import org.hamcrest.TypeSafeMatcher;
 +import org.jmock.Expectations;
 +import org.jmock.Sequence;
 +import org.jmock.auto.Mock;
 +import org.joda.time.LocalDate;
 +import org.junit.After;
 +import org.junit.Before;
 +import org.junit.Test;
 +import org.apache.isis.applib.NonRecoverableException;
 +import org.apache.isis.applib.RecoverableException;
 +import org.apache.isis.applib.clock.Clock;
 +import org.apache.isis.applib.fixturescripts.FixtureScripts;
 +import org.apache.isis.applib.services.clock.ClockService;
 +import org.apache.isis.applib.services.eventbus.AbstractInteractionEvent;
 +import org.apache.isis.applib.services.eventbus.ActionDomainEvent;
 +import org.apache.isis.applib.services.eventbus.CollectionDomainEvent;
 +import org.apache.isis.applib.services.eventbus.EventBusService;
 +import org.apache.isis.applib.services.eventbus.PropertyDomainEvent;
 +import org.apache.isis.applib.value.Blob;
 +
 +import static org.hamcrest.CoreMatchers.containsString;
 +import static org.hamcrest.CoreMatchers.equalTo;
 +import static org.hamcrest.CoreMatchers.is;
 +import static org.hamcrest.CoreMatchers.not;
 +import static org.hamcrest.CoreMatchers.notNullValue;
 +import static org.hamcrest.CoreMatchers.nullValue;
 +import static org.junit.Assert.assertThat;
 +
 +public class ToDoItemIntegTest extends AbstractToDoIntegTest {
 +
 +    ToDoItemsRecreateAndCompleteSeveral fixtureScript;
 +
 +    @Before
 +    public void setUpData() throws Exception {
-         fixtureScript = new ToDoItemsRecreateAndCompleteSeveral();
++    	fixtureScript = new ToDoItemsRecreateAndCompleteSeveral();
 +        fixtureScripts.runFixtureScript(fixtureScript, null);
 +    }
 +
 +    @Inject
 +    FixtureScripts fixtureScripts;
 +    @Inject
 +    ToDoItems toDoItems;
 +    @Inject
 +    ToDoItemSubscriptions toDoItemSubscriptions;
 +
 +    ToDoItem toDoItem;
 +
 +    @Before
 +    public void setUp() throws Exception {
 +        final List<ToDoItem> all = toDoItems.notYetComplete();
 +        toDoItem = wrap(all.get(0));
 +    }
 +
 +    @After
 +    public void tearDown() throws Exception {
 +        toDoItemSubscriptions.reset();
 +    }
 +
 +
 +    public static class Title extends ToDoItemIntegTest {
 +
 +        private LocalDate dueBy;
 +
 +        @Before
 +        public void setUp() throws Exception {
 +            super.setUp();
 +            final List<ToDoItem> all = wrap(toDoItems).notYetComplete();
 +            toDoItem = wrap(all.get(0));
 +
 +            toDoItem = wrap(fixtureScript.lookup("to-do-items-recreate-and-complete-several/to-do-item-for-buy-bread/item-1", ToDoItem.class));
 +            assertThat(toDoItem, is(not(nullValue())));
 +
 +            nextTransaction();
 +
 +            dueBy = toDoItem.getDueBy();
 +        }
 +
 +
 +        @Test
 +        public void includesDescription() throws Exception {
 +
 +            // given
 +            assertThat(container().titleOf(toDoItem), containsString("Buy bread due by"));
 +
 +            // when
 +            unwrap(toDoItem).setDescription("Buy bread and butter");
 +
 +            // then
 +            assertThat(container().titleOf(toDoItem), containsString("Buy bread and butter due by"));
 +        }
 +
 +        @Test
 +        public void includesDueDateIfAny() throws Exception {
 +
 +            // given
 +            assertThat(container().titleOf(toDoItem), containsString("due by " + dueBy.toString("yyyy-MM-dd")));
 +
 +            // when
 +            final LocalDate fiveDaysFromNow = Clock.getTimeAsLocalDate().plusDays(5);
 +            unwrap(toDoItem).setDueBy(fiveDaysFromNow);
 +
 +            // then
 +            assertThat(container().titleOf(toDoItem), containsString("due by " + fiveDaysFromNow.toString("yyyy-MM-dd")));
 +        }
 +
 +
 +        @Test
 +        public void ignoresDueDateIfNone() throws Exception {
 +
 +            // when
 +            // (since wrapped, will call clearDueBy)
 +            toDoItem.setDueBy(null);
 +
 +            // then
 +            assertThat(container().titleOf(toDoItem), not(containsString("due by")));
 +        }
 +
 +        @Test
 +        public void usesWhetherCompleted() throws Exception {
 +
 +            // given
 +            assertThat(container().titleOf(toDoItem), not(containsString("Completed!")));
 +
 +            // when
 +            toDoItem.completed();
 +
 +            // then
 +            assertThat(container().titleOf(toDoItem), not(containsString("due by")));
 +            assertThat(container().titleOf(toDoItem), containsString("Buy bread - Completed!"));
 +        }
 +    }
 +
 +    public static class Actions {
 +
 +        public static class Completed extends ToDoItemIntegTest {
 +
 +            @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();
 +
 +                // and then
 +                final EventObject ev = toDoItemSubscriptions.mostRecentlyReceivedEvent(EventObject.class);
 +                assertThat(ev, is(nullValue()));
 +            }
 +
 +
 +            @Test
 +            public void cannotSetPropertyDirectly() throws Exception {
 +
 +                // given
 +
 +                // when, then should fail
 +                expectedExceptions.expectMessage("Always disabled");
 +                toDoItem.setComplete(true);
 +
 +                // and then
 +                final EventObject ev = toDoItemSubscriptions.mostRecentlyReceivedEvent(EventObject.class);
 +                assertThat(ev, is(nullValue()));
 +            }
 +
 +            @Test
 +            public void subscriberReceivesEvents() throws Exception {
 +
 +                // given
 +                toDoItemSubscriptions.reset();
 +                assertThat(toDoItemSubscriptions.getSubscriberBehaviour(), is(ToDoItemSubscriptions.Behaviour.AnyExecuteAccept));
 +                assertThat(unwrap(toDoItem).isComplete(), is(false));
 +
 +                // when
 +                toDoItem.completed();
 +
 +                // then
 +                assertThat(unwrap(toDoItem).isComplete(), is(true));
 +
 +                // and then
 +                final List<ToDoItem.CompletedEvent> receivedEvents = toDoItemSubscriptions.receivedEvents(ToDoItem.CompletedEvent.class);
 +
 +                // hide, disable, validate, executing, executed
 +                // sent to both the general on(ActionInteractionEvent ev)
 +                // and also the specific on(final ToDoItem.CompletedEvent ev)
 +                assertThat(receivedEvents.size(), is(5*2));
 +                final ToDoItem.CompletedEvent ev = receivedEvents.get(0);
 +
 +                ToDoItem source = ev.getSource();
 +                assertThat(source, is(equalTo(unwrap(toDoItem))));
 +                assertThat(ev.getIdentifier().getMemberName(), is("completed"));
 +            }
 +
 +            @Test
 +            public void subscriberVetoesEventWithRecoverableException() throws Exception {
 +
 +                // given
 +                toDoItemSubscriptions.subscriberBehaviour(ToDoItemSubscriptions.Behaviour.AnyExecuteVetoWithRecoverableException);
 +
 +                // then
 +                expectedExceptions.expect(RecoverableException.class);
 +
 +                // when
 +                toDoItem.completed();
 +            }
 +
 +            @Test
 +            public void subscriberVetoesEventWithNonRecoverableException() throws Exception {
 +
 +                // given
 +                toDoItemSubscriptions.subscriberBehaviour(ToDoItemSubscriptions.Behaviour.AnyExecuteVetoWithNonRecoverableException);
 +
 +                // then
 +                expectedExceptions.expect(NonRecoverableException.class);
 +
 +                // when
 +                toDoItem.completed();
 +            }
 +
 +            @Test
 +            public void subscriberVetoesEventWithAnyOtherException() throws Exception {
 +
 +                // given
 +                toDoItemSubscriptions.subscriberBehaviour(ToDoItemSubscriptions.Behaviour.AnyExecuteVetoWithOtherException);
 +
 +                // then
 +                expectedExceptions.expect(RuntimeException.class);
 +
 +                // when
 +                toDoItem.completed();
 +            }
 +
 +        }
 +
 +        /**
 +         * This test demonstrates how a single service can be replaced, eg to use a mock.
 +         */
 +        public static class Completed_withMockService extends ToDoItemIntegTest {
 +
 +            private EventBusService originalEventBusService;
 +            @Mock
 +            private EventBusService mockEventBusService;
 +
 +            @Before
 +            public void setUpMockEventBusService() throws Exception {
 +                originalEventBusService = scenarioExecution().service(EventBusService.class);
 +
 +                context.checking(new Expectations() {{
 +                    ignoring(mockEventBusService).register(with(any(Object.class)));
 +                    ignoring(mockEventBusService).unregister(with(any(Object.class)));
 +                }});
 +
 +                scenarioExecution().replaceService(originalEventBusService, mockEventBusService);
 +                scenarioExecution().closeSession();
 +                scenarioExecution().openSession();
 +
 +                final List<ToDoItem> all = toDoItems.notYetComplete();
 +                toDoItem = wrap(all.get(0));
 +            }
 +
 +
 +            @After
 +            public void reinstateOriginalEventBusService() throws Exception {
 +                scenarioExecution().replaceService(mockEventBusService, originalEventBusService);
 +            }
 +
 +            @Test
 +            public void raisesEvent() throws Exception {
 +
 +                final Sequence busRulesThenExec = context.sequence("busRulesThenExec");
 +                // then
 +                context.checking(new Expectations() {{
 +                    oneOf(mockEventBusService).post(with(completedEvent(AbstractInteractionEvent.Phase.HIDE)));
 +                    inSequence(busRulesThenExec);
 +                    oneOf(mockEventBusService).post(with(completedEvent(AbstractInteractionEvent.Phase.DISABLE)));
 +                    inSequence(busRulesThenExec);
 +                    oneOf(mockEventBusService).post(with(completedEvent(AbstractInteractionEvent.Phase.VALIDATE)));
 +                    inSequence(busRulesThenExec);
 +                    oneOf(mockEventBusService).post(with(completedEvent(AbstractInteractionEvent.Phase.EXECUTING)));
 +                    inSequence(busRulesThenExec);
 +                    oneOf(mockEventBusService).post(with(completedEvent(AbstractInteractionEvent.Phase.EXECUTED)));
 +                    inSequence(busRulesThenExec);
 +                }});
 +
 +                // when
 +                toDoItem.completed();
 +            }
 +
 +            private Matcher<Object> completedEvent(final AbstractInteractionEvent.Phase phase) {
 +                return new TypeSafeMatcher<Object>() {
 +                    @Override
 +                    protected boolean matchesSafely(Object item) {
 +                        if (!(item instanceof ToDoItem.CompletedEvent)) {
 +                            return false;
 +                        }
 +
 +                        final ToDoItem.CompletedEvent completedEvent = (ToDoItem.CompletedEvent) item;
 +                        return completedEvent.getPhase() == phase;
 +
 +                    }
 +
 +                    @Override
 +                    public void describeTo(Description description) {
 +                        description.appendText(" instance of a ToDoItem.CompletedEvent, " + phase);
 +                    }
 +                };
 +            }
 +        }
 +
 +
 +        public static class Duplicate extends ToDoItemIntegTest {
 +
 +            ToDoItem duplicateToDoItem;
 +
 +            @Inject
 +            private ClockService clockService;
 +
 +            @Test
 +            public void happyCase() throws Exception {
 +
 +                // given
 +                final LocalDate todaysDate = clockService.now();
 +                toDoItem.setDueBy(todaysDate);
 +                toDoItem.updateCost(new BigDecimal("123.45"));
 +
 +                duplicateToDoItem = toDoItem.duplicate(
 +                        unwrap(toDoItem).default0Duplicate(),
 +                        unwrap(toDoItem).default1Duplicate(),
 +                        unwrap(toDoItem).default2Duplicate(),
 +                        unwrap(toDoItem).default3Duplicate(),
 +                        new BigDecimal("987.65"));
 +
 +                // then
 +                assertThat(duplicateToDoItem.getDescription(), is(toDoItem.getDescription() + " - Copy"));
 +                assertThat(duplicateToDoItem.getCategory(), is(toDoItem.getCategory()));
 +                assertThat(duplicateToDoItem.getDueBy(), is(todaysDate));
 +                assertThat(duplicateToDoItem.getCost(), is(new BigDecimal("987.65")));
 +            }
 +        }
 +
 +        public static class NotYetCompleted extends ToDoItemIntegTest {
 +
 +            @Test
 +            public void happyCase() throws Exception {
 +
 +                // given
 +                unwrap(toDoItem).setComplete(true);
 +
 +                // when
 +                toDoItem.notYetCompleted();
 +
 +                // then
 +                assertThat(toDoItem.isComplete(), is(false));
 +            }
 +
 +            @Test
 +            public void cannotUndoIfNotYetCompleted() throws Exception {
 +
 +                // given
 +                assertThat(toDoItem.isComplete(), is(false));
 +
 +                // when, then should fail
 +                expectedExceptions.expectMessage("Not yet completed");
 +                toDoItem.notYetCompleted();
 +            }
 +
 +            /**
 +             * Even though {@link dom.todo.ToDoItem#notYetCompleted()} is not annotated with
 +             * {@link org.apache.isis.applib.annotation.ActionInteraction}, an event is still raised.
 +             */
 +            @Test
 +            public void subscriberReceivesEvent() throws Exception {
 +
 +                // given
 +                assertThat(toDoItemSubscriptions.getSubscriberBehaviour(), is(ToDoItemSubscriptions.Behaviour.AnyExecuteAccept));
 +                unwrap(toDoItem).setComplete(true);
 +
 +                // when
 +                toDoItem.notYetCompleted();
 +
 +                // then
 +                assertThat(unwrap(toDoItem).isComplete(), is(false));
 +
 +                // and then
 +                final ActionDomainEvent<ToDoItem> ev = toDoItemSubscriptions.mostRecentlyReceivedEvent(ActionDomainEvent.class);
 +                assertThat(ev, is(not(nullValue())));
 +
 +                ToDoItem source = ev.getSource();
 +                assertThat(source, is(equalTo(unwrap(toDoItem))));
 +                assertThat(ev.getIdentifier().getMemberName(), is("notYetCompleted"));
 +            }
 +        }
 +    }
 +
 +    public static class Collections {
 +
 +        public static class Dependencies {
 +            public static class Add extends ToDoItemIntegTest {
 +
 +                private ToDoItem otherToDoItem;
 +
 +                @Before
 +                public void setUp() throws Exception {
 +                    super.setUp();
 +                    final List<ToDoItem> items = wrap(toDoItems).notYetComplete();
 +                    otherToDoItem = wrap(items.get(1));
 +                }
 +
 +                @After
 +                public void tearDown() throws Exception {
 +                    unwrap(toDoItem).getDependencies().clear();
 +                    super.tearDown();
 +                }
 +
 +                @Test
 +                public void happyCase() throws Exception {
 +
 +                    // given
 +                    assertThat(toDoItem.getDependencies().size(), is(0));
 +
 +                    // when
 +                    toDoItem.add(otherToDoItem);
 +
 +                    // then
 +                    assertThat(toDoItem.getDependencies().size(), is(1));
 +                    assertThat(toDoItem.getDependencies().iterator().next(), is(unwrap(otherToDoItem)));
 +                }
 +
 +
 +                @Test
 +                public void cannotDependOnSelf() throws Exception {
 +
 +                    // then
 +                    expectedExceptions.expectMessage("Can't set up a dependency to self");
 +
 +                    // when
 +                    toDoItem.add(toDoItem);
 +                }
 +
 +                @Test
 +                public void cannotAddIfComplete() throws Exception {
 +
 +                    // given
 +                    unwrap(toDoItem).setComplete(true);
 +
 +                    // then
 +                    expectedExceptions.expectMessage("Cannot add dependencies for items that are complete");
 +
 +                    // when
 +                    toDoItem.add(otherToDoItem);
 +                }
 +
 +
 +                @Test
 +                public void subscriberReceivesEvent() throws Exception {
 +
 +                    // given
 +                    toDoItemSubscriptions.reset();
 +
 +                    // when
 +                    toDoItem.add(otherToDoItem);
 +
 +                    // then received events
 +                    @SuppressWarnings("unchecked")
 +                    final List<EventObject> receivedEvents = toDoItemSubscriptions.receivedEvents();
 +
 +                    assertThat(receivedEvents.size(), is(7));
 +                    assertThat(receivedEvents.get(0) instanceof ActionDomainEvent, is(true)); // ToDoItem#add() executed
 +                    assertThat(receivedEvents.get(1) instanceof CollectionDomainEvent, is(true)); // ToDoItem#dependencies add, executed
 +                    assertThat(receivedEvents.get(2) instanceof CollectionDomainEvent, is(true)); // ToDoItem#dependencies add, executing
 +                    assertThat(receivedEvents.get(3) instanceof ActionDomainEvent, is(true)); // ToDoItem#add executing
 +                    assertThat(receivedEvents.get(4) instanceof ActionDomainEvent, is(true)); // ToDoItem#add validate
 +                    assertThat(receivedEvents.get(5) instanceof ActionDomainEvent, is(true)); // ToDoItem#add disable
 +                    assertThat(receivedEvents.get(6) instanceof ActionDomainEvent, is(true)); // ToDoItem#add hide
 +
 +                    // inspect the collection interaction (posted programmatically in ToDoItem#add)
 +                    final CollectionDomainEvent<ToDoItem,ToDoItem> ciEv = (CollectionDomainEvent<ToDoItem, ToDoItem>) toDoItemSubscriptions.mostRecentlyReceivedEvent(CollectionDomainEvent.class);
 +                    assertThat(ciEv, is(notNullValue()));
 +
 +                    assertThat(ciEv.getSource(), is(equalTo(unwrap(toDoItem))));
 +                    assertThat(ciEv.getIdentifier().getMemberName(), is("dependencies"));
 +                    assertThat(ciEv.getOf(), is(CollectionDomainEvent.Of.ADD_TO));
 +                    assertThat(ciEv.getValue(), is(unwrap(otherToDoItem)));
 +
 +                    // inspect the action interaction (posted declaratively by framework)
 +                    final ActionDomainEvent<ToDoItem> aiEv = (ActionDomainEvent<ToDoItem>) toDoItemSubscriptions.mostRecentlyReceivedEvent(ActionDomainEvent.class);
 +                    assertThat(aiEv, is(notNullValue()));
 +
 +                    assertThat(aiEv.getSource(), is(equalTo(unwrap(toDoItem))));
 +                    assertThat(aiEv.getIdentifier().getMemberName(), is("add"));
 +                    assertThat(aiEv.getArguments().size(), is(1));
 +                    assertThat(aiEv.getArguments().get(0), is(unwrap((Object)otherToDoItem)));
 +                    assertThat(aiEv.getCommand(), is(notNullValue()));
 +                }
 +
 +                @Test
 +                public void subscriberVetoesEventWithRecoverableException() throws Exception {
 +
 +                    // given
 +                    toDoItemSubscriptions.subscriberBehaviour(ToDoItemSubscriptions.Behaviour.AnyExecuteVetoWithRecoverableException);
 +
 +                    // then
 +                    expectedExceptions.expect(RecoverableException.class);
 +
 +                    // when
 +                    toDoItem.add(otherToDoItem);
 +                }
 +
 +                @Test
 +                public void subscriberVetoesEventWithNonRecoverableException() throws Exception {
 +
 +                    // given
 +                    toDoItemSubscriptions.subscriberBehaviour(ToDoItemSubscriptions.Behaviour.AnyExecuteVetoWithNonRecoverableException);
 +
 +                    // then
 +                    expectedExceptions.expect(NonRecoverableException.class);
 +
 +                    // when
 +                    toDoItem.add(otherToDoItem);
 +                }
 +
 +                @Test
 +                public void subscriberVetoesEventWithAnyOtherException() throws Exception {
 +
 +                    // given
 +                    toDoItemSubscriptions.subscriberBehaviour(ToDoItemSubscriptions.Behaviour.AnyExecuteVetoWithOtherException);
 +
 +                    // then
 +                    expectedExceptions.expect(RuntimeException.class);
 +
 +                    // when
 +                    toDoItem.add(otherToDoItem);
 +                }
 +            }
 +            public static class Remove extends ToDoItemIntegTest {
 +
 +                private ToDoItem otherToDoItem;
 +                private ToDoItem yetAnotherToDoItem;
 +
 +                @Before
 +                public void setUp() throws Exception {
 +                    super.setUp();
 +                    final List<ToDoItem> items = wrap(toDoItems).notYetComplete();
 +                    otherToDoItem = wrap(items.get(1));
 +                    yetAnotherToDoItem = wrap(items.get(2));
 +
 +                    toDoItem.add(otherToDoItem);
 +                }
 +
 +                @After
 +                public void tearDown() throws Exception {
 +                    unwrap(toDoItem).getDependencies().clear();
 +                    super.tearDown();
 +                }
 +
 +                @Test
 +                public void happyCase() throws Exception {
 +
 +                    // given
 +                    assertThat(toDoItem.getDependencies().size(), is(1));
 +
 +                    // when
 +                    toDoItem.remove(otherToDoItem);
 +
 +                    // then
 +                    assertThat(toDoItem.getDependencies().size(), is(0));
 +                }
 +
 +
 +                @Test
 +                public void cannotRemoveItemIfNotADependency() throws Exception {
 +
 +                    // then
 +                    expectedExceptions.expectMessage("Not a dependency");
 +
 +                    // when
 +                    toDoItem.remove(yetAnotherToDoItem);
 +                }
 +
 +                @Test
 +                public void cannotRemoveDependencyIfComplete() throws Exception {
 +
 +                    // given
 +                    unwrap(toDoItem).setComplete(true);
 +
 +                    // then
 +                    expectedExceptions.expectMessage("Cannot remove dependencies for items that are complete");
 +
 +                    // when
 +                    toDoItem.remove(otherToDoItem);
 +                }
 +
 +                @Test
 +                public void subscriberVetoesEventWithRecoverableException() throws Exception {
 +
 +                    // given
 +                    toDoItemSubscriptions.subscriberBehaviour(ToDoItemSubscriptions.Behaviour.AnyExecuteVetoWithRecoverableException);
 +
 +                    // then
 +                    expectedExceptions.expect(RecoverableException.class);
 +
 +                    // when
 +                    toDoItem.remove(otherToDoItem);
 +                }
 +
 +                @Test
 +                public void subscriberVetoesEventWithNonRecoverableException() throws Exception {
 +
 +                    // given
 +                    toDoItemSubscriptions.subscriberBehaviour(ToDoItemSubscriptions.Behaviour.AnyExecuteVetoWithNonRecoverableException);
 +
 +                    // then
 +                    expectedExceptions.expect(NonRecoverableException.class);
 +
 +                    // when
 +                    toDoItem.remove(otherToDoItem);
 +                }
 +
 +                @Test
 +                public void subscriberVetoesEventWithAnyOtherException() throws Exception {
 +
 +                    // given
 +                    toDoItemSubscriptions.subscriberBehaviour(ToDoItemSubscriptions.Behaviour.AnyExecuteVetoWithOtherException);
 +
 +                    // then
 +                    expectedExceptions.expect(RuntimeException.class);
 +
 +                    // when
 +                    toDoItem.remove(otherToDoItem);
 +                }
 +            }
 +        }
 +
 +    }
 +
 +    public static class Properties {
 +
 +        public static class Attachment extends ToDoItemIntegTest {
 +
 +            @Test
 +            public void happyCase() throws Exception {
 +
 +                byte[] bytes = "{\"foo\": \"bar\"}".getBytes(Charset.forName("UTF-8"));
 +                final Blob newAttachment = new Blob("myfile.json", new MimeType("application/json"), bytes);
 +
 +                // when
 +                toDoItem.setAttachment(newAttachment);
 +
 +                // then
 +                assertThat(toDoItem.getAttachment(), is(newAttachment));
 +            }
 +
 +            @Test
 +            public void canBeNull() throws Exception {
 +
 +                // when
 +                toDoItem.setAttachment((Blob)null);
 +
 +                // then
 +                assertThat(toDoItem.getAttachment(), is((Blob)null));
 +            }
 +        }
 +
 +        public static class Category extends ToDoItemIntegTest {
 +
 +            @Test
 +            public void cannotModify() throws Exception {
 +
 +                // when, then
 +                expectedExceptions.expectMessage(containsString("Reason: Use action to update both category and subcategory."));
 +                toDoItem.setCategory(ToDoItem.Category.Professional);
 +            }
 +        }
 +
 +        public static class Cost extends ToDoItemIntegTest {
 +
 +            private BigDecimal cost;
 +
 +            @Before
 +            public void setUp() throws Exception {
 +                super.setUp();
 +                cost = toDoItem.getCost();
 +            }
 +
 +            @Test
 +            public void happyCaseUsingProperty() throws Exception {
 +
 +                final BigDecimal newCost = new BigDecimal("123.45");
 +
 +                // when
 +                toDoItem.updateCost(newCost);
 +
 +                // then
 +                assertThat(toDoItem.getCost(), is(newCost));
 +            }
 +
 +            @Test
 +            public void happyCaseUsingAction() throws Exception {
 +
 +                final BigDecimal newCost = new BigDecimal("123.45");
 +
 +                // when
 +                toDoItem.updateCost(newCost);
 +
 +                // then
 +                assertThat(toDoItem.getCost(), is(newCost));
 +            }
 +
 +            @Test
 +            public void canBeNull() throws Exception {
 +
 +                // when
 +                toDoItem.updateCost((BigDecimal)null);
 +
 +                // then
 +                assertThat(toDoItem.getCost(), is((BigDecimal)null));
 +            }
 +
 +            @Test
 +            public void defaultForAction() throws Exception {
 +
 +                // then
 +                assertThat(unwrap(toDoItem).default0UpdateCost(), is(cost));
 +            }
 +
 +        }
 +
 +        public static class Description extends ToDoItemIntegTest {
 +
 +            @Test
 +            public void happyCase() throws Exception {
 +
 +                // given
 +                assertThat(toDoItem.getDescription(), is("Buy bread"));
 +
 +                // when
 +                toDoItem.setDescription("Buy bread and butter");
 +
 +                // then
 +                assertThat(toDoItem.getDescription(), is("Buy bread and butter"));
 +            }
 +
 +
 +            @Test
 +            public void failsRegex() throws Exception {
 +
 +                // when
 +                expectedExceptions.expectMessage("Doesn't match pattern");
 +                toDoItem.setDescription("exclamation marks are not allowed!!!");
 +            }
 +
 +            @Test
 +            public void cannotBeNull() throws Exception {
 +
 +                // when, then
 +                expectedExceptions.expectMessage("Mandatory");
 +                toDoItem.setDescription(null);
 +            }
 +
 +            @Test
 +            public void cannotUseModify() throws Exception {
 +
 +                expectedExceptions.expectMessage("Cannot invoke supporting method for 'Description'; use only property accessor/mutator");
 +
 +                // given
 +                assertThat(toDoItem.getDescription(), is("Buy bread"));
 +
 +                // when
 +                toDoItem.modifyDescription("Buy bread and butter");
 +
 +                // then
 +                assertThat(toDoItem.getDescription(), is("Buy bread"));
 +            }
 +
 +            @Test
 +            public void cannotUseClear() throws Exception {
 +
 +                expectedExceptions.expectMessage("Cannot invoke supporting method for 'Description'; use only property accessor/mutator");
 +
 +                // given
 +                assertThat(toDoItem.getDescription(), is("Buy bread"));
 +
 +                // when
 +                toDoItem.clearDescription();
 +
 +                // then
 +                assertThat(toDoItem.getDescription(), is("Buy bread"));
 +            }
 +
 +
 +            @Test
 +            public void onlyJustShortEnough() throws Exception {
 +
 +                // when, then
 +                toDoItem.setDescription(characters(100));
 +            }
 +
 +            @Test
 +            public void tooLong() throws Exception {
 +
 +                // then
 +                expectedExceptions.expectMessage("The value proposed exceeds the maximum length of 100");
 +
 +                // when
 +                toDoItem.setDescription(characters(101));
 +            }
 +
 +
 +            @Test
 +            public void subscriberReceivesEvent() throws Exception {
 +
 +                // given
 +                assertThat(toDoItemSubscriptions.getSubscriberBehaviour(), is(ToDoItemSubscriptions.Behaviour.AnyExecuteAccept));
 +                assertThat(toDoItem.getDescription(), is("Buy bread"));
 +
 +                // when
 +                toDoItem.setDescription("Buy bread and butter");
 +
 +                // then published and received
 +                @SuppressWarnings("unchecked")
 +                final PropertyDomainEvent<ToDoItem,String> ev = toDoItemSubscriptions.mostRecentlyReceivedEvent(PropertyDomainEvent.class);
 +                assertThat(ev, is(not(nullValue())));
 +
 +                ToDoItem source = ev.getSource();
 +                assertThat(source, is(equalTo(unwrap(toDoItem))));
 +                assertThat(ev.getIdentifier().getMemberName(), is("description"));
 +                assertThat(ev.getOldValue(), is("Buy bread"));
 +                assertThat(ev.getNewValue(), is("Buy bread and butter"));
 +            }
 +
 +            @Test
 +            public void subscriberVetoesEventWithRecoverableException() throws Exception {
 +
 +                // given
 +                toDoItemSubscriptions.subscriberBehaviour(ToDoItemSubscriptions.Behaviour.AnyExecuteVetoWithRecoverableException);
 +
 +                // then
 +                expectedExceptions.expect(RecoverableException.class);
 +
 +                // when
 +                toDoItem.setDescription("Buy bread and butter");
 +            }
 +
 +
 +            @Test
 +            public void subscriberVetoesEventWithNonRecoverableException() throws Exception {
 +
 +                // given
 +                toDoItemSubscriptions.subscriberBehaviour(ToDoItemSubscriptions.Behaviour.AnyExecuteVetoWithNonRecoverableException);
 +
 +                // then
 +                expectedExceptions.expect(NonRecoverableException.class);
 +
 +                // when
 +                toDoItem.setDescription("Buy bread and butter");
 +            }
 +
 +
 +            @Test
 +            public void subscriberVetoesEventWithAnyOtherException() throws Exception {
 +
 +                // given
 +                toDoItemSubscriptions.subscriberBehaviour(ToDoItemSubscriptions.Behaviour.AnyExecuteVetoWithOtherException);
 +
 +                // then
 +                expectedExceptions.expect(RuntimeException.class);
 +
 +                // when
 +                toDoItem.setDescription("Buy bread and butter");
 +            }
 +
 +
 +            private static String characters(final int n) {
 +                StringBuffer buf = new StringBuffer();
 +                for(int i=0; i<n; i++) {
 +                    buf.append("a");
 +                }
 +                return buf.toString();
 +            }
 +        }
 +
 +        public static class DueBy extends ToDoItemIntegTest {
 +
 +            @Inject
 +            private ClockService clockService;
 +
 +            @Test
 +            public void happyCase() throws Exception {
 +
 +                // when
 +                final LocalDate fiveDaysFromNow = clockService.now().plusDays(5);
 +                toDoItem.setDueBy(fiveDaysFromNow);
 +
 +                // then
 +                assertThat(toDoItem.getDueBy(), is(fiveDaysFromNow));
 +            }
 +
 +
 +            @Test
 +            public void canBeNull() throws Exception {
 +
 +                // when
 +                toDoItem.setDueBy((LocalDate)null);
 +
 +                // then
 +                assertThat(toDoItem.getDueBy(), is((LocalDate)null));
 +            }
 +
 +            @Test
 +            public void canBeUpToSixDaysInPast() throws Exception {
 +
 +                final LocalDate nowAsLocalDate = clockService.now();
 +                final LocalDate sixDaysAgo = nowAsLocalDate.plusDays(-5);
 +
 +                // when
 +                toDoItem.setDueBy(sixDaysAgo);
 +
 +                // then
 +                assertThat(toDoItem.getDueBy(), is(sixDaysAgo));
 +            }
 +
 +
 +            @Test
 +            public void cannotBeMoreThanSixDaysInPast() throws Exception {
 +
 +                final LocalDate sevenDaysAgo = Clock.getTimeAsLocalDate().plusDays(-7);
 +
 +                // when, then
 +                expectedExceptions.expectMessage("Due by date cannot be more than one week old");
 +                toDoItem.setDueBy(sevenDaysAgo);
 +            }
 +        }
 +
 +        public static class Notes extends ToDoItemIntegTest {
 +
 +            @Test
 +            public void happyCase() throws Exception {
 +
 +                final String newNotes = "Lorem ipsum yada yada";
 +
 +                // when
 +                toDoItem.setNotes(newNotes);
 +
 +                // then
 +                assertThat(toDoItem.getNotes(), is(newNotes));
 +            }
 +
 +            @Test
 +            public void canBeNull() throws Exception {
 +
 +                // when
 +                toDoItem.setNotes((String)null);
 +
 +                // then
 +                assertThat(toDoItem.getNotes(), is((String)null));
 +            }
 +
 +            @Test
 +            public void suscriberReceivedDefaultEvent() throws Exception {
 +
 +                final String newNotes = "Lorem ipsum yada yada";
 +
 +                // when
 +                toDoItem.setNotes(newNotes);
 +
 +                // then
 +                assertThat(unwrap(toDoItem).getNotes(), is(newNotes));
 +
 +                // and then receive the default event.
 +                @SuppressWarnings("unchecked")
 +                final PropertyDomainEvent.Default ev = toDoItemSubscriptions.mostRecentlyReceivedEvent(PropertyDomainEvent.Default.class);
 +                assertThat(ev, is(notNullValue()));
 +
 +                assertThat(ev.getSource(), is((Object)unwrap(toDoItem)));
 +                assertThat(ev.getNewValue(), is((Object)newNotes));
 +            }
 +
 +
 +        }
 +
 +        public static class OwnedBy extends ToDoItemIntegTest {
 +
 +            @Test
 +            public void cannotModify() throws Exception {
 +
 +                // when, then
 +                expectedExceptions.expectMessage("Reason: Hidden on Everywhere. Identifier: dom.todo.ToDoItem#ownedBy()");
 +                toDoItem.setOwnedBy("other");
 +            }
 +
 +
 +        }
 +
 +        public static class Subcategory extends ToDoItemIntegTest {
 +
 +            @Test
 +            public void cannotModify() throws Exception {
 +
 +                // when, then
 +                expectedExceptions.expectMessage(containsString("Reason: Use action to update both category and subcategory."));
 +                toDoItem.setSubcategory(ToDoItem.Subcategory.Chores);
 +            }
 +        }
 +
 +    }
 +
 +
 +
 +
 +}

http://git-wip-us.apache.org/repos/asf/isis/blob/e2dffa84/mothballed/example/application/todoapp/webapp/pom.xml
----------------------------------------------------------------------
diff --cc mothballed/example/application/todoapp/webapp/pom.xml
index 785d17e,0000000..1dca6f3
mode 100644,000000..100644
--- a/mothballed/example/application/todoapp/webapp/pom.xml
+++ b/mothballed/example/application/todoapp/webapp/pom.xml
@@@ -1,352 -1,0 +1,352 @@@
 +<?xml version="1.0" encoding="UTF-8"?>
 +<!--
 +  Licensed to the Apache Software Foundation (ASF) under one
 +  or more contributor license agreements.  See the NOTICE file
 +  distributed with this work for additional information
 +  regarding copyright ownership.  The ASF licenses this file
 +  to you under the Apache License, Version 2.0 (the
 +  "License"); you may not use this file except in compliance
 +  with the License.  You may obtain a copy of the License at
 +  
 +         http://www.apache.org/licenses/LICENSE-2.0
 +         
 +  Unless required by applicable law or agreed to in writing,
 +  software distributed under the License is distributed on an
 +  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 +  KIND, either express or implied.  See the License for the
 +  specific language governing permissions and limitations
 +  under the License.
 +--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 +    <modelVersion>4.0.0</modelVersion>
 +
 +    <parent>
 +        <groupId>org.apache.isis.example.application</groupId>
 +        <artifactId>todoapp</artifactId>
 +        <version>1.9.0-SNAPSHOT</version>
 +    </parent>
 +
 +    <artifactId>todoapp-webapp</artifactId>
 +    <name>ToDo App Webapp</name>
 +
 +    <description>This module runs both the Wicket viewer and the Restfulobjects viewer in a single webapp configured to run using the datanucleus object store.</description>
 +
 +    <packaging>war</packaging>
 +
 +    <properties>
 +        <siteBaseDir>..</siteBaseDir>
 +    </properties>
 +    
 +    <build>
 +        <plugins>
 +            <plugin>
 +                <groupId>org.mortbay.jetty</groupId>
 +                <artifactId>maven-jetty-plugin</artifactId>
 +            </plugin>
 +
 +            <!-- mvn package -->
 +            <plugin>
 +                <groupId>org.simplericity.jettyconsole</groupId>
 +                <artifactId>jetty-console-maven-plugin</artifactId>
 +                <executions>
 +                    <execution>
 +                        <goals>
 +                            <goal>createconsole</goal>
 +                        </goals>
 +                        <configuration>
 +                            <backgroundImage>${basedir}/src/main/jettyconsole/isis-banner.png</backgroundImage>
 +                            <destinationFile>${project.build.directory}/${project.build.finalName}-jetty-console.jar</destinationFile>
 +                        </configuration>
 +                        <phase>package</phase>
 +                    </execution>
 +                </executions>
 +            </plugin>
 +
 +            <plugin>
 +                <groupId>org.codehaus.mojo</groupId>
 +                <artifactId>build-helper-maven-plugin</artifactId>
 +                <version>1.8</version>
 +                  <executions>
 +                    <execution>
 +                      <phase>validate</phase>
 +                      <goals>
 +                        <goal>maven-version</goal>
 +                      </goals>
 +                    </execution>
 +                  </executions>
 +            </plugin>
 +
 +            <plugin>
 +                <artifactId>maven-war-plugin</artifactId>
 +                <configuration>
 +                    <warName>todoapp</warName>
 +                    <archive>
 +                        <manifest>
 +                            <addClasspath>false</addClasspath>
 +                        </manifest>
 +                        <manifestEntries>
 +                            <Build-Time>${maven.build.timestamp}</Build-Time>
 +                            <Build-Host>${agent.name}</Build-Host>
 +                            <Build-User>${user.name}</Build-User>
 +                            <Build-Maven>Maven ${maven.version}</Build-Maven>
 +                            <Build-Java>${java.version}</Build-Java>
 +                            <Build-OS>${os.name}</Build-OS>
 +                            <Build-Label>${project.version}</Build-Label>
 +                        </manifestEntries>
 +                    </archive>
 +                </configuration>
 +            </plugin>
 +
 +        </plugins>
 +        <pluginManagement>
 +            <plugins>
 +                <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
 +                <plugin>
 +                    <groupId>org.eclipse.m2e</groupId>
 +                    <artifactId>lifecycle-mapping</artifactId>
 +                    <version>1.0.0</version>
 +                    <configuration>
 +                        <lifecycleMappingMetadata>
 +                            <pluginExecutions>
 +                                <pluginExecution>
 +                                    <pluginExecutionFilter>
 +                                        <groupId>
 +                                            org.codehaus.mojo
 +                                        </groupId>
 +                                        <artifactId>
 +                                            build-helper-maven-plugin
 +                                        </artifactId>
 +                                        <versionRange>
 +                                            [1.5,)
 +                                        </versionRange>
 +                                        <goals>
 +                                            <goal>maven-version</goal>
 +                                        </goals>
 +                                    </pluginExecutionFilter>
 +                                    <action>
 +                                        <ignore></ignore>
 +                                    </action>
 +                                </pluginExecution>
 +                            </pluginExecutions>
 +                        </lifecycleMappingMetadata>
 +                    </configuration>
 +                </plugin>
 +            </plugins>
 +        </pluginManagement>
 +    </build>
 +
 +    <dependencies>
 +    
 +        <!-- other modules in this project -->
 +        <dependency>
 +            <groupId>${project.groupId}</groupId>
 +            <artifactId>todoapp-dom</artifactId>
 +            <exclusions>
 +                <exclusion>
 +                    <!-- so don't pick up transitive dependency to asm 4.0.0 -->
 +                    <groupId>org.datanucleus</groupId>
 +                    <artifactId>datanucleus-enhancer</artifactId>
 +                </exclusion>
 +            </exclusions>
 +        </dependency>
 +        <dependency>
 +            <groupId>${project.groupId}</groupId>
 +            <artifactId>todoapp-fixture</artifactId>
 +            <exclusions>
 +                <exclusion>
 +                    <!-- so don't pick up transitive dependency to asm 4.0.0 -->
 +                    <groupId>org.datanucleus</groupId>
 +                    <artifactId>datanucleus-enhancer</artifactId>
 +                </exclusion>
 +            </exclusions>
 +        </dependency>
 +        
 +        <!-- other isis components -->
 +        <dependency>
 +            <groupId>org.apache.isis.viewer</groupId>
 +            <artifactId>isis-viewer-wicket-impl</artifactId>
 +        </dependency>
 +        <dependency>
 +            <groupId>org.apache.isis.core</groupId>
 +            <artifactId>isis-core-viewer-restfulobjects-server</artifactId>
 +        </dependency>
 +        <dependency>
 +            <groupId>org.apache.isis.core</groupId>
 +            <artifactId>isis-core-security-shiro</artifactId>
 +        </dependency>
 +
 +
 +        <!-- isis core -->
 +        <dependency>
 +            <groupId>org.apache.isis.core</groupId>
 +            <artifactId>isis-core-runtime</artifactId>
 +        </dependency>
 +        <dependency>
 +            <groupId>org.apache.isis.core</groupId>
 +            <artifactId>isis-core-wrapper</artifactId>
 +        </dependency>
 +        <dependency>
 +            <groupId>org.apache.isis.core</groupId>
 +            <artifactId>isis-core-security</artifactId>
 +        </dependency>
 +
 +
 +        <!-- to run using WebServer (optional) -->
 +        <dependency>
 +            <groupId>org.apache.isis.core</groupId>
 +            <artifactId>isis-core-webserver</artifactId>
 +            <scope>runtime</scope>
 +            <optional>true</optional>
 +        </dependency>
 +
 +
 +        <dependency>
 +            <groupId>org.apache.geronimo.specs</groupId>
 +            <artifactId>geronimo-servlet_2.5_spec</artifactId>
 +            <!--
 +            removed so can run o.a.i.WebServer from within IntelliJ;
 +            can rely on servlet container to ignore this in war file
 +            <scope>provided</scope>
 +            -->
 +        </dependency>
 +
 +        <!-- 
 +          JDBC drivers 
 +          (for jdo objectstore)
 +          -->
 +        <dependency>
 +            <groupId>org.hsqldb</groupId>
 +            <artifactId>hsqldb</artifactId>
 +        </dependency>
 +
 +        <!-- 
 +        <dependency>
 +            <groupId>postgresql</groupId>
 +            <artifactId>postgresql</artifactId>
 +            <version>9.1-901.jdbc4</version>
 +        </dependency>
 +         -->
 +
 +        <!-- 
 +        mvn install:install-file -Dfile=sqljdbc4.jar \
 +                                 -DgroupId=com.microsoft.sqlserver \
 +                                 -DartifactId=jdbc \
 +                                 -Dversion=4.0 \
 +                                 -Dpackaging=jar
 +         -->
 +         <!-- 
 +        <dependency>
 +            <groupId>com.microsoft.sqlserver</groupId>
 +            <artifactId>sqljdbc4</artifactId>
 +            <version>4.0</version>
 +        </dependency>
 +          -->
 +
 +        <dependency>
 +          <groupId>org.lazyluke</groupId>
 +          <artifactId>log4jdbc-remix</artifactId>
 +          <exclusions>
 +            <exclusion>
 +              <groupId>org.slf4j</groupId>
 +              <artifactId>slf4j-api</artifactId>
 +            </exclusion>
 +          </exclusions>
 +        </dependency>
 +
 +    </dependencies>
 +
 +    <profiles>
 +        <profile>
 +            <id>self-host</id>
 +            <build>
 +                <plugins>
 +                    <!-- 
 +                    mvn -P self-host antrun:run
 +                    -->
 +                    <plugin>
 +                        <groupId>org.apache.maven.plugins</groupId>
 +                        <artifactId>maven-antrun-plugin</artifactId>
 +                        <configuration>
 +                            <tasks>
 +                                <exec executable="java" failonerror="true">
 +                                    <arg value="-jar" />
 +                                    <arg value="${project.build.directory}/${project.build.finalName}-jetty-console.jar" />
 +                                </exec>
 +                            </tasks>
 +                        </configuration>
 +                    </plugin>
 +                </plugins>
 +            </build>
 +        </profile>
 +
 +        <profile>
 +            <id>jrebel</id>
 +            <properties>
 +                <!-- as used in the rebel.xml in the dom project -->
 +                <target.dir>target</target.dir>
 +                <isis-jrebel-plugin.packagePrefix>dom.todo,org.apache.isis.objectstore.jdo.applib</isis-jrebel-plugin.packagePrefix>
 +                <isis-jrebel-plugin.loggingLevel>warn</isis-jrebel-plugin.loggingLevel>
 +            </properties>
 +            <build>
 +                <plugins>
 +                    <!--
 +                    mvn -P jrebel antrun:run \
 +                        -Djrebel.jar="C:/Users/Dan/.IdeaIC13/config/plugins/jr-ide-idea/lib/jrebel/jrebel.jar" \
 +                        -Disis_jrebel_plugin.jar="C:/github/danhaywood/isis-jrebel-plugin/target/danhaywood-isis-jrebel-plugin-1.0.0-SNAPSHOT.jar"
 +                    -->
 +                    <plugin>
 +                        <groupId>org.apache.maven.plugins</groupId>
 +                        <artifactId>maven-antrun-plugin</artifactId>
 +                        <configuration>
 +                            <target>
 +                                <property name="compile_classpath" refid="maven.compile.classpath"/>
 +                                <property name="runtime_classpath" refid="maven.runtime.classpath"/>
 +                                <property name="test_classpath" refid="maven.test.classpath"/>
 +                                <property name="plugin_classpath" refid="maven.plugin.classpath"/>
 +
 +                                <echo message=""/>
 +                                <echo message=""/>
 +                                <echo message="jrebel.jar             = ${jrebel.jar}"/>
 +                                <echo message="isis_jrebel_plugin.jar = ${isis_jrebel_plugin.jar}"/>
 +                                <echo message="target.dir             = ${target.dir}"/>
 +                                <echo message=""/>
 +                                <echo message=""/>
 +
 +                                <exec executable="java" failonerror="true">
 +                                    <arg value="-javaagent:${jrebel.jar}"/>
 +                                    <arg value="-Drebel.log=false"/>
 +                                    <arg value="-Drebel.check_class_hash=true"/>
 +                                    <arg value="-Drebel.packages_exclude=org.apache.isis"/>
 +
 +                                    <!-- as used in the rebel.xml in the dom project -->
 +                                    <arg value="-Dproject.root=${project.basedir}/.."/>
 +                                    <arg value="-Dtarget.dir=${target.dir}"/>
 +
 +                                    <arg value="-Drebel.plugins=${isis_jrebel_plugin.jar}"/>
 +                                    <arg value="-Disis-jrebel-plugin.packagePrefix=${isis-jrebel-plugin.packagePrefix}"/>
 +                                    <arg value="-Disis-jrebel-plugin.loggingLevel=${isis-jrebel-plugin.loggingLevel}"/>
 +                                    <arg value="-XX:MaxPermSize=128m"/>
 +                                    <arg value="-classpath"/>
 +                                    <arg value="${runtime_classpath}"/>
 +                                    <arg value="org.apache.isis.WebServer"/>
 +                                </exec>
 +                            </target>
 +                        </configuration>
 +                    </plugin>
 +                </plugins>
 +            </build>
 +        </profile>
 +        <profile>
-             <id>neo4j</id>
-             <dependencies>
-                 <dependency>
-                     <groupId>org.datanucleus</groupId>
-                     <artifactId>datanucleus-neo4j</artifactId>
-                     <version>3.2.3</version>
-                 </dependency>
-             </dependencies>
++        	<id>neo4j</id>
++        	<dependencies>
++		        <dependency>
++		        	<groupId>org.datanucleus</groupId>
++		        	<artifactId>datanucleus-neo4j</artifactId>
++		        	<version>4.0.4</version>
++		        </dependency>
++        	</dependencies>
 +        </profile>
 +    </profiles>
 +
 +
 +
 +</project>

http://git-wip-us.apache.org/repos/asf/isis/blob/e2dffa84/mothballed/example/application/todoapp/webapp/src/main/webapp/WEB-INF/isis.properties
----------------------------------------------------------------------
diff --cc mothballed/example/application/todoapp/webapp/src/main/webapp/WEB-INF/isis.properties
index f3366a7,0000000..e22a282
mode 100644,000000..100644
--- a/mothballed/example/application/todoapp/webapp/src/main/webapp/WEB-INF/isis.properties
+++ b/mothballed/example/application/todoapp/webapp/src/main/webapp/WEB-INF/isis.properties
@@@ -1,290 -1,0 +1,290 @@@
 +#  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.
 +
 +
 +#################################################################################
 +#
 +# specify system components.
 +#
 +# The values correspond to the named components in the installer-registry.properties file
 +# in the org.apache.isis.core:isis-core-runtime JAR (in the org.apache.isis.core.runtime package)
 +#
 +# Although all configuration could reside in isis.properties, the recommendation is
 +# to split out into component specific files:
 +# 
 +#    xxx_yyy.properties files
 +#
 +# where
 +#    * xxx is the component type, and
 +#    * yyy is the component name.
 +#
 +# For example, viewer_wicket.properties holds configuration information specific to the Wicket viewer.
 +#
 +#################################################################################
 +
 +
 +#
 +# configure the persistor (object store) to use
 +#
 +
 +# JDO/DataNucleus objectstore
 +isis.persistor=datanucleus
 +
 +
 +
 +#
 +# configure authentication mechanism to use (to logon to the system)
 +#
 + 
 +#isis.authentication=bypass
 +isis.authentication=shiro
 +
 +
 +#
 +# configure authorization mechanism to use
 +#
 + 
 +#isis.authorization=bypass
 +isis.authorization=shiro
 +
 +
 +
 +
 +
 +#################################################################################
 +#
 +# MetaModel
 +#
 +# The metamodel typically does not require additional configuration, although
 +# the system components (defined above) may refine the metamodel for their needs.
 +#
 +#################################################################################
 +
 +
 +#
 +# Additional programming model facet factories, or remove standard facet factories.
 +# Comma separated list of fully qualified class names.
 +#
 +#isis.reflector.facets.include=
 +#isis.reflector.facets.exclude=
 +
 +
 +#
 +# Metamodel validation (in addition to that automatically performed by the programming model facet factories)
 +# Default implementation does nothing.
 +#
 +# Use a custom implementation to enforce additional constraints specific to your app/project/company.
 +#
 +#isis.reflector.validator=org.apache.isis.core.metamodel.metamodelvalidator.dflt.MetaModelValidatorDefault
 +
 +
 +
 +#
 +# Whether to allow deprecated annotations/method prefixes (otherwise raise metamodel validation errors).
 +# If not specified, default is to allow.
 +#
 +#isis.reflector.validator.allowDeprecated=false
 +
 +
 +
 +#
 +# Implementation to use for reading dynamic layout.  Default implementation reads Xxx.layout.json files from classpath.
 +#
 +#isis.reflector.layoutMetadataReaders=org.apache.isis.core.metamodel.layoutmetadata.json.LayoutMetadataReaderFromJson
 +
 +
 +
 +#
 +# patterns for applying CssClassFa facet (font-awesome icons), matching on action names
 +#
 +isis.reflector.facet.cssClassFa.patterns=\
 +                        new.*:fa-plus,\
 +                        add.*:fa-plus-square,\
 +                        create.*:fa-plus,\
 +                        update.*:fa-edit,\
 +                        change.*:fa-edit,\
 +                        remove.*:fa-minus-square,\
 +                        move.*:fa-exchange,\
 +                        first.*:fa-star,\
 +                        find.*:fa-search,\
 +                        lookup.*:fa-search,\
 +                        clear.*:fa-remove,\
 +                        previous.*:fa-step-backward,\
 +                        next.*:fa-step-forward,\
 +                        list.*:fa-list, \
 +                        all.*:fa-list, \
 +                        download.*:fa-download, \
 +                        upload.*:fa-upload, \
 +                        execute.*:fa-bolt, \
 +                        run.*:fa-bolt, \
 +                        calculate.*:fa-calculator, \
 +                        verify.*:fa-check-circle, \
 +                        refresh.*:fa-refresh, \
 +                        install.*:fa-wrench
 +
 +
 +#
 +# patterns for applying CssClass facet (CSS styles), matching on member names
 +#
 +isis.reflector.facet.cssClass.patterns=\
 +                        delete.*:btn-warning,\
 +                        .*:btn-default
 +
 +
 +#################################################################################
 +#
 +# Value facet defaults
 +#
 +# (see also viewer-specific config files, eg viewer_wicket.properties)
 +#
 +#################################################################################
 +
 +# as used by @Title of a date
 +isis.value.format.date=dd-MM-yyyy
 +
 +
 +
 +#################################################################################
 +#
 +# Facet Decorators
 +#
 +#################################################################################
 +
 +#
 +# Providing such capabilities as i18n
 +#
 +
 +isis.reflector.facet-decorators=org.apache.isis.core.metamodel.facetdecorator.i18n.resourcebundle.I18nDecoratorUsingResourceBundleInstaller
 +
 +
 +#################################################################################
 +#
 +# Application Services and fixtures
 +#
 +#################################################################################
 +
 +#
 +# Specify the domain services.
 +# 
 +# These are the most important configuration properties in the system, as they define
 +# the set of the classes for Isis to instantiate as domain service singletons.
 +# From these domain service instances the rest of the metamodel is discovered, while the 
 +# end-user gains access to other domain objects by invoking the actions of the domain services.
 +#
 +isis.services-installer=configuration-and-annotation
- isis.services.ServicesInstallerFromAnnotation.packagePrefix=app,\
++isis.services.ServicesInstallerFromAnnotation.packagePrefix=app,dom.todo,fixture.todo,webapp.admin,webapp.prototyping, \
 +                                                            dom.todo,\
 +                                                            fixture.todo,\
 +                                                            webapp.userprof,\
 +                                                            webapp.prototyping
 +
- isis.services = \
++isis.services = org.apache.isis.applib.services.bookmark.BookmarkHolderActionContributions,\# customizable exception handling, org.apache.isis.objectstore.jdo.applib.service.exceprecog.ExceptionRecognizerCompositeForJdoObjectStore,\#,1\:webapp.CustomMementoService,1\:webapp.CustomRepresentationService
 +                org.apache.isis.applib.services.bookmark.BookmarkHolderActionContributions,\
 +                \
 +                # customizable exception handling, \
 +                org.apache.isis.objectstore.jdo.applib.service.exceprecog.ExceptionRecognizerCompositeForJdoObjectStore,\
 +                #,\
 +                1:webapp.CustomMementoService,\
 +                1:webapp.CustomRepresentationService
 +
 +
 +# Specify the (optional) test fixtures
 +#
 +# Fixtures are used to seed the object store with an initial set of data.  For the 
 +# in-memory object store, the fixtures are installed on every run.  For other
 +# object stores, they are used only when the object store is first initialized.
 +#
 +#isis.fixtures=fixture.todo.scenarios.ToDoItemsRecreateForSven
 +
 +
 +#
 +# required by EmailServiceDefault
 +#
 +#isis.service.email.sender.address=some.valid@email.address
 +#isis.service.email.sender.password=the.password.for-isis.notification.email.sender.address
 +
 +
 +#
 +# whether ExceptionRecognizers should also log any recognized exceptions
 +# (default false; enable for diagnostics/debugging)
 +#
 +#isis.services.exceprecog.logRecognizedExceptions=true
 +
 +
 +################################################################################
 +#
 +# Auditing, Publishing, Command
 +#
 +################################################################################
 +
 +#
 +# Whether changes to objects should be audited; if not set, defaults to "none"
 +# - if not set or set to "none", can explicitly enable using @DomainObject(auditing=Auditing.ENABLED)
 +# - if set to "all", can explicitly disable using @Object(auditing=Auditing.DISABLED)
 +#
 +#isis.services.audit.objects=all|none
 +
 +#
 +# Whether changes to objects should be published; if not set, defaults to "none"
 +# - if not set or set to "none", can explicitly enable using @DomainObject(publishing=Publishing.ENABLED)
 +# - if set to "all", can explicitly disable using @Object(publishing=Publishing.DISABLED)
 +#
 +#isis.services.publish.objects=all|none
 +
 +#
 +# Whether all (or all non-query only) actions should be published; if not set, defaults to "none"
 +# - if not set or set to "none", can explicitly enable using @Action(publishing=Publishing.ENABLED)
 +# - if set to "all", can explicitly disable using @Action(publishing=Publishing.DISABLED)
 +#
 +#isis.services.publish.actions=all|none|ignoreQueryOnly
 +
 +
 +#
 +# Whether all (or all non-query only) actions should be reified as commands; if not set, defaults to "none"
 +# - if not set or set to "none", can explicitly enable using @Action(command=CommandReification.ENABLED)
 +# - if set to "all", can explicitly disable using @Action(command=CommandReification.DISABLED)
 +#
 +#isis.services.command.actions=all|none|ignoreQueryOnly
 +
 +
 +
 +################################################################################
 +#
 +# Policies
 +#
 +#################################################################################
 +
 +#
 +# Whether editing of object properties is allowed; if not set, defaults to "true"
 +# - if not set or set to "true", can explicitly disable using @DomainObject(editing=Editing.DISABLED)
 +# - if set to "false", can explicitly enable using @DomainObject(editing=Editing.ENABLED)
 +#
 +#isis.objects.editing=true|false
 +
 +
 +
 +################################################################################
 +#
 +# Viewer defaults
 +#
 +#################################################################################
 +
 +#isis.viewers.paged.standalone=30
 +#isis.viewers.paged.parented=10
 +
 +#isis.viewers.propertyLayout.labelPosition=LEFT
 +#isis.viewers.parameterLayout.labelPosition=LEFT

http://git-wip-us.apache.org/repos/asf/isis/blob/e2dffa84/mothballed/example/application/todoapp/webapp/src/main/webapp/WEB-INF/persistor_datanucleus.properties
----------------------------------------------------------------------
diff --cc mothballed/example/application/todoapp/webapp/src/main/webapp/WEB-INF/persistor_datanucleus.properties
index a60a733,0000000..051d1dc
mode 100644,000000..100644
--- a/mothballed/example/application/todoapp/webapp/src/main/webapp/WEB-INF/persistor_datanucleus.properties
+++ b/mothballed/example/application/todoapp/webapp/src/main/webapp/WEB-INF/persistor_datanucleus.properties
@@@ -1,88 -1,0 +1,88 @@@
 +#  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.
 +
 +#
 +# configuration file for the JDO/DataNucleus objectstore
 +#
 +
 +# identifies @PersistenceCapable entities to be eagerly registered
 +# if move class to other package (eg com.mycompany.myapp.dom) then update 
 +isis.persistor.datanucleus.RegisterEntities.packagePrefix=dom
 +
 +# whether to persist the event data as a "clob" or as a "zipped" byte[]
 +# default is "zipped"
 +#isis.persistor.datanucleus.PublishingService.serializedForm=zipped
 +
 +
 +
 +#####################################################################
 +#
 +# DataNucleus' configuration
 +#
 +# The 'isis.persistor.datanucleus.impl' prefix is stripped off,
 +# remainder is passed through to DataNucleus
 +#
 +#####################################################################
 +
- isis.persistor.datanucleus.impl.datanucleus.autoCreateSchema=true
- isis.persistor.datanucleus.impl.datanucleus.validateTables=true
- isis.persistor.datanucleus.impl.datanucleus.validateConstraints=true
++isis.persistor.datanucleus.impl.datanucleus.schema.autoCreateAll=true
++isis.persistor.datanucleus.impl.datanucleus.schema.validateTables=true
++isis.persistor.datanucleus.impl.datanucleus.schema.validateConstraints=true
 +
 +
 +#
 +# Require explicit persistence (since entities are Comparable and using ObjectContracts#compareTo).
 +# see http://www.datanucleus.org/products/accessplatform_3_0/jdo/transaction_types.html
 +#
 +isis.persistor.datanucleus.impl.datanucleus.persistenceByReachabilityAtCommit=false
 +
 +
 +#
 +# How column names are identified 
 +# (http://www.datanucleus.org/products/datanucleus/jdo/orm/datastore_identifiers.html)
 +#
- isis.persistor.datanucleus.impl.datanucleus.identifier.case=PreserveCase
++isis.persistor.datanucleus.impl.datanucleus.identifier.case=MixedCase
 +
 +
 +#
 +# L2 cache
 +# off except if explicitly marked as cacheable
 +# http://www.datanucleus.org/products/datanucleus/jdo/cache.html
 +#
 +isis.persistor.datanucleus.impl.datanucleus.cache.level2.type=none
 +isis.persistor.datanucleus.impl.datanucleus.cache.level2.mode=ENABLE_SELECTIVE
 +
 +
 +
 +#
 +# uncomment to use JNDI rather than direct JDBC
 +#
 +#isis.persistor.datanucleus.impl.datanucleus.ConnectionFactoryName=java:comp/env/jdbc/quickstart
 +
 +#
 +# uncomment to use JTA resource
 +#
 +#isis.persistor.datanucleus.impl.datanucleus.ConnectionFactory2Name=java:comp/env/jdbc/quickstart-nontx
 +#isis.persistor.datanucleus.impl.javax.jdo.option.TransactionType=JTA
 +
 +
 +
 +#
 +#
 +# JDBC connection details
 +# ... are in persistor.properties
 +#
 +#

http://git-wip-us.apache.org/repos/asf/isis/blob/e2dffa84/pom.xml
----------------------------------------------------------------------