You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2013/05/20 13:34:43 UTC

[3/8] ISIS-409: moving wrapper progmodel into core, as a service

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/component/progmodel/wrapper/wrapper-metamodel/src/test/java/org/apache/isis/progmodel/wrapper/WrappedFactoryDefaultTest_wrappedObject.java
----------------------------------------------------------------------
diff --git a/component/progmodel/wrapper/wrapper-metamodel/src/test/java/org/apache/isis/progmodel/wrapper/WrappedFactoryDefaultTest_wrappedObject.java b/component/progmodel/wrapper/wrapper-metamodel/src/test/java/org/apache/isis/progmodel/wrapper/WrappedFactoryDefaultTest_wrappedObject.java
deleted file mode 100644
index 12c3c99..0000000
--- a/component/progmodel/wrapper/wrapper-metamodel/src/test/java/org/apache/isis/progmodel/wrapper/WrappedFactoryDefaultTest_wrappedObject.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
-package org.apache.isis.progmodel.wrapper;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.notNullValue;
-import static org.junit.Assert.assertThat;
-
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-
-import org.apache.isis.core.tck.dom.claimapp.employees.Employee;
-import org.apache.isis.core.tck.dom.claimapp.employees.EmployeeRepository;
-import org.apache.isis.core.tck.dom.claimapp.employees.EmployeeRepositoryImpl;
-import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2;
-import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
-import org.apache.isis.progmodel.wrapper.applib.DisabledException;
-import org.apache.isis.progmodel.wrapper.applib.HiddenException;
-import org.apache.isis.progmodel.wrapper.applib.InvalidException;
-import org.apache.isis.progmodel.wrapper.applib.WrapperFactory;
-import org.apache.isis.progmodel.wrapper.metamodel.internal.WrapperFactoryDefault;
-
-public class WrappedFactoryDefaultTest_wrappedObject {
-
-    @Rule
-    public JUnitRuleMockery2 mockery = JUnitRuleMockery2.createFor(Mode.INTERFACES_ONLY);
-
-    private EmployeeRepository employeeRepository;
-    // private ClaimRepository claimRepository;
-
-    private Employee employeeDO;
-    private Employee employeeWO;
-
-    private WrapperFactory wrapperFactory;
-
-    @Before
-    public void setUp() {
-
-        employeeRepository = new EmployeeRepositoryImpl();
-        // claimRepository = new ClaimRepositoryImpl();
-
-        employeeDO = new Employee();
-        employeeDO.setName("Smith");
-        employeeDO.setEmployeeRepository(employeeRepository); // would be done
-                                                              // by the
-                                                              // EmbeddedContext
-                                                              // impl
-
-        wrapperFactory = new WrapperFactoryDefault();
-        employeeWO = wrapperFactory.wrap(employeeDO);
-    }
-
-    @Ignore("TODO - moved from embedded runtime, need to re-enable")
-    @Test
-    public void shouldWrapDomainObject() {
-        // then
-        assertThat(employeeWO, is(notNullValue()));
-    }
-
-    @Ignore("TODO - moved from embedded runtime, need to re-enable")
-    @Test
-    public void shouldBeAbleToInjectIntoDomainObjects() {
-
-        // given
-        assertThat(employeeDO.getEmployeeRepository(), is(notNullValue()));
-
-        // then
-        assertThat(employeeWO.getEmployeeRepository(), is(notNullValue()));
-    }
-
-    @Ignore("TODO - moved from embedded runtime, need to re-enable")
-    @Test
-    public void shouldBeAbleToReadVisibleProperty() {
-        // then
-        assertThat(employeeWO.getName(), is(employeeDO.getName()));
-    }
-
-    @Ignore("TODO - moved from embedded runtime, need to re-enable")
-    @Test(expected = HiddenException.class)
-    public void shouldNotBeAbleToViewHiddenProperty() {
-        // given
-        employeeDO.whetherHideName = true;
-        // when
-        employeeWO.getName();
-        // then should throw exception
-    }
-
-    @Ignore("TODO - moved from embedded runtime, need to re-enable")
-    @Test
-    public void shouldBeAbleToModifyEnabledPropertyUsingSetter() {
-        // when
-        employeeWO.setName("Jones");
-        // then
-        assertThat(employeeDO.getName(), is("Jones"));
-        assertThat(employeeWO.getName(), is(employeeDO.getName()));
-    }
-
-    @Ignore("TODO - moved from embedded runtime, need to re-enable")
-    @Test(expected = DisabledException.class)
-    public void shouldNotBeAbleToModifyDisabledProperty() {
-        // given
-        employeeDO.reasonDisableName = "sorry, no change allowed";
-        // when
-        employeeWO.setName("Jones");
-        // then should throw exception
-    }
-
-    @Ignore("TODO - moved from embedded runtime, need to re-enable")
-    @Test(expected = UnsupportedOperationException.class)
-    public void shouldNotBeAbleToModifyPropertyUsingModify() {
-        // when
-        employeeWO.modifyName("Jones");
-        // then should throw exception
-    }
-
-    @Ignore("TODO - moved from embedded runtime, need to re-enable")
-    @Test(expected = UnsupportedOperationException.class)
-    public void shouldNotBeAbleToModifyPropertyUsingClear() {
-        // when
-        employeeWO.clearName();
-        // then should throw exception
-    }
-
-    @Ignore("TODO - moved from embedded runtime, need to re-enable")
-    @Test(expected = InvalidException.class)
-    public void shouldNotBeAbleToModifyPropertyIfInvalid() {
-        // given
-        employeeDO.reasonValidateName = "sorry, invalid data";
-        // when
-        employeeWO.setName("Jones");
-        // then should throw exception
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/component/progmodel/wrapper/wrapper-metamodel/src/test/java/org/apache/isis/progmodel/wrapper/WrappedFactoryDefaultTest_wrappedObject_transient.java
----------------------------------------------------------------------
diff --git a/component/progmodel/wrapper/wrapper-metamodel/src/test/java/org/apache/isis/progmodel/wrapper/WrappedFactoryDefaultTest_wrappedObject_transient.java b/component/progmodel/wrapper/wrapper-metamodel/src/test/java/org/apache/isis/progmodel/wrapper/WrappedFactoryDefaultTest_wrappedObject_transient.java
deleted file mode 100644
index 34eb6d9..0000000
--- a/component/progmodel/wrapper/wrapper-metamodel/src/test/java/org/apache/isis/progmodel/wrapper/WrappedFactoryDefaultTest_wrappedObject_transient.java
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
-package org.apache.isis.progmodel.wrapper;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertThat;
-
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import org.jmock.Expectations;
-import org.jmock.auto.Mock;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-
-import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.annotation.Where;
-import org.apache.isis.applib.events.PropertyModifyEvent;
-import org.apache.isis.applib.events.PropertyUsabilityEvent;
-import org.apache.isis.applib.events.PropertyVisibilityEvent;
-import org.apache.isis.applib.filter.Filter;
-import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
-import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
-import org.apache.isis.core.metamodel.adapter.ObjectPersistor;
-import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
-import org.apache.isis.core.metamodel.consent.Allow;
-import org.apache.isis.core.metamodel.consent.Consent;
-import org.apache.isis.core.metamodel.consent.InteractionResult;
-import org.apache.isis.core.metamodel.consent.Veto;
-import org.apache.isis.core.metamodel.facetapi.Facet;
-import org.apache.isis.core.metamodel.spec.SpecificationLoader;
-import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
-import org.apache.isis.core.metamodel.specloader.specimpl.dflt.ObjectSpecificationDefault;
-import org.apache.isis.core.progmodel.facets.members.disabled.DisabledFacet;
-import org.apache.isis.core.progmodel.facets.members.disabled.staticmethod.DisabledFacetAlwaysEverywhere;
-import org.apache.isis.core.progmodel.facets.properties.accessor.PropertyAccessorFacetViaAccessor;
-import org.apache.isis.core.progmodel.facets.properties.modify.PropertySetterFacetViaSetterMethod;
-import org.apache.isis.core.runtime.authentication.standard.SimpleSession;
-import org.apache.isis.core.tck.dom.claimapp.employees.Employee;
-import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2;
-import org.apache.isis.core.unittestsupport.jmocking.JUnitRuleMockery2.Mode;
-import org.apache.isis.progmodel.wrapper.applib.DisabledException;
-import org.apache.isis.progmodel.wrapper.metamodel.internal.WrapperFactoryDefault;
-
-public class WrappedFactoryDefaultTest_wrappedObject_transient {
-
-    @Rule
-    public final JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(Mode.INTERFACES_AND_CLASSES);
-
-    @Mock
-    private AdapterManager mockAdapterManager;
-    @Mock
-    private AuthenticationSessionProvider mockAuthenticationSessionProvider;
-    @Mock
-    private ObjectPersistor mockObjectPersistor;
-    @Mock
-    private SpecificationLoader mockSpecificationLookup;
-
-    private Employee employeeDO;
-    @Mock
-    private ObjectAdapter mockEmployeeAdapter;
-    @Mock
-    private ObjectSpecificationDefault mockEmployeeSpec;
-    @Mock
-    private OneToOneAssociation mockPasswordMember;
-    @Mock
-    private Identifier mockPasswordIdentifier;
-
-    @Mock
-    protected ObjectAdapter mockPasswordAdapter;
-    
-    private final String passwordValue = "12345678";
-
-    private final SimpleSession session = new SimpleSession("tester", Collections.<String>emptyList());
-
-    private List<Facet> facets;
-    private Method getPasswordMethod;
-    private Method setPasswordMethod;
-
-
-    private WrapperFactoryDefault wrapperFactory;
-    private Employee employeeWO;
-
-
-    @Before
-    public void setUp() throws Exception {
-
-        // employeeRepository = new EmployeeRepositoryImpl();
-        // claimRepository = new ClaimRepositoryImpl();
-
-        employeeDO = new Employee();
-        employeeDO.setName("Smith");
-        
-        getPasswordMethod = Employee.class.getMethod("getPassword");
-        setPasswordMethod = Employee.class.getMethod("setPassword", String.class);
-
-        wrapperFactory = new WrapperFactoryDefault();
-        wrapperFactory.setAdapterManager(mockAdapterManager);
-        wrapperFactory.setAuthenticationSessionProvider(mockAuthenticationSessionProvider);
-        wrapperFactory.setObjectPersistor(mockObjectPersistor);
-        wrapperFactory.setSpecificationLookup(mockSpecificationLookup);
-        
-        context.checking(new Expectations() {
-            {
-                allowing(mockAdapterManager).getAdapterFor(employeeDO);
-                will(returnValue(mockEmployeeAdapter));
-
-                allowing(mockAdapterManager).adapterFor(passwordValue);
-                will(returnValue(mockPasswordAdapter));
-
-                allowing(mockEmployeeAdapter).getSpecification();
-                will(returnValue(mockEmployeeSpec));
-
-                allowing(mockEmployeeAdapter).getObject();
-                will(returnValue(employeeDO));
-
-                allowing(mockPasswordAdapter).getObject();
-                will(returnValue(passwordValue));
-
-                allowing(mockPasswordMember).getIdentifier();
-                will(returnValue(mockPasswordIdentifier));
-
-                allowing(mockSpecificationLookup).loadSpecification(Employee.class);
-                will(returnValue(mockEmployeeSpec));
-                
-                allowing(mockEmployeeSpec).getMember(with(setPasswordMethod));
-                will(returnValue(mockPasswordMember));
-
-                allowing(mockEmployeeSpec).getMember(with(getPasswordMethod));
-                will(returnValue(mockPasswordMember));
-
-                allowing(mockPasswordMember).getName();
-                will(returnValue("password"));
-
-                allowing(mockAuthenticationSessionProvider).getAuthenticationSession();
-                will(returnValue(session));
-                
-                allowing(mockPasswordMember).isOneToOneAssociation();
-                will(returnValue(true));
-
-                allowing(mockPasswordMember).isOneToManyAssociation();
-                will(returnValue(false));
-            }
-        });
-
-        employeeWO = wrapperFactory.wrap(employeeDO);
-    }
-
-    @Test(expected = DisabledException.class)
-    public void shouldNotBeAbleToModifyProperty() {
-
-        // given
-        final DisabledFacet disabledFacet = new DisabledFacetAlwaysEverywhere(mockPasswordMember);
-        facets = Arrays.asList((Facet)disabledFacet, new PropertySetterFacetViaSetterMethod(setPasswordMethod, mockPasswordMember));
-
-        final Consent visibilityConsent = new Allow(new InteractionResult(new PropertyVisibilityEvent(employeeDO, null)));
-
-        final InteractionResult usabilityInteractionResult = new InteractionResult(new PropertyUsabilityEvent(employeeDO, null));
-        usabilityInteractionResult.advise("disabled", disabledFacet);
-        final Consent usabilityConsent = new Veto(usabilityInteractionResult);
-
-        context.checking(new Expectations() {
-            {
-                allowing(mockPasswordMember).getFacets(with(any(Filter.class)));
-                will(returnValue(facets));
-                
-                allowing(mockPasswordMember).isVisible(session, mockEmployeeAdapter, Where.ANYWHERE);
-                will(returnValue(visibilityConsent));
-                
-                allowing(mockPasswordMember).isUsable(session, mockEmployeeAdapter, Where.ANYWHERE);
-                will(returnValue(usabilityConsent));
-            }
-        });
-        
-        // when
-        employeeWO.setPassword(passwordValue);
-        
-        // then should throw exception
-    }
-
-    @Test
-    public void canModifyProperty() {
-        // given
-
-        final Consent visibilityConsent = new Allow(new InteractionResult(new PropertyVisibilityEvent(employeeDO, mockPasswordIdentifier)));
-        final Consent usabilityConsent = new Allow(new InteractionResult(new PropertyUsabilityEvent(employeeDO, mockPasswordIdentifier)));
-        final Consent validityConsent = new Allow(new InteractionResult(new PropertyModifyEvent(employeeDO, mockPasswordIdentifier, passwordValue)));
-
-        context.checking(new Expectations() {
-            {
-                allowing(mockPasswordMember).isVisible(session, mockEmployeeAdapter, Where.ANYWHERE);
-                will(returnValue(visibilityConsent));
-                
-                allowing(mockPasswordMember).isUsable(session, mockEmployeeAdapter, Where.ANYWHERE);
-                will(returnValue(usabilityConsent));
-                
-                allowing(mockPasswordMember).isAssociationValid(mockEmployeeAdapter, mockPasswordAdapter);
-                will(returnValue(validityConsent));
-            }
-        });
-
-        facets = Arrays.asList((Facet)new PropertySetterFacetViaSetterMethod(setPasswordMethod, mockPasswordMember));
-        context.checking(new Expectations() {
-            {
-                one(mockPasswordMember).getFacets(with(any(Filter.class)));
-                will(returnValue(facets));
-                
-                one(mockPasswordMember).set(mockEmployeeAdapter, mockPasswordAdapter);
-            }
-        });
-
-        // when
-        employeeWO.setPassword(passwordValue);
-
-
-        // and given
-        facets = Arrays.asList((Facet)new PropertyAccessorFacetViaAccessor(getPasswordMethod, mockPasswordMember));
-        context.checking(new Expectations() {
-            {
-                one(mockPasswordMember).getFacets(with(any(Filter.class)));
-                will(returnValue(facets));
-                
-                one(mockPasswordMember).get(mockEmployeeAdapter);
-                will(returnValue(mockPasswordAdapter));
-            }
-        });
-
-        // then be allowed
-        assertThat(employeeWO.getPassword(), is(passwordValue));
-    }
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/component/viewer/junit/impl/pom.xml
----------------------------------------------------------------------
diff --git a/component/viewer/junit/impl/pom.xml b/component/viewer/junit/impl/pom.xml
index 09dca4d..cd69bfc 100644
--- a/component/viewer/junit/impl/pom.xml
+++ b/component/viewer/junit/impl/pom.xml
@@ -67,8 +67,8 @@
 
     <dependencies>
         <dependency>
-            <groupId>org.apache.isis.progmodel</groupId>
-            <artifactId>isis-progmodel-wrapper-metamodel</artifactId>
+            <groupId>org.apache.isis.core</groupId>
+            <artifactId>isis-core-wrapper</artifactId>
         </dependency>
 
         <dependency>

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/AbstractTest.java
----------------------------------------------------------------------
diff --git a/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/AbstractTest.java b/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/AbstractTest.java
index 3c1c625..bf87851 100644
--- a/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/AbstractTest.java
+++ b/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/AbstractTest.java
@@ -24,7 +24,7 @@ import org.junit.Before;
 import org.junit.runner.RunWith;
 
 import org.apache.isis.applib.DomainObjectContainer;
-import org.apache.isis.progmodel.wrapper.applib.WrapperFactory;
+import org.apache.isis.applib.services.wrapper.WrapperFactory;
 import org.apache.isis.viewer.junit.sample.domain.Country;
 import org.apache.isis.viewer.junit.sample.domain.Customer;
 import org.apache.isis.viewer.junit.sample.domain.Product;

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/InteractionListenerTest.java
----------------------------------------------------------------------
diff --git a/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/InteractionListenerTest.java b/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/InteractionListenerTest.java
index e33df98..9cb9cd2 100644
--- a/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/InteractionListenerTest.java
+++ b/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/InteractionListenerTest.java
@@ -27,8 +27,8 @@ import org.junit.Test;
 
 import org.apache.isis.applib.events.InteractionEvent;
 import org.apache.isis.applib.events.PropertyAccessEvent;
-import org.apache.isis.progmodel.wrapper.applib.listeners.InteractionAdapter;
-import org.apache.isis.progmodel.wrapper.applib.listeners.InteractionListener;
+import org.apache.isis.applib.services.wrapper.listeners.InteractionAdapter;
+import org.apache.isis.applib.services.wrapper.listeners.InteractionListener;
 import org.apache.isis.viewer.junit.sample.domain.Customer;
 
 public class InteractionListenerTest extends AbstractTest {

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/MemberDisabledTest.java
----------------------------------------------------------------------
diff --git a/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/MemberDisabledTest.java b/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/MemberDisabledTest.java
index 8e5b3a2..0bb145b 100644
--- a/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/MemberDisabledTest.java
+++ b/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/MemberDisabledTest.java
@@ -28,9 +28,9 @@ import java.util.List;
 
 import org.junit.Test;
 
+import org.apache.isis.applib.services.wrapper.DisabledException;
 import org.apache.isis.core.progmodel.facets.members.disabled.annotation.DisabledFacetAnnotation;
 import org.apache.isis.core.progmodel.facets.members.disabled.method.DisableForContextFacetViaMethod;
-import org.apache.isis.progmodel.wrapper.applib.DisabledException;
 import org.apache.isis.viewer.junit.sample.domain.Order;
 
 public class MemberDisabledTest extends AbstractTest {

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/MemberHiddenTest.java
----------------------------------------------------------------------
diff --git a/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/MemberHiddenTest.java b/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/MemberHiddenTest.java
index 6a30fbf..d8cb0c8 100644
--- a/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/MemberHiddenTest.java
+++ b/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/MemberHiddenTest.java
@@ -26,10 +26,10 @@ import static org.junit.Assert.fail;
 
 import org.junit.Test;
 
+import org.apache.isis.applib.services.wrapper.HiddenException;
 import org.apache.isis.core.progmodel.facets.members.hidden.annotation.HiddenFacetForMemberAnnotation;
 import org.apache.isis.core.progmodel.facets.members.hidden.forsession.HideForSessionFacetViaMethod;
 import org.apache.isis.core.progmodel.facets.members.hidden.method.HideForContextFacetViaMethod;
-import org.apache.isis.progmodel.wrapper.applib.HiddenException;
 import org.apache.isis.viewer.junit.sample.domain.Country;
 
 public class MemberHiddenTest extends AbstractTest {

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/MemberInvalidTest.java
----------------------------------------------------------------------
diff --git a/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/MemberInvalidTest.java b/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/MemberInvalidTest.java
index c176bca..3ef955f 100644
--- a/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/MemberInvalidTest.java
+++ b/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/MemberInvalidTest.java
@@ -26,6 +26,7 @@ import static org.junit.Assert.fail;
 
 import org.junit.Test;
 
+import org.apache.isis.applib.services.wrapper.InvalidException;
 import org.apache.isis.core.metamodel.facets.mandatory.MandatoryFacetDefault;
 import org.apache.isis.core.progmodel.facets.actions.validate.method.ActionValidationFacetViaMethod;
 import org.apache.isis.core.progmodel.facets.collections.validate.CollectionValidateAddToFacetViaMethod;
@@ -33,7 +34,6 @@ import org.apache.isis.core.progmodel.facets.collections.validate.CollectionVali
 import org.apache.isis.core.progmodel.facets.properties.validate.PropertyValidateFacetViaMethod;
 import org.apache.isis.core.progmodel.facets.properties.validate.maxlenannot.MaxLengthFacetAnnotationForProperty;
 import org.apache.isis.core.progmodel.facets.properties.validate.regexannot.RegExFacetAnnotationForProperty;
-import org.apache.isis.progmodel.wrapper.applib.InvalidException;
 import org.apache.isis.viewer.junit.sample.domain.Country;
 
 public class MemberInvalidTest extends AbstractTest {

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/MemberModifyTest.java
----------------------------------------------------------------------
diff --git a/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/MemberModifyTest.java b/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/MemberModifyTest.java
index 12cf26d..0e87673 100644
--- a/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/MemberModifyTest.java
+++ b/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/MemberModifyTest.java
@@ -30,7 +30,7 @@ import java.util.List;
 
 import org.junit.Test;
 
-import org.apache.isis.progmodel.wrapper.applib.InvalidException;
+import org.apache.isis.applib.services.wrapper.InvalidException;
 import org.apache.isis.viewer.junit.sample.domain.Country;
 import org.apache.isis.viewer.junit.sample.domain.Order;
 

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/ObjectImmutableTest.java
----------------------------------------------------------------------
diff --git a/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/ObjectImmutableTest.java b/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/ObjectImmutableTest.java
index 8bd1e8f..3abcec6 100644
--- a/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/ObjectImmutableTest.java
+++ b/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/ObjectImmutableTest.java
@@ -26,9 +26,9 @@ import static org.junit.Assert.fail;
 
 import org.junit.Test;
 
+import org.apache.isis.applib.services.wrapper.DisabledException;
 import org.apache.isis.core.progmodel.facets.collections.disabled.fromimmutable.DisabledFacetForCollectionDerivedFromImmutable;
 import org.apache.isis.core.progmodel.facets.properties.disabled.fromimmutable.DisabledFacetForPropertyDerivedFromImmutable;
-import org.apache.isis.progmodel.wrapper.applib.DisabledException;
 
 public class ObjectImmutableTest extends AbstractTest {
 

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/SaveObjectsTest.java
----------------------------------------------------------------------
diff --git a/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/SaveObjectsTest.java b/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/SaveObjectsTest.java
index 994c529..726b051 100644
--- a/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/SaveObjectsTest.java
+++ b/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/SaveObjectsTest.java
@@ -27,9 +27,9 @@ import static org.junit.Assert.fail;
 
 import org.junit.Test;
 
+import org.apache.isis.applib.services.wrapper.InvalidException;
+import org.apache.isis.applib.services.wrapper.WrapperObject;
 import org.apache.isis.core.progmodel.facets.object.validate.method.ValidateObjectFacetViaValidateMethod;
-import org.apache.isis.progmodel.wrapper.applib.InvalidException;
-import org.apache.isis.progmodel.wrapper.applib.WrapperObject;
 import org.apache.isis.viewer.junit.sample.domain.Customer;
 
 public class SaveObjectsTest extends AbstractTest {

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/ViewObjectTest.java
----------------------------------------------------------------------
diff --git a/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/ViewObjectTest.java b/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/ViewObjectTest.java
index 668bc2a..dcc4593 100644
--- a/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/ViewObjectTest.java
+++ b/component/viewer/junit/impl/src/test/java/org/apache/isis/viewer/junit/ViewObjectTest.java
@@ -28,7 +28,7 @@ import java.util.List;
 
 import org.junit.Test;
 
-import org.apache.isis.progmodel.wrapper.applib.WrapperObject;
+import org.apache.isis.applib.services.wrapper.WrapperObject;
 import org.apache.isis.viewer.junit.sample.domain.Country;
 import org.apache.isis.viewer.junit.sample.domain.Customer;
 

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/component/viewer/junit/tck/src/test/java/junit/AbstractTest.java
----------------------------------------------------------------------
diff --git a/component/viewer/junit/tck/src/test/java/junit/AbstractTest.java b/component/viewer/junit/tck/src/test/java/junit/AbstractTest.java
index d62b5eb..9924061 100644
--- a/component/viewer/junit/tck/src/test/java/junit/AbstractTest.java
+++ b/component/viewer/junit/tck/src/test/java/junit/AbstractTest.java
@@ -24,9 +24,9 @@ import org.junit.Before;
 import org.junit.runner.RunWith;
 
 import org.apache.isis.applib.DomainObjectContainer;
+import org.apache.isis.applib.services.wrapper.WrapperFactory;
+import org.apache.isis.applib.services.wrapper.WrapperObject;
 import org.apache.isis.core.tck.dom.scalars.PrimitiveValuedEntityRepository;
-import org.apache.isis.progmodel.wrapper.applib.WrapperFactory;
-import org.apache.isis.progmodel.wrapper.applib.WrapperObject;
 import org.apache.isis.viewer.junit.ConfigDir;
 import org.apache.isis.viewer.junit.IsisTestRunner;
 import org.apache.isis.viewer.junit.Service;

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/DisabledException.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/DisabledException.java b/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/DisabledException.java
new file mode 100644
index 0000000..a6ba6b2
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/DisabledException.java
@@ -0,0 +1,42 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.applib.services.wrapper;
+
+import org.apache.isis.applib.events.InteractionEvent;
+import org.apache.isis.applib.events.UsabilityEvent;
+
+/**
+ * Superclass of exceptions which indicate an attempt to interact with a class
+ * member that is disabled.
+ */
+public class DisabledException extends InteractionException {
+
+    private static final long serialVersionUID = 1L;
+
+    public DisabledException(final InteractionEvent interactionEvent) {
+        super(interactionEvent);
+    }
+
+    @Override
+    public UsabilityEvent getInteractionEvent() {
+        return (UsabilityEvent) super.getInteractionEvent();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/HiddenException.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/HiddenException.java b/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/HiddenException.java
new file mode 100644
index 0000000..ab95cd7
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/HiddenException.java
@@ -0,0 +1,42 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.applib.services.wrapper;
+
+import org.apache.isis.applib.events.InteractionEvent;
+import org.apache.isis.applib.events.VisibilityEvent;
+
+/**
+ * Superclass of exceptions which indicate an attempt to interact with a class
+ * member that is in some way hidden or invisible.
+ */
+public class HiddenException extends InteractionException {
+
+    private static final long serialVersionUID = 1L;
+
+    public HiddenException(final InteractionEvent interactionEvent) {
+        super(interactionEvent);
+    }
+
+    @Override
+    public VisibilityEvent getInteractionEvent() {
+        return (VisibilityEvent) super.getInteractionEvent();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/InteractionException.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/InteractionException.java b/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/InteractionException.java
new file mode 100644
index 0000000..f734b3f
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/InteractionException.java
@@ -0,0 +1,75 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.applib.services.wrapper;
+
+import org.apache.isis.applib.ApplicationException;
+import org.apache.isis.applib.Identifier;
+import org.apache.isis.applib.events.InteractionEvent;
+
+public abstract class InteractionException extends ApplicationException {
+
+    private static final long serialVersionUID = 1L;
+
+    private final InteractionEvent interactionEvent;
+
+    public InteractionException(final InteractionEvent interactionEvent) {
+        super(interactionEvent.getReason());
+        this.interactionEvent = interactionEvent;
+    }
+
+    /**
+     * The {@link InteractionEvent event} passed into the
+     * {@link #InteractionException(InteractionEvent) constructor}.
+     * 
+     * <p>
+     * Not part of the API, but made available so that subclasses can expose as
+     * the appropriate subtype of {@link InteractionEvent}. This would have been
+     * more obvious to see if {@link InteractionException} was generic, but
+     * generic subclasses of {@link Throwable} are (apparently) not allowed.
+     * 
+     * @return
+     */
+    protected InteractionEvent getInteractionEvent() {
+        return interactionEvent;
+    }
+
+    /**
+     * Convenience method that returns the
+     * {@link InteractionEvent#getAdvisorClass() advisor class} of the wrapped
+     * {@link #getInteractionEvent() interaction event}.
+     * 
+     * @return
+     */
+    public Class<?> getAdvisorClass() {
+        return interactionEvent.getAdvisorClass();
+    }
+
+    /**
+     * Convenience method that returns the
+     * {@link InteractionEvent#getIdentifier() identifier} of the wrapped
+     * {@link #getInteractionEvent() interaction event}.
+     * 
+     * @return
+     */
+    public Identifier getIdentifier() {
+        return interactionEvent.getIdentifier();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/InvalidException.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/InvalidException.java b/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/InvalidException.java
new file mode 100644
index 0000000..494155c
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/InvalidException.java
@@ -0,0 +1,45 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.applib.services.wrapper;
+
+import org.apache.isis.applib.events.InteractionEvent;
+import org.apache.isis.applib.events.ValidityEvent;
+
+/**
+ * Superclass of exceptions which indicate an attempt to interact with an object
+ * or member in a way that is invalid.
+ * 
+ * <p>
+ * 
+ */
+public class InvalidException extends InteractionException {
+
+    private static final long serialVersionUID = 1L;
+
+    public InvalidException(final InteractionEvent interactionEvent) {
+        super(interactionEvent);
+    }
+
+    @Override
+    public ValidityEvent getInteractionEvent() {
+        return (ValidityEvent) super.getInteractionEvent();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/WrapperFactory.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/WrapperFactory.java b/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/WrapperFactory.java
new file mode 100644
index 0000000..317bbaa
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/WrapperFactory.java
@@ -0,0 +1,142 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.applib.services.wrapper;
+
+import java.util.List;
+
+import org.apache.isis.applib.annotation.Hidden;
+import org.apache.isis.applib.events.InteractionEvent;
+import org.apache.isis.applib.services.wrapper.listeners.InteractionListener;
+
+/**
+ * Provides the ability to &quot;wrap&quot; of a domain object such that it can
+ * be interacted with while enforcing the hide/disable/validate rules implies by
+ * the Isis programming model.
+ * 
+ * <p>
+ * The &quot;wrap&quot; is a CGLib proxy that wraps the underlying domain
+ * object. The wrapper can then be interacted with as follows:
+ * <ul>
+ * <li>a <tt>get</tt> method for properties or collections</li>
+ * <li>a <tt>set</tt> method for properties</li>
+ * <li>an <tt>addTo</tt> or <tt>removeFrom</tt> method for collections</li>
+ * <li>any action</li>
+ * </ul>
+ * 
+ * <p>
+ * Calling any of the above methods may result in a (subclass of)
+ * {@link InteractionException} if the object disallows it. For example, if a
+ * property is annotated with {@link Hidden} then a {@link HiddenException} will
+ * be thrown. Similarly if an action has a <tt>validate</tt> method and the
+ * supplied arguments are invalid then a {@link InvalidException} will be
+ * thrown.
+ * 
+ * <p>
+ * In addition, the following methods may also be called:
+ * <ul>
+ * <li>the <tt>title</tt> method</li>
+ * <li>any <tt>defaultXxx</tt> or <tt>choicesXxx</tt> method</li>
+ * </ul>
+ * 
+ * <p>
+ * An exception will be thrown if any other methods are thrown.
+ */
+public interface WrapperFactory {
+
+    /**
+     * Whether interactions with the wrapper are actually passed onto the
+     * underlying domain object.
+     * 
+     * @see WrapperFactory#wrap(Object, ExecutionMode)
+     */
+    public static enum ExecutionMode {
+        EXECUTE, NO_EXECUTE
+    }
+
+    /**
+     * Provides the &quot;wrapper&quot; of the underlying domain object.
+     * 
+     * <p>
+     * If the object has (see {@link #isWrapper(Object)} already been wrapped),
+     * then should just return the object back unchanged.
+     * 
+     * @see #addInteractionListener(InteractionListener)
+     */
+    <T> T wrap(T domainObject);
+
+    /**
+     * Same as {@link #wrap(Object)}, except the actual execution occurs only if
+     * the <tt>execute</tt> parameter indicates.
+     * 
+     * <p>
+     * Otherwise, will do all the validations (raise exceptions as required
+     * etc.), but doesn't modify the model.
+     */
+    <T> T wrap(T domainObject, ExecutionMode mode);
+
+    /**
+     * Whether the supplied object has been wrapped.
+     * 
+     * @param <T>
+     * @param possibleWrapper
+     *            - object that might or might not be a wrapper.
+     * @return
+     */
+    <T> boolean isWrapper(T possibleWrapper);
+
+    /**
+     * All {@link InteractionListener}s that have been registered using
+     * {@link #addInteractionListener(InteractionListener)}.
+     */
+    List<InteractionListener> getListeners();
+
+    /**
+     * Registers an {@link InteractionListener}, to be notified of interactions
+     * on all wrappers.
+     * 
+     * <p>
+     * This is retrospective: the listener will be notified of interactions even
+     * on wrappers created before the listener was installed. (From an
+     * implementation perspective this is because the wrappers delegate back to
+     * the container to fire the events).
+     * 
+     * @param listener
+     * @return
+     */
+    public boolean addInteractionListener(InteractionListener listener);
+
+    /**
+     * Remove an {@link InteractionListener}, to no longer be notified of
+     * interactions on wrappers.
+     * 
+     * <p>
+     * This is retrospective: the listener will no longer be notified of any
+     * interactions created on any wrappers, not just on those wrappers created
+     * subsequently. (From an implementation perspective this is because the
+     * wrappers delegate back to the container to fire the events).
+     * 
+     * @param listener
+     * @return
+     */
+    public boolean removeInteractionListener(InteractionListener listener);
+
+    public void notifyListeners(InteractionEvent ev);
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/WrapperObject.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/WrapperObject.java b/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/WrapperObject.java
new file mode 100644
index 0000000..350446d
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/WrapperObject.java
@@ -0,0 +1,49 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.applib.services.wrapper;
+
+/**
+ * Implemented by all objects that have been viewed as per
+ * {@link WrapperFactory#wrap(Object)}.
+ */
+public interface WrapperObject {
+
+    /**
+     * Programmatic equivalent of invoking save for a transient object (that is,
+     * like hitting the <i>save</i> button that the DnD viewer automatically
+     * renders.
+     */
+    void save();
+
+    /**
+     * Provide access to the underlying, wrapped object.
+     * 
+     * <p>
+     * Used to unwrap objects used as arguments to actions (otherwise, end up
+     * creating a <tt>ObjectSpecification</tt> for the CGLib-enhanced class, not
+     * the original class).
+     * 
+     * <p>
+     * <b>NOTE: there is a string-literal reference to this name
+     * <tt>DomainObjectInvocationHandler</tt>, so it should not be changed.</b>.
+     */
+    Object wrapped();
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/listeners/InteractionAdapter.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/listeners/InteractionAdapter.java b/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/listeners/InteractionAdapter.java
new file mode 100644
index 0000000..f43a129
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/listeners/InteractionAdapter.java
@@ -0,0 +1,109 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.applib.services.wrapper.listeners;
+
+import org.apache.isis.applib.events.ActionArgumentEvent;
+import org.apache.isis.applib.events.ActionInvocationEvent;
+import org.apache.isis.applib.events.ActionUsabilityEvent;
+import org.apache.isis.applib.events.ActionVisibilityEvent;
+import org.apache.isis.applib.events.CollectionAccessEvent;
+import org.apache.isis.applib.events.CollectionAddToEvent;
+import org.apache.isis.applib.events.CollectionMethodEvent;
+import org.apache.isis.applib.events.CollectionRemoveFromEvent;
+import org.apache.isis.applib.events.CollectionUsabilityEvent;
+import org.apache.isis.applib.events.CollectionVisibilityEvent;
+import org.apache.isis.applib.events.ObjectTitleEvent;
+import org.apache.isis.applib.events.ObjectValidityEvent;
+import org.apache.isis.applib.events.PropertyAccessEvent;
+import org.apache.isis.applib.events.PropertyModifyEvent;
+import org.apache.isis.applib.events.PropertyUsabilityEvent;
+import org.apache.isis.applib.events.PropertyVisibilityEvent;
+
+/**
+ * Provides no-op implementations of each of the methods within
+ * {@link InteractionListener}, to simplify the creation of new listeners.
+ */
+public class InteractionAdapter implements InteractionListener {
+
+    @Override
+    public void propertyVisible(final PropertyVisibilityEvent ev) {
+    }
+
+    @Override
+    public void propertyUsable(final PropertyUsabilityEvent ev) {
+    }
+
+    @Override
+    public void propertyAccessed(final PropertyAccessEvent ev) {
+    }
+
+    @Override
+    public void propertyModified(final PropertyModifyEvent ev) {
+    }
+
+    @Override
+    public void collectionVisible(final CollectionVisibilityEvent ev) {
+    }
+
+    @Override
+    public void collectionUsable(final CollectionUsabilityEvent ev) {
+    }
+
+    @Override
+    public void collectionAccessed(final CollectionAccessEvent ev) {
+    }
+
+    @Override
+    public void collectionAddedTo(final CollectionAddToEvent ev) {
+    }
+
+    @Override
+    public void collectionRemovedFrom(final CollectionRemoveFromEvent ev) {
+    }
+
+    @Override
+    public void collectionMethodInvoked(final CollectionMethodEvent interactionEvent) {
+    }
+
+    @Override
+    public void actionVisible(final ActionVisibilityEvent interactionEvent) {
+    }
+
+    @Override
+    public void actionUsable(final ActionUsabilityEvent ev) {
+    }
+
+    @Override
+    public void actionArgument(final ActionArgumentEvent ev) {
+    }
+
+    @Override
+    public void actionInvoked(final ActionInvocationEvent ev) {
+    }
+
+    @Override
+    public void objectPersisted(final ObjectValidityEvent ev) {
+    }
+
+    @Override
+    public void objectTitleRead(final ObjectTitleEvent ev) {
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/listeners/InteractionListener.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/listeners/InteractionListener.java b/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/listeners/InteractionListener.java
new file mode 100644
index 0000000..10c8c36
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/wrapper/listeners/InteractionListener.java
@@ -0,0 +1,194 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.applib.services.wrapper.listeners;
+
+import org.apache.isis.applib.events.ActionArgumentEvent;
+import org.apache.isis.applib.events.ActionInvocationEvent;
+import org.apache.isis.applib.events.ActionUsabilityEvent;
+import org.apache.isis.applib.events.ActionVisibilityEvent;
+import org.apache.isis.applib.events.CollectionAccessEvent;
+import org.apache.isis.applib.events.CollectionAddToEvent;
+import org.apache.isis.applib.events.CollectionMethodEvent;
+import org.apache.isis.applib.events.CollectionRemoveFromEvent;
+import org.apache.isis.applib.events.CollectionUsabilityEvent;
+import org.apache.isis.applib.events.CollectionVisibilityEvent;
+import org.apache.isis.applib.events.ObjectTitleEvent;
+import org.apache.isis.applib.events.ObjectValidityEvent;
+import org.apache.isis.applib.events.PropertyAccessEvent;
+import org.apache.isis.applib.events.PropertyModifyEvent;
+import org.apache.isis.applib.events.PropertyUsabilityEvent;
+import org.apache.isis.applib.events.PropertyVisibilityEvent;
+
+public interface InteractionListener {
+
+    /**
+     * The title was read.
+     * 
+     * @param ev
+     */
+    void objectTitleRead(ObjectTitleEvent ev);
+
+    /**
+     * The object was persisted (or an attempt to persist it was made).
+     * 
+     * @param ev
+     */
+    void objectPersisted(ObjectValidityEvent ev);
+
+    /**
+     * A check was made to determine if a property was visible.
+     * 
+     * @param ev
+     */
+    void propertyVisible(PropertyVisibilityEvent ev);
+
+    /**
+     * A check was made to determine if a property was usable.
+     * 
+     * @param ev
+     */
+    void propertyUsable(PropertyUsabilityEvent ev);
+
+    /**
+     * A property was read.
+     * 
+     * <p>
+     * Unlike most other events, a {@link PropertyAccessEvent} will never have
+     * been vetoed (that is, {@link PropertyAccessEvent#isVeto()} will always be
+     * <tt>false</tt>).
+     * 
+     * @param ev
+     */
+    void propertyAccessed(PropertyAccessEvent ev);
+
+    /**
+     * A property was modified (or an attempt to modify it was made)
+     * 
+     * <p>
+     * Use {@link PropertyModifyEvent#getProposed()} to determine whether the
+     * property was being set or cleared.
+     * 
+     * @param ev
+     */
+    void propertyModified(PropertyModifyEvent ev);
+
+    /**
+     * A check was made to determine if a collection was visible.
+     * 
+     * <p>
+     * Will be fired prior to
+     * {@link #collectionUsable(CollectionUsabilityEvent)}.
+     * 
+     * @param ev
+     */
+    void collectionVisible(CollectionVisibilityEvent ev);
+
+    /**
+     * A check was made to determine if a collection was usable.
+     * 
+     * <p>
+     * Will be fired prior to either
+     * {@link #collectionAccessed(CollectionAccessEvent)} or
+     * {@link #collectionAddedTo(CollectionAddToEvent)} or
+     * {@link #collectionRemovedFrom(CollectionRemoveFromEvent)}.
+     * 
+     * @param ev
+     */
+    void collectionUsable(CollectionUsabilityEvent ev);
+
+    /**
+     * A collection was read.
+     * 
+     * <p>
+     * Unlike most other events, a {@link CollectionAccessEvent} will never have
+     * been vetoed (that is, {@link CollectionAccessEvent#isVeto()} will always
+     * be <tt>false</tt>).
+     * 
+     * @param ev
+     */
+    void collectionAccessed(CollectionAccessEvent ev);
+
+    /**
+     * An object was added to the collection (or an attempt to add it was made).
+     * 
+     * @param ev
+     */
+    void collectionAddedTo(CollectionAddToEvent ev);
+
+    /**
+     * An object was removed from the collection (or an attempt to remove it was
+     * made).
+     * 
+     * @param ev
+     */
+    void collectionRemovedFrom(CollectionRemoveFromEvent ev);
+
+/**
+     * A method of a collection (such as <tt>isEmpty()</tt> or <tt>size()</tt>) has been invoked.
+     * 
+     * 
+     * <p>
+     * Unlike the other methods in this interface, the source of these events will be an instance of a
+     * Collection (such as <tt>java.util.List</tt>) rather than the domain object. (The domain object is
+     * {@link CollectionMethodEvent#getDomainObject() still available,  however).
+     * 
+     * @param interactionEvent
+     */
+    void collectionMethodInvoked(CollectionMethodEvent interactionEvent);
+
+    /**
+     * A check was made to determine if an action was visible.
+     * 
+     * <p>
+     * Will be fired prior to {@link #actionUsable(ActionUsabilityEvent)}.
+     * 
+     * @param ev
+     */
+    void actionVisible(ActionVisibilityEvent interactionEvent);
+
+    /**
+     * A check was made to determine if an action was usable.
+     * 
+     * <p>
+     * Will be fired prior to {@link #actionArgument(ActionArgumentEvent)}.
+     * 
+     * @param ev
+     */
+    void actionUsable(ActionUsabilityEvent ev);
+
+    /**
+     * A check was made as to whether an argument proposed for an action was
+     * valid.
+     * 
+     * <p>
+     * Will be fired prior to {@link #actionInvoked(ActionInvocationEvent)}.
+     * 
+     * @param ev
+     */
+    void actionArgument(ActionArgumentEvent ev);
+
+    /**
+     * An action was invoked (or an attempt to invoke it was made).
+     * 
+     * @param ev
+     */
+    void actionInvoked(ActionInvocationEvent ev);
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/core/pom.xml
----------------------------------------------------------------------
diff --git a/core/pom.xml b/core/pom.xml
index 4fd7a7a..78e674c 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -1055,7 +1055,7 @@ ${license.additional-notes}
                 <version>1.2.0-SNAPSHOT</version>
             </dependency>
 
-            <!-- isis-webserver -->
+            <!-- webserver -->
             <dependency>
                 <groupId>org.apache.isis.core</groupId>
                 <artifactId>isis-core-webserver</artifactId>
@@ -1070,6 +1070,14 @@ ${license.additional-notes}
                 <!-- not scope=test, because referenced by some sql-tests-common under compile scope -->
             </dependency>
 
+            <!-- wrapper service -->
+            <dependency>
+                <groupId>org.apache.isis.core</groupId>
+                <artifactId>isis-core-wrapper</artifactId>
+                <version>1.2.0-SNAPSHOT</version>
+            </dependency>
+
+
             <!-- default implementations of components -->
             <dependency>
                 <groupId>org.apache.isis.core</groupId>
@@ -1790,6 +1798,8 @@ ${license.additional-notes}
         <module>unittestsupport</module>
         <module>integtestsupport</module>
 
+        <module>wrapper</module>
+
         <module>tck</module>
     </modules>
 

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/core/wrapper/pom.xml
----------------------------------------------------------------------
diff --git a/core/wrapper/pom.xml b/core/wrapper/pom.xml
new file mode 100644
index 0000000..7627a02
--- /dev/null
+++ b/core/wrapper/pom.xml
@@ -0,0 +1,115 @@
+<?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.core</groupId>
+        <artifactId>isis</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+	</parent>
+
+	<artifactId>isis-core-wrapper</artifactId>
+
+	<name>Isis Core Wrapper Service</name>
+	<description>Isis Core Wrapper Service</description>
+
+
+	<properties>
+        <siteBaseDir>..</siteBaseDir>
+		<relativeUrl>wrapper/</relativeUrl>
+	</properties>
+
+    <!-- used in Site generation for relative references. -->
+    <url>http://isis.apache.org/${relativeUrl}</url>
+
+    <reporting>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-project-info-reports-plugin</artifactId>
+				<version>${maven-project-info-reports-plugin}</version>
+                <inherited>false</inherited>
+                <configuration>
+                	<dependencyLocationsEnabled>false</dependencyLocationsEnabled>
+                </configuration>
+                <reportSets>
+                    <reportSet>
+                        <inherited>false</inherited>
+                        <reports>
+                            <report>dependencies</report>
+                            <report>dependency-convergence</report>
+                            <report>plugins</report>
+                            <report>summary</report>
+                        </reports>
+                    </reportSet>
+                </reportSets>
+            </plugin>
+        </plugins>
+    </reporting>
+
+	<dependencies>
+        <dependency>
+		    <groupId>org.apache.isis.core</groupId>
+		    <artifactId>isis-core-runtime</artifactId>
+        </dependency>
+
+		<dependency>
+		    <groupId>org.apache.isis.core</groupId>
+		    <artifactId>isis-core-metamodel</artifactId>
+		    <type>test-jar</type>
+		    <scope>test</scope>
+        </dependency>
+		<dependency>
+		    <groupId>org.apache.isis.core</groupId>
+		    <artifactId>isis-core-runtime</artifactId>
+		    <type>test-jar</type>
+		    <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.isis.core</groupId>
+            <artifactId>isis-core-unittestsupport</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.isis.core</groupId>
+            <artifactId>isis-core-tck-dom</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+		<dependency>
+            <groupId>asm</groupId>
+            <artifactId>asm</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>org.objenesis</groupId>
+			<artifactId>objenesis</artifactId>
+		</dependency>
+
+		<dependency>
+			<groupId>cglib</groupId>
+			<artifactId>cglib-nodep</artifactId>
+		</dependency>
+
+	</dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/DomainObjectContainerWrapperFactory.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/DomainObjectContainerWrapperFactory.java b/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/DomainObjectContainerWrapperFactory.java
new file mode 100644
index 0000000..6b908c8
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/DomainObjectContainerWrapperFactory.java
@@ -0,0 +1,116 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.progmodel.wrapper.metamodel;
+
+import java.util.List;
+
+import org.apache.isis.applib.DomainObjectContainer;
+import org.apache.isis.applib.events.InteractionEvent;
+import org.apache.isis.applib.services.wrapper.WrapperFactory;
+import org.apache.isis.applib.services.wrapper.listeners.InteractionListener;
+import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
+import org.apache.isis.core.metamodel.adapter.ObjectPersistor;
+import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
+import org.apache.isis.core.metamodel.services.container.DomainObjectContainerDefault;
+import org.apache.isis.core.metamodel.spec.SpecificationLoader;
+import org.apache.isis.progmodel.wrapper.metamodel.internal.WrapperFactoryDefault;
+
+/**
+ * A combined {@link DomainObjectContainer} and {@link WrapperFactory}.
+ */
+public class DomainObjectContainerWrapperFactory extends DomainObjectContainerDefault implements WrapperFactory {
+
+    private final WrapperFactoryDefault wrapperFactoryDelegate;
+
+    public DomainObjectContainerWrapperFactory() {
+        this.wrapperFactoryDelegate = new WrapperFactoryDefault();
+    }
+
+    // /////////////////////////////////////////////////////////////
+    // Views
+    // /////////////////////////////////////////////////////////////
+
+    @Override
+    public <T> T wrap(final T domainObject) {
+        return wrapperFactoryDelegate.wrap(domainObject);
+    }
+
+    @Override
+    public <T> T wrap(final T domainObject, final ExecutionMode mode) {
+        return wrapperFactoryDelegate.wrap(domainObject, mode);
+    }
+
+    @Override
+    public boolean isWrapper(final Object possibleView) {
+        return wrapperFactoryDelegate.isWrapper(possibleView);
+    }
+
+    // /////////////////////////////////////////////////////////////
+    // Listeners
+    // /////////////////////////////////////////////////////////////
+
+    @Override
+    public List<InteractionListener> getListeners() {
+        return wrapperFactoryDelegate.getListeners();
+    }
+
+    @Override
+    public boolean addInteractionListener(final InteractionListener listener) {
+        return wrapperFactoryDelegate.addInteractionListener(listener);
+    }
+
+    @Override
+    public boolean removeInteractionListener(final InteractionListener listener) {
+        return wrapperFactoryDelegate.removeInteractionListener(listener);
+    }
+
+    @Override
+    public void notifyListeners(final InteractionEvent interactionEvent) {
+        wrapperFactoryDelegate.notifyListeners(interactionEvent);
+    }
+
+    // /////////////////////////////////////////////////////////////
+    // Dependencies
+    // /////////////////////////////////////////////////////////////
+
+    @Override
+    public void setSpecificationLookup(final SpecificationLoader specificationLookup) {
+        super.setSpecificationLookup(specificationLookup);
+        wrapperFactoryDelegate.setSpecificationLookup(specificationLookup);
+    }
+
+    @Override
+    public void setAuthenticationSessionProvider(final AuthenticationSessionProvider authenticationSessionProvider) {
+        super.setAuthenticationSessionProvider(authenticationSessionProvider);
+        wrapperFactoryDelegate.setAuthenticationSessionProvider(authenticationSessionProvider);
+    }
+
+    @Override
+    public void setAdapterManager(final AdapterManager adapterManager) {
+        super.setAdapterManager(adapterManager);
+        wrapperFactoryDelegate.setAdapterManager(adapterManager);
+    }
+
+    @Override
+    public void setObjectPersistor(final ObjectPersistor objectPersistor) {
+        super.setObjectPersistor(objectPersistor);
+        wrapperFactoryDelegate.setObjectPersistor(objectPersistor);
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/AbstractCollectionInvocationHandler.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/AbstractCollectionInvocationHandler.java b/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/AbstractCollectionInvocationHandler.java
new file mode 100644
index 0000000..75e5fce
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/AbstractCollectionInvocationHandler.java
@@ -0,0 +1,89 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.progmodel.wrapper.metamodel.internal;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.isis.applib.events.CollectionMethodEvent;
+import org.apache.isis.applib.events.InteractionEvent;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+
+abstract class AbstractCollectionInvocationHandler<T, C> extends DelegatingInvocationHandlerDefault<C> {
+
+    private final List<Method> interceptedMethods = new ArrayList<Method>();
+    private final List<Method> vetoedMethods = new ArrayList<Method>();
+    private final String collectionName;
+    private final OneToManyAssociation oneToManyAssociation;
+    private final T domainObject;
+
+    public AbstractCollectionInvocationHandler(final C collectionOrMapToProxy, final String collectionName, final DomainObjectInvocationHandler<T> handler, final OneToManyAssociation otma) {
+        super(collectionOrMapToProxy, handler.getHeadlessViewer(), handler.getExecutionMode());
+        this.collectionName = collectionName;
+        this.oneToManyAssociation = otma;
+        this.domainObject = handler.getDelegate();
+    }
+
+    protected Method intercept(final Method method) {
+        this.interceptedMethods.add(method);
+        return method;
+    }
+
+    protected Method veto(final Method method) {
+        this.vetoedMethods.add(method);
+        return method;
+    }
+
+    public String getCollectionName() {
+        return collectionName;
+    }
+
+    public OneToManyAssociation getCollection() {
+        return oneToManyAssociation;
+    }
+
+    public T getDomainObject() {
+        return domainObject;
+    }
+
+    @Override
+    public Object invoke(final Object collectionObject, final Method method, final Object[] args) throws Throwable {
+
+        // delegate
+        final Object returnValueObj = delegate(method, args);
+
+        if (interceptedMethods.contains(method)) {
+
+            resolveIfRequired(domainObject);
+
+            final InteractionEvent ev = new CollectionMethodEvent(getDelegate(), getCollection().getIdentifier(), getDomainObject(), method.getName(), args, returnValueObj);
+            notifyListeners(ev);
+            return returnValueObj;
+        }
+
+        if (vetoedMethods.contains(method)) {
+            throw new UnsupportedOperationException(String.format("Method '%s' may not be called directly.", method.getName()));
+        }
+
+        return returnValueObj;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/CgLibClassProxyFactory.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/CgLibClassProxyFactory.java b/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/CgLibClassProxyFactory.java
new file mode 100644
index 0000000..1646074
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/CgLibClassProxyFactory.java
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.progmodel.wrapper.metamodel.internal;
+
+import java.lang.reflect.InvocationHandler;
+
+import net.sf.cglib.proxy.Callback;
+import net.sf.cglib.proxy.Enhancer;
+import net.sf.cglib.proxy.Factory;
+import net.sf.cglib.proxy.MethodInterceptor;
+
+import org.apache.isis.applib.services.wrapper.WrapperObject;
+
+/**
+ * Factory generating a mock for a class.
+ * <p>
+ * Note that this class is stateful
+ */
+public class CgLibClassProxyFactory<T> implements IProxyFactory<T> {
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public T createProxy(final T toProxy, final InvocationHandler handler) {
+        final Class<T> proxyClass = (Class<T>) toProxy.getClass();
+        return createProxy(proxyClass, handler);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public T createProxy(final Class<T> toProxyClass, final InvocationHandler handler) {
+
+        final MethodInterceptor interceptor = new InvocationHandlerMethodInterceptor(handler);
+
+        // Create the proxy
+        final Enhancer enhancer = new Enhancer();
+        enhancer.setSuperclass(toProxyClass);
+        enhancer.setInterfaces(new Class[] { WrapperObject.class });
+        enhancer.setCallbackType(interceptor.getClass());
+
+        final Class<?> enhancedClass = enhancer.createClass();
+
+        Enhancer.registerCallbacks(enhancedClass, new Callback[] { interceptor });
+
+        Factory factory;
+        try {
+            factory = (Factory) ClassInstantiatorFactoryCE.getInstantiator().newInstance(enhancedClass);
+        } catch (final InstantiationException e) {
+            throw new RuntimeException("Fail to instantiate mock for " + toProxyClass + " on " + ClassInstantiatorFactoryCE.getJVM() + " JVM");
+        }
+
+        return (T) factory;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/CgLibProxy.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/CgLibProxy.java b/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/CgLibProxy.java
new file mode 100644
index 0000000..da4211c
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/CgLibProxy.java
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.progmodel.wrapper.metamodel.internal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import net.sf.cglib.proxy.Enhancer;
+import net.sf.cglib.proxy.Factory;
+
+import org.apache.isis.applib.services.wrapper.WrapperObject;
+import org.apache.isis.core.metamodel.specloader.classsubstitutor.CglibEnhanced;
+
+public class CgLibProxy<T> {
+
+    private final DelegatingInvocationHandler<T> handler;
+
+    public CgLibProxy(final DelegatingInvocationHandler<T> handler) {
+        this.handler = handler;
+    }
+
+    @SuppressWarnings("unchecked")
+    public T proxy() {
+
+        final T toProxy = handler.getDelegate();
+
+        // handle if already proxied using cglib.
+        if (CglibEnhanced.class.isAssignableFrom(toProxy.getClass())) {
+
+            handler.setResolveObjectChangedEnabled(true);
+
+            final Class<? extends Object> enhancedClass = toProxy.getClass();
+            final Class<? extends Object> origSuperclass = toProxy.getClass().getSuperclass();
+
+            final List<Class> interfaces = new ArrayList<Class>();
+            interfaces.addAll(Arrays.asList(enhancedClass.getInterfaces()));
+            interfaces.remove(Factory.class); // if there.
+            interfaces.add(WrapperObject.class);
+
+            InvocationHandlerMethodInterceptor interceptor = new InvocationHandlerMethodInterceptor(handler);
+            return (T) Enhancer.create(origSuperclass, interfaces.toArray(new Class[] {}), interceptor);
+        }
+
+        final Class<T> clazz = (Class<T>) toProxy.getClass();
+
+        T proxy = null;
+        try {
+            final IProxyFactory<T> proxyFactory = clazz.isInterface() ? new JavaProxyFactory<T>() : new CgLibClassProxyFactory<T>();
+            proxy = proxyFactory.createProxy(clazz, handler);
+        } catch (final RuntimeExceptionWrapper e) {
+            throw (RuntimeException) e.getRuntimeException().fillInStackTrace();
+        }
+        return proxy;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/ClassInstantiatorFactoryCE.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/ClassInstantiatorFactoryCE.java b/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/ClassInstantiatorFactoryCE.java
new file mode 100644
index 0000000..85bc196
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/ClassInstantiatorFactoryCE.java
@@ -0,0 +1,65 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.progmodel.wrapper.metamodel.internal;
+
+/**
+ * Factory returning a {@link IClassInstantiatorCE}for the current JVM
+ */
+class ClassInstantiatorFactoryCE {
+
+    private static IClassInstantiatorCE instantiator = new ObjenesisClassInstantiatorCE();
+
+    // ///CLOVER:OFF
+    private ClassInstantiatorFactoryCE() {
+    }
+
+    // ///CLOVER:ON
+
+    /**
+     * Returns the current JVM as specified in the Systtem properties
+     * 
+     * @return current JVM
+     */
+    public static String getJVM() {
+        return System.getProperty("java.vm.vendor");
+    }
+
+    /**
+     * Returns the current JVM specification version (1.5, 1.4, 1.3)
+     * 
+     * @return current JVM specification version
+     */
+    public static String getJVMSpecificationVersion() {
+        return System.getProperty("java.specification.version");
+    }
+
+    public static boolean is1_3Specifications() {
+        return getJVMSpecificationVersion().equals("1.3");
+    }
+
+    /**
+     * Returns a class instantiator suitable for the current JVM
+     * 
+     * @return a class instantiator usable on the current JVM
+     */
+    public static IClassInstantiatorCE getInstantiator() {
+        return instantiator;
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/CollectionInvocationHandler.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/CollectionInvocationHandler.java b/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/CollectionInvocationHandler.java
new file mode 100644
index 0000000..d143af6
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/CollectionInvocationHandler.java
@@ -0,0 +1,54 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.progmodel.wrapper.metamodel.internal;
+
+import static org.apache.isis.core.commons.lang.MethodUtils.getMethod;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+
+class CollectionInvocationHandler<T, R> extends AbstractCollectionInvocationHandler<T, R> {
+
+    public CollectionInvocationHandler(final R collectionToProxy, final String collectionName, final DomainObjectInvocationHandler<T> handler, final OneToManyAssociation otma) {
+        super(collectionToProxy, collectionName, handler, otma);
+
+        try {
+            intercept(getMethod(collectionToProxy, "contains", Object.class));
+            intercept(getMethod(collectionToProxy, "size"));
+            intercept(getMethod(collectionToProxy, "isEmpty"));
+            if (collectionToProxy instanceof List) {
+                intercept(getMethod(collectionToProxy, "get", int.class));
+            }
+            veto(getMethod(collectionToProxy, "add", Object.class));
+            veto(getMethod(collectionToProxy, "remove", Object.class));
+            veto(getMethod(collectionToProxy, "addAll", Collection.class));
+            veto(getMethod(collectionToProxy, "removeAll", Collection.class));
+            veto(getMethod(collectionToProxy, "retainAll", Collection.class));
+            veto(getMethod(collectionToProxy, "clear"));
+        } catch (final NoSuchMethodException e) {
+            // ///CLOVER:OFF
+            throw new RuntimeException("A Collection method could not be found: " + e.getMessage());
+            // ///CLOVER:ON
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/cd0735d2/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/DelegatingInvocationHandler.java
----------------------------------------------------------------------
diff --git a/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/DelegatingInvocationHandler.java b/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/DelegatingInvocationHandler.java
new file mode 100644
index 0000000..5772b88
--- /dev/null
+++ b/core/wrapper/src/main/java/org/apache/isis/progmodel/wrapper/metamodel/internal/DelegatingInvocationHandler.java
@@ -0,0 +1,32 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.progmodel.wrapper.metamodel.internal;
+
+import java.lang.reflect.InvocationHandler;
+
+public interface DelegatingInvocationHandler<T> extends InvocationHandler {
+
+    T getDelegate();
+
+    public boolean isResolveObjectChangedEnabled();
+
+    public void setResolveObjectChangedEnabled(boolean resolveObjectChangedEnabled);
+
+}