You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2014/05/11 19:41:49 UTC

[04/16] git commit: ISIS-550: PostsCollectionAddToEvent first-cut impl

ISIS-550: PostsCollectionAddToEvent first-cut impl

... pretty much there.


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

Branch: refs/heads/master
Commit: 2637a0551f49c2373154cd00b78791039c8d7dc0
Parents: 43c50c4
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Wed May 7 08:53:41 2014 +0100
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Wed May 7 08:53:41 2014 +0100

----------------------------------------------------------------------
 .../annotation/PostsCollectionAddedToEvent.java |   9 +-
 .../PostsCollectionRemovedFromEvent.java        |   9 +-
 .../annotation/PostsPropertyChangedEvent.java   |   9 +-
 .../isis/applib/annotation/WrapperPolicy.java   |  35 ++++
 .../eventbus/CollectionAddedToEvent.java        |  37 ++--
 .../eventbus/CollectionRemovedFromEvent.java    |  35 ++--
 .../services/eventbus/PropertyChangedEvent.java |  23 ++-
 .../applib/services/publish/EventPayload.java   |   2 +-
 .../ObjectResolveAndObjectChangedEnhancer.java  |   4 +-
 .../ObjectResolveAndObjectChangedEnhancer.java  |   4 +-
 .../core/metamodel/facets/ImperativeFacet.java  |  85 +++++++++
 .../metamodel/facets/ImperativeFacetUtils.java  |  76 ++------
 .../facets/PostsEventWithWrapperPolicy.java     |  61 +++++++
 .../event/PostsAddedToCollectionEventFacet.java |  34 ----
 .../PostsCollectionAddToEventFacetAbstract.java |  37 ----
 .../event/PostsCollectionAddedToEventFacet.java |  37 ++++
 ...ostsCollectionAddedToEventFacetAbstract.java |  55 ++++++
 .../event/PostsPropertyChangedEventFacet.java   |   3 +-
 .../PostsPropertyChangedEventFacetAbstract.java |  17 +-
 .../collection/CollectionFacetFactory.java      |   6 +-
 ...lectionAddToEventAnnotationFacetFactory.java | 117 -------------
 ...ostsCollectionAddToEventFacetAnnotation.java | 154 -----------------
 ...ctionAddedToEventAnnotationFacetFactory.java |  78 +++++++++
 ...tsCollectionAddedToEventFacetAnnotation.java | 173 +++++++++++++++++++
 ...pertyChangedEventAnnotationFacetFactory.java |  11 +-
 ...ostsPropertyChangedEventFacetAnnotation.java |  64 ++++---
 .../dflt/ProgrammingModelFacetsJava5.java       |   4 +
 .../facets/ImperativeFacetUtilsTest.java        |  16 +-
 ...nAddedEventFacetAnnotationTest_newEvent.java |  34 ++--
 ...hangedEventFacetAnnotationTest_newEvent.java |  14 +-
 .../AbstractCollectionInvocationHandler.java    |   7 +-
 .../handlers/DomainObjectInvocationHandler.java |  96 ++++++++--
 .../dom/src/main/java/dom/todo/ToDoItem.java    |  25 ++-
 .../java/dom/todo/ToDoItemSubscriptions.java    |  14 ++
 .../webapp/pom.xml                              |   4 +
 .../src/main/webapp/WEB-INF/isis.properties     |   1 +
 36 files changed, 884 insertions(+), 506 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/applib/src/main/java/org/apache/isis/applib/annotation/PostsCollectionAddedToEvent.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/PostsCollectionAddedToEvent.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/PostsCollectionAddedToEvent.java
index e67be7f..04037b8 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/PostsCollectionAddedToEvent.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/PostsCollectionAddedToEvent.java
@@ -25,6 +25,7 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 import org.apache.isis.applib.services.eventbus.CollectionAddedToEvent;
+import org.apache.isis.applib.services.wrapper.WrapperFactory;
 
 /**
  * Applies only to collections; any changes should be propagated as events to subscribers.  
@@ -58,6 +59,12 @@ public @interface PostsCollectionAddedToEvent {
      * <p>
      * This subclass must provide a no-arg constructor; the fields are set reflectively.
      */
-    Class<? extends CollectionAddedToEvent<?,?>> value();
+    Class<? extends CollectionAddedToEvent<?,?>> value() default CollectionAddedToEvent.Default.class;
+    
+    /**
+     * If invoked through the {@link WrapperFactory}, whether business rules (&quot;see it, use it, do it&quot;)
+     * should be enforced or not.
+     */
+    WrapperPolicy wrapperPolicy() default WrapperPolicy.ENFORCE_RULES;
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/applib/src/main/java/org/apache/isis/applib/annotation/PostsCollectionRemovedFromEvent.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/PostsCollectionRemovedFromEvent.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/PostsCollectionRemovedFromEvent.java
index f560434..f94851f 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/PostsCollectionRemovedFromEvent.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/PostsCollectionRemovedFromEvent.java
@@ -25,6 +25,7 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 import org.apache.isis.applib.services.eventbus.CollectionRemovedFromEvent;
+import org.apache.isis.applib.services.wrapper.WrapperFactory;
 
 /**
  * Applies only to collections; any changes should be propagated as events to subscribers.  
@@ -58,6 +59,12 @@ public @interface PostsCollectionRemovedFromEvent {
      * <p>
      * This subclass must provide a no-arg constructor; the fields are set reflectively.
      */
-    Class<? extends CollectionRemovedFromEvent<?,?>> value();
+    Class<? extends CollectionRemovedFromEvent<?,?>> value() default CollectionRemovedFromEvent.Default.class;
+
+    /**
+     * If invoked through the {@link WrapperFactory}, whether business rules (&quot;see it, use it, do it&quot;)
+     * should be enforced or not.
+     */
+    WrapperPolicy wrapperPolicy() default WrapperPolicy.ENFORCE_RULES;
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/applib/src/main/java/org/apache/isis/applib/annotation/PostsPropertyChangedEvent.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/PostsPropertyChangedEvent.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/PostsPropertyChangedEvent.java
index f1d9491..b55c961 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/PostsPropertyChangedEvent.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/PostsPropertyChangedEvent.java
@@ -25,6 +25,7 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 import org.apache.isis.applib.services.eventbus.PropertyChangedEvent;
+import org.apache.isis.applib.services.wrapper.WrapperFactory;
 
 /**
  * Applies only to properties; any changes should be propagated as events to subscribers.  
@@ -54,6 +55,12 @@ public @interface PostsPropertyChangedEvent {
      * <p>
      * This subclass must provide a no-arg constructor; the fields are set reflectively.
      */
-    Class<? extends PropertyChangedEvent<?,?>> value();
+    Class<? extends PropertyChangedEvent<?,?>> value() default PropertyChangedEvent.Default.class;
+
+    /**
+     * If invoked through the {@link WrapperFactory}, whether business rules (&quot;see it, use it, do it&quot;)
+     * should be enforced or not.
+     */
+    WrapperPolicy wrapperPolicy() default WrapperPolicy.ENFORCE_RULES;
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/applib/src/main/java/org/apache/isis/applib/annotation/WrapperPolicy.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/WrapperPolicy.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/WrapperPolicy.java
new file mode 100644
index 0000000..a69c817
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/WrapperPolicy.java
@@ -0,0 +1,35 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.applib.annotation;
+
+import org.apache.isis.applib.services.wrapper.WrapperFactory;
+
+/**
+ * An attribute of {@link PostsPropertyChangedEvent}, {@link PostsCollectionAddedToEvent} and other related annotations;
+ * is a hint to indicate that if the object member is interacted with through a {@link WrapperFactory}, then whether 
+ * business rules (&quot;see it, use it, do it&quot;) should be enforced or not.
+ * 
+ * <p>
+ * This provides a half-way house between strictly UI-interactions and fully programmatic interactions, so that an 
+ * event can be fired programmatically even if the object is disabled in the UI.
+ */
+public enum WrapperPolicy {
+    ENFORCE_RULES,
+    SKIP_RULES
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/applib/src/main/java/org/apache/isis/applib/services/eventbus/CollectionAddedToEvent.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/eventbus/CollectionAddedToEvent.java b/core/applib/src/main/java/org/apache/isis/applib/services/eventbus/CollectionAddedToEvent.java
index 10229f7..7b2d8f1 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/eventbus/CollectionAddedToEvent.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/eventbus/CollectionAddedToEvent.java
@@ -18,38 +18,55 @@
  */
 package org.apache.isis.applib.services.eventbus;
 
+import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.annotation.PostsPropertyChangedEvent;
 import org.apache.isis.applib.util.ObjectContracts;
 
 public abstract class CollectionAddedToEvent<S,T> {
+    
+    public static class Default extends CollectionAddedToEvent<Object, Object> {}
+
     private final S source;
-    private final T addedValue;
+    private final Identifier identifier;
+    private final T value;
     
     /**
      * To instantiate reflectively when the {@link PostsPropertyChangedEvent} annotation
      * is used.
      * 
      * <p>
-     * The fields ({@link #source} and {@link #addedValue} are then set reflectively.
+     * The fields ({@link #source} and {@link #value} are then set reflectively.
      */
     public CollectionAddedToEvent() {
-        this(null, null);
+        this(null, null, null);
     }
-    public CollectionAddedToEvent(S source, T addedValue) {
-        this.source = source;
-        this.addedValue = addedValue;
+    
+    /**
+     * @deprecated - use {@link #CollectionAddedToEvent(Object, Identifier, Object)}
+     */
+    @Deprecated
+    public CollectionAddedToEvent(S source, T value) {
+        this(source, null, value);
     }
 
+    public CollectionAddedToEvent(S source, Identifier identifier, T value) {
+        this.source = source;
+        this.identifier = identifier;
+        this.value = value;
+    }
+    
     public S getSource() {
         return source;
     }
-    
-    public T getAddedValue() {
-        return addedValue;
+    public Identifier getIdentifier() {
+        return identifier;
+    }
+    public T getValue() {
+        return value;
     }
     
     @Override
     public String toString() {
-        return ObjectContracts.toString(this, "source,addedValue");
+        return ObjectContracts.toString(this, "source,identifier,value");
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/applib/src/main/java/org/apache/isis/applib/services/eventbus/CollectionRemovedFromEvent.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/eventbus/CollectionRemovedFromEvent.java b/core/applib/src/main/java/org/apache/isis/applib/services/eventbus/CollectionRemovedFromEvent.java
index 84289da..17b8fed 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/eventbus/CollectionRemovedFromEvent.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/eventbus/CollectionRemovedFromEvent.java
@@ -18,37 +18,52 @@
  */
 package org.apache.isis.applib.services.eventbus;
 
+import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.util.ObjectContracts;
 
 public abstract class CollectionRemovedFromEvent<S,T> {
+    
+    public static class Default extends CollectionRemovedFromEvent<Object, Object> {}
+
     private final S source;
-    private final T removedValue;
+    private final Identifier identifier;
+    private final T value;
     
     /**
-     * To instantiate reflectively when the {@link PostsCollectionAddedToEvent} annotation
+     * To instantiate reflectively when the {@link PostsCollectionRemovedFromEvent} annotation
      * is used.
      * 
      * <p>
-     * The fields ({@link #source} and {@link #removedValue} are then set reflectively.
+     * The fields ({@link #source} and {@link #value} are then set reflectively.
      */
     public CollectionRemovedFromEvent() {
-        this(null, null);
+        this(null, null, null);
     }
-    public CollectionRemovedFromEvent(S source, T removedValue) {
+    /**
+     * @deprecated - use {@link #CollectionRemovedFromEvent(Object, Identifier, Object)}
+     */
+    @Deprecated
+    public CollectionRemovedFromEvent(S source, T value) {
+        this(source, null, value);
+    }
+    public CollectionRemovedFromEvent(S source, Identifier identifier, T value) {
         this.source = source;
-        this.removedValue = removedValue;
+        this.identifier = identifier;
+        this.value = value;
     }
 
     public S getSource() {
         return source;
     }
-    
-    public T getRemovedValue() {
-        return removedValue;
+    public Identifier getIdentifier() {
+        return identifier;
+    }
+    public T getValue() {
+        return value;
     }
     
     @Override
     public String toString() {
-        return ObjectContracts.toString(this, "source,removedValue");
+        return ObjectContracts.toString(this, "source,value");
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/applib/src/main/java/org/apache/isis/applib/services/eventbus/PropertyChangedEvent.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/eventbus/PropertyChangedEvent.java b/core/applib/src/main/java/org/apache/isis/applib/services/eventbus/PropertyChangedEvent.java
index e528867..9ae0afe 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/eventbus/PropertyChangedEvent.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/eventbus/PropertyChangedEvent.java
@@ -18,11 +18,16 @@
  */
 package org.apache.isis.applib.services.eventbus;
 
+import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.annotation.PostsPropertyChangedEvent;
 import org.apache.isis.applib.util.ObjectContracts;
 
 public abstract class PropertyChangedEvent<S,T> {
+    
+    public static class Default extends PropertyChangedEvent<Object, Object> {}
+    
     private final S source;
+    private final Identifier identifier;
     private final T oldValue;
     private final T newValue;
     
@@ -35,18 +40,30 @@ public abstract class PropertyChangedEvent<S,T> {
      * then set reflectively.
      */
     public PropertyChangedEvent() {
-        this(null, null, null);
+        this(null, null, null, null);
     }
+    
+    /**
+     * @deprecated - use {@link #PropertyChangedEvent(Object, Identifier, Object, Object)}.
+     */
+    @Deprecated
     public PropertyChangedEvent(S source, T oldValue, T newValue) {
+        this(source, null, oldValue, newValue);
+    }
+
+    public PropertyChangedEvent(S source, Identifier identifier, T oldValue, T newValue) {
         this.source = source;
+        this.identifier = identifier;
         this.oldValue = oldValue;
         this.newValue = newValue;
     }
-
+    
     public S getSource() {
         return source;
     }
-    
+    public Identifier getIdentifier() {
+        return identifier;
+    }
     public T getOldValue() {
         return oldValue;
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventPayload.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventPayload.java b/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventPayload.java
index cbeb1fd..4dd96e1 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventPayload.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/publish/EventPayload.java
@@ -32,7 +32,7 @@ import org.apache.isis.applib.annotation.Programmatic;
  * This should be prepared in a way that can be processed by the {@link EventSerializer}.  For example:
  * <ul>
  * <li>The {@link EventSerializer.Simple simple event serializer} simply invokes
- * {@link Object#toString() toString()} on the payload.  Use the {@link Simple simple} implementation
+ * {@link Object#toString() toString()} on the payload.  Use the {@link Default simple} implementation
  * which simply wraps a string.
  * </li>
  * <li>The <tt>RestfulObjectsSpecEventSerializer</tt> event serializer expects a pojo domain object

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/bytecode-cglib/src/main/java/org/apache/isis/core/bytecode/cglib/ObjectResolveAndObjectChangedEnhancer.java
----------------------------------------------------------------------
diff --git a/core/bytecode-cglib/src/main/java/org/apache/isis/core/bytecode/cglib/ObjectResolveAndObjectChangedEnhancer.java b/core/bytecode-cglib/src/main/java/org/apache/isis/core/bytecode/cglib/ObjectResolveAndObjectChangedEnhancer.java
index 64ce728..d5c68a7 100644
--- a/core/bytecode-cglib/src/main/java/org/apache/isis/core/bytecode/cglib/ObjectResolveAndObjectChangedEnhancer.java
+++ b/core/bytecode-cglib/src/main/java/org/apache/isis/core/bytecode/cglib/ObjectResolveAndObjectChangedEnhancer.java
@@ -29,8 +29,8 @@ import net.sf.cglib.proxy.MethodInterceptor;
 import net.sf.cglib.proxy.MethodProxy;
 
 import org.apache.isis.core.commons.lang.ArrayExtensions;
+import org.apache.isis.core.metamodel.facets.ImperativeFacet;
 import org.apache.isis.core.metamodel.facets.ImperativeFacetUtils;
-import org.apache.isis.core.metamodel.facets.ImperativeFacetUtils.ImperativeFacetFlags;
 import org.apache.isis.core.metamodel.spec.SpecificationLoaderSpi;
 import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
 import org.apache.isis.core.metamodel.specloader.classsubstitutor.CglibEnhanced;
@@ -62,7 +62,7 @@ public class ObjectResolveAndObjectChangedEnhancer extends ObjectResolveAndObjec
             public Object intercept(final Object proxied, final Method proxiedMethod, final Object[] args, final MethodProxy proxyMethod) throws Throwable {
 
                 final boolean ignore = proxiedMethod.getDeclaringClass().equals(Object.class);
-                ImperativeFacetFlags flags = null;
+                ImperativeFacet.Flags flags = null;
 
                 if (!ignore) {
                     final ObjectSpecificationDefault targetObjSpec = getJavaSpecificationOfOwningClass(proxiedMethod);

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/bytecode-javassist/src/main/java/org/apache/isis/core/bytecode/javassist/ObjectResolveAndObjectChangedEnhancer.java
----------------------------------------------------------------------
diff --git a/core/bytecode-javassist/src/main/java/org/apache/isis/core/bytecode/javassist/ObjectResolveAndObjectChangedEnhancer.java b/core/bytecode-javassist/src/main/java/org/apache/isis/core/bytecode/javassist/ObjectResolveAndObjectChangedEnhancer.java
index df4ded0..b1103b0 100644
--- a/core/bytecode-javassist/src/main/java/org/apache/isis/core/bytecode/javassist/ObjectResolveAndObjectChangedEnhancer.java
+++ b/core/bytecode-javassist/src/main/java/org/apache/isis/core/bytecode/javassist/ObjectResolveAndObjectChangedEnhancer.java
@@ -28,8 +28,8 @@ import javassist.util.proxy.ProxyObject;
 
 import org.apache.isis.core.commons.exceptions.IsisException;
 import org.apache.isis.core.commons.lang.ArrayExtensions;
+import org.apache.isis.core.metamodel.facets.ImperativeFacet;
 import org.apache.isis.core.metamodel.facets.ImperativeFacetUtils;
-import org.apache.isis.core.metamodel.facets.ImperativeFacetUtils.ImperativeFacetFlags;
 import org.apache.isis.core.metamodel.spec.SpecificationLoaderSpi;
 import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
 import org.apache.isis.core.metamodel.specloader.specimpl.dflt.ObjectSpecificationDefault;
@@ -54,7 +54,7 @@ public class ObjectResolveAndObjectChangedEnhancer extends ObjectResolveAndObjec
             public Object invoke(final Object proxied, final Method proxyMethod, final Method proxiedMethod, final Object[] args) throws Throwable {
 
                 final boolean ignore = proxyMethod.getDeclaringClass().equals(Object.class);
-                ImperativeFacetFlags flags = null;
+                ImperativeFacet.Flags flags = null;
 
                 if (!ignore) {
                     final ObjectSpecificationDefault targetObjSpec = getJavaSpecificationOfOwningClass(proxiedMethod);

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/ImperativeFacet.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/ImperativeFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/ImperativeFacet.java
index f1f0e90..f702496 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/ImperativeFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/ImperativeFacet.java
@@ -24,6 +24,9 @@ import java.util.List;
 
 import org.apache.isis.applib.DomainObjectContainer;
 import org.apache.isis.applib.filter.Filter;
+import org.apache.isis.applib.filter.Filters;
+import org.apache.isis.core.commons.lang.ObjectExtensions;
+import org.apache.isis.core.metamodel.facetapi.DecoratingFacet;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
@@ -93,4 +96,86 @@ public interface ImperativeFacet {
      */
     public boolean impliesObjectChanged();
 
+
+    // //////////////////////////////////////
+
+    public static class Util {
+        private Util(){}
+
+        /**
+         * Returns the provided {@link Facet facet} as an {@link ImperativeFacet} if
+         * it either is one or if it is a {@link DecoratingFacet} that in turn wraps
+         * an {@link ImperativeFacet}.
+         * 
+         * <p>
+         * Otherwise, returns <tt>null</tt>.
+         */
+        public static ImperativeFacet getImperativeFacet(final Facet facet) {
+            if (facet instanceof ImperativeFacet) {
+                return (ImperativeFacet) facet;
+            }
+            if (facet.getUnderlyingFacet() instanceof ImperativeFacet) {
+                return (ImperativeFacet) facet.getUnderlyingFacet();
+            }
+            if (facet instanceof DecoratingFacet) {
+                final DecoratingFacet<?> decoratingFacet = ObjectExtensions.asT(facet);
+                return getImperativeFacet(decoratingFacet.getDecoratedFacet());
+            }
+            return null;
+        }
+        
+        public static boolean isImperativeFacet(final Facet facet) {
+            return getImperativeFacet(facet) != null;
+        }
+
+        public static Flags getImperativeFacetFlags(final ObjectMember member, final Method method) {
+            final Flags flags = new Flags();
+            if (member == null) {
+                return flags;
+            }
+            final List<Facet> allFacets = member.getFacets(Filters.anyOfType(Facet.class));
+            for (final Facet facet : allFacets) {
+                final ImperativeFacet imperativeFacet = ImperativeFacetUtils.getImperativeFacet(facet);
+                if (imperativeFacet == null) {
+                    continue;
+                }
+                final List<Method> methods = imperativeFacet.getMethods();
+                if (!methods.contains(method)) {
+                    continue;
+                }
+                flags.apply(imperativeFacet);
+
+                // no need to search further
+                if (flags.bothSet()) {
+                    break;
+                }
+            }
+            return flags;
+        }
+    }
+
+    public static class Flags {
+        private boolean impliesResolve;
+        private boolean impliesObjectChanged;
+
+        public void apply(final ImperativeFacet imperativeFacet) {
+            this.impliesResolve |= imperativeFacet.impliesResolve();
+            this.impliesObjectChanged |= imperativeFacet.impliesObjectChanged();
+        }
+
+        public boolean bothSet() {
+            return impliesResolve && impliesObjectChanged;
+        }
+
+        public boolean impliesResolve() {
+            return impliesResolve;
+        }
+
+        public boolean impliesObjectChanged() {
+            return impliesObjectChanged;
+        }
+    }
+
+
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/ImperativeFacetUtils.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/ImperativeFacetUtils.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/ImperativeFacetUtils.java
index b4e0beb..049ba3e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/ImperativeFacetUtils.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/ImperativeFacetUtils.java
@@ -23,8 +23,6 @@ import java.lang.reflect.Method;
 import java.util.List;
 
 import org.apache.isis.applib.filter.Filters;
-import org.apache.isis.core.commons.lang.ObjectExtensions;
-import org.apache.isis.core.metamodel.facetapi.DecoratingFacet;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
 
@@ -34,73 +32,27 @@ public final class ImperativeFacetUtils {
     }
 
     /**
-     * Returns the provided {@link Facet facet} as an {@link ImperativeFacet} if
-     * it either is one or if it is a {@link DecoratingFacet} that in turn wraps
-     * an {@link ImperativeFacet}.
-     * 
-     * <p>
-     * Otherwise, returns <tt>null</tt>.
+     * @deprecated - use {@link ImperativeFacet.Util#getImperativeFacet(Facet)}
      */
+    @Deprecated
     public static ImperativeFacet getImperativeFacet(final Facet facet) {
-        if (facet instanceof ImperativeFacet) {
-            return (ImperativeFacet) facet;
-        }
-        if (facet instanceof DecoratingFacet) {
-            final DecoratingFacet<?> decoratingFacet = ObjectExtensions.asT(facet);
-            return getImperativeFacet(decoratingFacet.getDecoratedFacet());
-        }
-        return null;
+        return ImperativeFacet.Util.getImperativeFacet(facet);
     }
 
+    /**
+     * @deprecated - use {@link ImperativeFacet.Util#isImperativeFacet(Facet)}
+     */
+    @Deprecated
     public static boolean isImperativeFacet(final Facet facet) {
-        return getImperativeFacet(facet) != null;
+        return ImperativeFacet.Util.isImperativeFacet(facet);
     }
 
-    public static class ImperativeFacetFlags {
-        private boolean impliesResolve;
-        private boolean impliesObjectChanged;
-
-        public void apply(final ImperativeFacet imperativeFacet) {
-            this.impliesResolve |= imperativeFacet.impliesResolve();
-            this.impliesObjectChanged |= imperativeFacet.impliesObjectChanged();
-        }
-
-        public boolean bothSet() {
-            return impliesResolve && impliesObjectChanged;
-        }
-
-        public boolean impliesResolve() {
-            return impliesResolve;
-        }
-
-        public boolean impliesObjectChanged() {
-            return impliesObjectChanged;
-        }
-    }
-
-    public static ImperativeFacetFlags getImperativeFacetFlags(final ObjectMember member, final Method method) {
-        final ImperativeFacetFlags flags = new ImperativeFacetFlags();
-        if (member == null) {
-            return flags;
-        }
-        final List<Facet> allFacets = member.getFacets(Filters.anyOfType(Facet.class));
-        for (final Facet facet : allFacets) {
-            final ImperativeFacet imperativeFacet = ImperativeFacetUtils.getImperativeFacet(facet);
-            if (imperativeFacet == null) {
-                continue;
-            }
-            final List<Method> methods = imperativeFacet.getMethods();
-            if (!methods.contains(method)) {
-                continue;
-            }
-            flags.apply(imperativeFacet);
-
-            // no need to search further
-            if (flags.bothSet()) {
-                break;
-            }
-        }
-        return flags;
+    /**
+     * @deprecated - use {@link ImperativeFacet.Util#getImperativeFacet(Facet)}
+     */
+    @Deprecated
+    public static ImperativeFacet.Flags getImperativeFacetFlags(final ObjectMember member, final Method method) {
+        return ImperativeFacet.Util.getImperativeFacetFlags(member, method);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/PostsEventWithWrapperPolicy.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/PostsEventWithWrapperPolicy.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/PostsEventWithWrapperPolicy.java
new file mode 100644
index 0000000..0c12c1c
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/PostsEventWithWrapperPolicy.java
@@ -0,0 +1,61 @@
+/*
+ *  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.core.metamodel.facets;
+
+import org.apache.isis.applib.annotation.WrapperPolicy;
+import org.apache.isis.applib.services.eventbus.EventBusService;
+import org.apache.isis.applib.services.eventbus.PropertyChangedEvent;
+import org.apache.isis.core.commons.lang.ObjectExtensions;
+import org.apache.isis.core.metamodel.facetapi.DecoratingFacet;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.MultiTypedFacet;
+import org.apache.isis.core.metamodel.facets.properties.modify.PropertyClearFacet;
+import org.apache.isis.core.metamodel.facets.properties.modify.PropertySetterFacet;
+
+public interface PostsEventWithWrapperPolicy {
+
+    WrapperPolicy getWrapperPolicy();
+    
+    public static class Util {
+        private Util(){}
+
+        /**
+         * Returns the provided {@link Facet facet} as an {@link PostsEventWithWrapperPolicy} if
+         * it either is one or if it is a {@link DecoratingFacet} that in turn wraps
+         * an {@link PostsEventWithWrapperPolicy}.
+         * 
+         * <p>
+         * Otherwise, returns <tt>null</tt>.
+         */
+        public static PostsEventWithWrapperPolicy getWrapperPolicyFacet(final Facet facet) {
+            if (facet instanceof PostsEventWithWrapperPolicy) {
+                return (PostsEventWithWrapperPolicy) facet;
+            }
+            if (facet.getUnderlyingFacet() instanceof PostsEventWithWrapperPolicy) {
+                return (PostsEventWithWrapperPolicy) facet.getUnderlyingFacet();
+            }
+            if (facet instanceof DecoratingFacet) {
+                final DecoratingFacet<?> decoratingFacet = ObjectExtensions.asT(facet);
+                return getWrapperPolicyFacet(decoratingFacet.getDecoratedFacet());
+            }
+            return null;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/event/PostsAddedToCollectionEventFacet.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/event/PostsAddedToCollectionEventFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/event/PostsAddedToCollectionEventFacet.java
deleted file mode 100644
index b2f6c18..0000000
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/event/PostsAddedToCollectionEventFacet.java
+++ /dev/null
@@ -1,34 +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.core.metamodel.facets.collections.event;
-
-import org.apache.isis.applib.services.eventbus.EventBusService;
-import org.apache.isis.applib.services.eventbus.PropertyChangedEvent;
-import org.apache.isis.core.metamodel.facetapi.Facet;
-import org.apache.isis.core.metamodel.facetapi.MultiTypedFacet;
-import org.apache.isis.core.metamodel.facets.collections.modify.CollectionAddToFacet;
-
-/**
- * Indicates that (the specified subclass of) {@link PropertyChangedEvent} should be posted to the
- * {@link EventBusService}.
- */
-public interface PostsAddedToCollectionEventFacet extends CollectionAddToFacet, MultiTypedFacet, Facet {
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/event/PostsCollectionAddToEventFacetAbstract.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/event/PostsCollectionAddToEventFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/event/PostsCollectionAddToEventFacetAbstract.java
deleted file mode 100644
index 44eec96..0000000
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/event/PostsCollectionAddToEventFacetAbstract.java
+++ /dev/null
@@ -1,37 +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.core.metamodel.facets.collections.event;
-
-import org.apache.isis.core.metamodel.facetapi.Facet;
-import org.apache.isis.core.metamodel.facetapi.FacetHolder;
-import org.apache.isis.core.metamodel.facets.collections.CollectionFacetAbstract;
-
-public abstract class PostsCollectionAddToEventFacetAbstract extends CollectionFacetAbstract implements PostsAddedToCollectionEventFacet {
-
-	public PostsCollectionAddToEventFacetAbstract(FacetHolder holder) {
-		super(holder);
-	}
-
-	public static Class<? extends Facet> type() {
-        return PostsAddedToCollectionEventFacet.class;
-    }
-	
-	  
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/event/PostsCollectionAddedToEventFacet.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/event/PostsCollectionAddedToEventFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/event/PostsCollectionAddedToEventFacet.java
new file mode 100644
index 0000000..91d7d3c
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/event/PostsCollectionAddedToEventFacet.java
@@ -0,0 +1,37 @@
+/*
+ *  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.core.metamodel.facets.collections.event;
+
+import org.apache.isis.applib.services.eventbus.CollectionAddedToEvent;
+import org.apache.isis.applib.services.eventbus.EventBusService;
+import org.apache.isis.applib.services.eventbus.PropertyChangedEvent;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.MultiTypedFacet;
+import org.apache.isis.core.metamodel.facets.PostsEventWithWrapperPolicy;
+import org.apache.isis.core.metamodel.facets.SingleValueFacet;
+import org.apache.isis.core.metamodel.facets.collections.modify.CollectionAddToFacet;
+
+/**
+ * Indicates that (the specified subclass of) {@link CollectionAddedToEvent} should be posted to the
+ * {@link EventBusService}.
+ */
+public interface PostsCollectionAddedToEventFacet extends SingleValueFacet<Class<? extends CollectionAddedToEvent<?,?>>>, CollectionAddToFacet, MultiTypedFacet, PostsEventWithWrapperPolicy {
+}
+

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/event/PostsCollectionAddedToEventFacetAbstract.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/event/PostsCollectionAddedToEventFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/event/PostsCollectionAddedToEventFacetAbstract.java
new file mode 100644
index 0000000..4f89185
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/event/PostsCollectionAddedToEventFacetAbstract.java
@@ -0,0 +1,55 @@
+/*
+ *  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.core.metamodel.facets.collections.event;
+
+import org.apache.isis.applib.annotation.WrapperPolicy;
+import org.apache.isis.applib.services.eventbus.CollectionAddedToEvent;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.SingleValueFacetAbstract;
+import org.apache.isis.core.metamodel.facets.collections.modify.CollectionAddToFacet;
+
+
+public abstract class PostsCollectionAddedToEventFacetAbstract 
+    extends SingleValueFacetAbstract<Class<? extends CollectionAddedToEvent<?,?>>> 
+    implements PostsCollectionAddedToEventFacet {
+
+	public static Class<? extends Facet> type() {
+	    
+	    // the "primary" type is CollectionAddToFacet rather than PostsAddedToCollectionEventFacet
+	    // so that this facet can wrap an existing (via setUnderlying).
+	    
+        //return PostsAddedToCollectionEventFacet.class;
+	    return CollectionAddToFacet.class;
+    }
+
+    private final WrapperPolicy wrapperPolicy;
+
+    public PostsCollectionAddedToEventFacetAbstract(Class<? extends CollectionAddedToEvent<?, ?>> changedEventType, WrapperPolicy wrapperPolicy, FacetHolder holder) {
+        super(type(), changedEventType, holder);
+        this.wrapperPolicy = wrapperPolicy;
+    }
+
+    @Override
+    public WrapperPolicy getWrapperPolicy() {
+        return wrapperPolicy;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/event/PostsPropertyChangedEventFacet.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/event/PostsPropertyChangedEventFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/event/PostsPropertyChangedEventFacet.java
index a01e7f4..e5c108f 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/event/PostsPropertyChangedEventFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/event/PostsPropertyChangedEventFacet.java
@@ -22,6 +22,7 @@ package org.apache.isis.core.metamodel.facets.properties.event;
 import org.apache.isis.applib.services.eventbus.EventBusService;
 import org.apache.isis.applib.services.eventbus.PropertyChangedEvent;
 import org.apache.isis.core.metamodel.facetapi.MultiTypedFacet;
+import org.apache.isis.core.metamodel.facets.PostsEventWithWrapperPolicy;
 import org.apache.isis.core.metamodel.facets.SingleValueFacet;
 import org.apache.isis.core.metamodel.facets.properties.modify.PropertyClearFacet;
 import org.apache.isis.core.metamodel.facets.properties.modify.PropertySetterFacet;
@@ -30,6 +31,6 @@ import org.apache.isis.core.metamodel.facets.properties.modify.PropertySetterFac
  * Indicates that (the specified subclass of) {@link PropertyChangedEvent} should be posted to the
  * {@link EventBusService}.
  */
-public interface PostsPropertyChangedEventFacet extends SingleValueFacet<Class<? extends PropertyChangedEvent<?,?>>>, PropertyClearFacet, PropertySetterFacet, MultiTypedFacet {
+public interface PostsPropertyChangedEventFacet extends SingleValueFacet<Class<? extends PropertyChangedEvent<?,?>>>, PropertyClearFacet, PropertySetterFacet, MultiTypedFacet, PostsEventWithWrapperPolicy {
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/event/PostsPropertyChangedEventFacetAbstract.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/event/PostsPropertyChangedEventFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/event/PostsPropertyChangedEventFacetAbstract.java
index 281438a..69ff6a0 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/event/PostsPropertyChangedEventFacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/event/PostsPropertyChangedEventFacetAbstract.java
@@ -19,19 +19,32 @@
 
 package org.apache.isis.core.metamodel.facets.properties.event;
 
+import org.apache.isis.applib.annotation.WrapperPolicy;
 import org.apache.isis.applib.services.eventbus.PropertyChangedEvent;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.SingleValueFacetAbstract;
 
-public abstract class PostsPropertyChangedEventFacetAbstract extends SingleValueFacetAbstract<Class<? extends PropertyChangedEvent<?,?>>> implements PostsPropertyChangedEventFacet {
+public abstract class PostsPropertyChangedEventFacetAbstract 
+        extends SingleValueFacetAbstract<Class<? extends PropertyChangedEvent<?,?>>> 
+        implements PostsPropertyChangedEventFacet {
 
     public static Class<? extends Facet> type() {
+        // different implementation to PostsCollectionAddToEventFacet (for example) because this facet wraps
+        // multiple facets and so we cannot use the setUnderlyingFacet capability.
         return PostsPropertyChangedEventFacet.class;
     }
 
-    public PostsPropertyChangedEventFacetAbstract(final Class<? extends PropertyChangedEvent<?,?>> changedEventType, final FacetHolder holder) {
+    private final WrapperPolicy wrapperPolicy;
+
+    public PostsPropertyChangedEventFacetAbstract(final Class<? extends PropertyChangedEvent<?,?>> changedEventType, final WrapperPolicy wrapperPolicy, final FacetHolder holder) {
         super(type(), changedEventType, holder);
+        this.wrapperPolicy = wrapperPolicy;
+    }
+
+    @Override
+    public WrapperPolicy getWrapperPolicy() {
+        return wrapperPolicy;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/collection/CollectionFacetFactory.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/collection/CollectionFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/collection/CollectionFacetFactory.java
index cbaa8f5..9b4b4a5 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/collection/CollectionFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/collection/CollectionFacetFactory.java
@@ -51,11 +51,11 @@ public class CollectionFacetFactory extends FacetFactoryAbstract implements Coll
 
     }
 
-    private void processCollectionType(final ProcessClassContext processClassContaxt) {
-        final FacetHolder facetHolder = processClassContaxt.getFacetHolder();
+    private void processCollectionType(final ProcessClassContext processClassContext) {
+        final FacetHolder facetHolder = processClassContext.getFacetHolder();
         final TypeOfFacet typeOfFacet = facetHolder.getFacet(TypeOfFacet.class);
         if (typeOfFacet == null) {
-            final Class<?> collectionElementType = collectionElementType(processClassContaxt.getCls());
+            final Class<?> collectionElementType = collectionElementType(processClassContext.getCls());
             facetHolder.addFacet(collectionElementType != Object.class ? new TypeOfFacetInferredFromGenerics(collectionElementType, facetHolder, getSpecificationLoader()) : new TypeOfFacetDefaultToObject(facetHolder, getSpecificationLoader()));
         } else {
             // nothing

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/event/PostsCollectionAddToEventAnnotationFacetFactory.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/event/PostsCollectionAddToEventAnnotationFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/event/PostsCollectionAddToEventAnnotationFacetFactory.java
deleted file mode 100644
index 408a144..0000000
--- a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/event/PostsCollectionAddToEventAnnotationFacetFactory.java
+++ /dev/null
@@ -1,117 +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.core.progmodel.facets.collections.event;
-
-import java.lang.reflect.Method;
-import java.util.Comparator;
-import java.util.List;
-
-import org.apache.isis.applib.annotation.PostsCollectionAddedToEvent;
-import org.apache.isis.applib.services.eventbus.CollectionAddedToEvent;
-import org.apache.isis.core.commons.config.IsisConfiguration;
-import org.apache.isis.core.metamodel.adapter.ServicesProvider;
-import org.apache.isis.core.metamodel.adapter.ServicesProviderAware;
-import org.apache.isis.core.metamodel.facetapi.FacetHolder;
-import org.apache.isis.core.metamodel.facetapi.FacetUtil;
-import org.apache.isis.core.metamodel.facetapi.FeatureType;
-import org.apache.isis.core.metamodel.facetapi.MetaModelValidatorRefiner;
-import org.apache.isis.core.metamodel.facets.Annotations;
-import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
-import org.apache.isis.core.metamodel.facets.collections.modify.CollectionAddToFacet;
-import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
-import org.apache.isis.core.metamodel.facets.collections.sortedby.SortedByFacet;
-import org.apache.isis.core.metamodel.facets.collections.event.PostsAddedToCollectionEventFacet;
-import org.apache.isis.core.metamodel.spec.ObjectSpecification;
-import org.apache.isis.core.metamodel.spec.feature.Contributed;
-import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorComposite;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting;
-import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting.Visitor;
-import org.apache.isis.core.metamodel.specloader.validator.ValidationFailures;
-
-public class PostsCollectionAddToEventAnnotationFacetFactory extends FacetFactoryAbstract implements ServicesProviderAware, MetaModelValidatorRefiner {
-
-    private ServicesProvider servicesProvider;
-
-    public PostsCollectionAddToEventAnnotationFacetFactory() {
-        super(FeatureType.PROPERTIES_ONLY);
-    }
-
-    @Override
-    public void process(final ProcessMethodContext processMethodContext) {
-        final Method method = processMethodContext.getMethod();
-        FacetUtil.addFacet(create(method, processMethodContext.getFacetHolder()));
-    }
-
-    private PostsAddedToCollectionEventFacet create(Method method, final FacetHolder holder) {
-        final PostsCollectionAddedToEvent annotation = Annotations.getAnnotation(method, PostsCollectionAddedToEvent.class);
-        if(annotation == null) {
-            return null;
-        }
-        final PostsAddedToCollectionEventFacet postsAddedToCollectionEventFacet = holder.getFacet(PostsAddedToCollectionEventFacet.class);
-        if(postsAddedToCollectionEventFacet == null) {
-            return null;
-        } 
-        final CollectionAddToFacet collectionAddToFacet = holder.getFacet(CollectionAddToFacet.class);
-        final CollectionFacet collectionFacet = holder.getFacet(CollectionFacet.class);
-        if(postsAddedToCollectionEventFacet != null) {
-            holder.removeFacet(postsAddedToCollectionEventFacet);
-        }
-        if(collectionAddToFacet != null) {
-            holder.removeFacet(collectionAddToFacet);
-        }
-        if(collectionFacet != null) {
-            holder.removeFacet(collectionFacet);
-        }
-        final Class<? extends CollectionAddedToEvent<?,?>> changedEventType = annotation.value();
-        return new PostsCollectionAddToEventFacetAnnotation(changedEventType, postsAddedToCollectionEventFacet, collectionAddToFacet, collectionFacet, servicesProvider, holder);
-    }
-
-    @Override
-    public void setServicesProvider(ServicesProvider servicesProvider) {
-        this.servicesProvider = servicesProvider;
-    }
-
-    @Override
-    public void refineMetaModelValidator(MetaModelValidatorComposite metaModelValidator, IsisConfiguration configuration) {
-        metaModelValidator.add(new MetaModelValidatorVisiting(newValidatorVisitor()));
-    }
-
-    protected Visitor newValidatorVisitor() {
-        return new MetaModelValidatorVisiting.Visitor() {
-
-            @Override
-            public boolean visit(ObjectSpecification objectSpec, ValidationFailures validationFailures) {
-                List<OneToManyAssociation> objectCollections = objectSpec.getCollections(Contributed.EXCLUDED);
-                for (OneToManyAssociation objectCollection : objectCollections) {
-                    final SortedByFacet facet = objectCollection.getFacet(SortedByFacet.class);
-                    if(facet != null) {
-                        final Class<? extends Comparator<?>> cls = facet.value();
-                        if(!Comparator.class.isAssignableFrom(cls)) {
-                            validationFailures.add("%s#%s is annotated with @SortedBy, but the class specified '%s' is not a Comparator", objectSpec.getIdentifier().getClassName(), objectCollection.getId(), facet.value().getName());
-                        }
-                    }
-                }
-                return true;
-            }
-        };
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/event/PostsCollectionAddToEventFacetAnnotation.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/event/PostsCollectionAddToEventFacetAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/event/PostsCollectionAddToEventFacetAnnotation.java
deleted file mode 100644
index 8318cdb..0000000
--- a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/event/PostsCollectionAddToEventFacetAnnotation.java
+++ /dev/null
@@ -1,154 +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.core.progmodel.facets.collections.event;
-
-import java.lang.reflect.Field;
-import java.util.Collection;
-import java.util.List;
-
-import com.google.common.collect.Lists;
-
-import org.apache.isis.applib.FatalException;
-import org.apache.isis.applib.services.eventbus.CollectionAddedToEvent;
-import org.apache.isis.applib.services.eventbus.EventBusService;
-import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
-import org.apache.isis.core.metamodel.adapter.ServicesProvider;
-import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
-import org.apache.isis.core.metamodel.facetapi.Facet;
-import org.apache.isis.core.metamodel.facetapi.FacetHolder;
-import org.apache.isis.core.metamodel.facets.collections.event.PostsAddedToCollectionEventFacet;
-import org.apache.isis.core.metamodel.facets.collections.event.PostsCollectionAddToEventFacetAbstract;
-import org.apache.isis.core.metamodel.facets.collections.modify.CollectionAddToFacet;
-import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
-
-public class PostsCollectionAddToEventFacetAnnotation extends
-		PostsCollectionAddToEventFacetAbstract {
-
-	private final CollectionAddToFacet collectionAddToFacet;
-	private final CollectionFacet collectionFacet;
-	private final ServicesProvider servicesProvider;
-
-	private EventBusService eventBusService;
-	private boolean searchedForEventBusService = false;
-	private Class<? extends CollectionAddedToEvent<?, ?>> addedToCollectionEventType;
-
-	public PostsCollectionAddToEventFacetAnnotation(
-			Class<? extends CollectionAddedToEvent<?, ?>> addedToCollectionEventType,
-			CollectionAddToFacet collectionAddToFacet,
-			CollectionFacet collectionFacet,
-			ServicesProvider servicesProvider, FacetHolder holder) {
-		super(holder);
-		this.addedToCollectionEventType = addedToCollectionEventType;
-		this.collectionAddToFacet = collectionAddToFacet;
-		this.collectionFacet = collectionFacet;
-		this.servicesProvider = servicesProvider;
-	}
-
-	@Override
-	public void add(ObjectAdapter inObject, ObjectAdapter value) {
-		if (this.collectionAddToFacet == null) {
-			return;
-		}
-		eventBusService = getEventBusService();
-		if (eventBusService == null) {
-			collectionAddToFacet.add(inObject, value);
-			return;
-		}
-
-		final Boolean previouslyExisting = this.collectionFacet.contains(
-				inObject, value);
-		if (!previouslyExisting) {
-			collectionAddToFacet.add(inObject, value);
-			postEvent(inObject, value);
-		}
-	}
-
-	@SuppressWarnings({ "rawtypes", "unchecked" })
-	private void postEvent(ObjectAdapter inObject,
-			final Object addedValue) {
-		final Object source = inObject.getObject();
-		try {
-			final Class type =  addedToCollectionEventType;
-			final CollectionAddedToEvent<?, ?> event = newEvent(type, addedValue, source);
-
-			eventBusService.post(event);
-		} catch (Exception e) {
-			throw new FatalException(e);
-		}
-	}
-
-
-	static <S, T> CollectionAddedToEvent<S, T> newEvent(
-			final Class<? extends CollectionAddedToEvent<S, T>> type,
-			final T addedValue, final S source)
-			throws InstantiationException, IllegalAccessException,
-			NoSuchFieldException {
-		final CollectionAddedToEvent<S, T> event = type.newInstance();
-
-		setField("source", event, source);
-		setField("addedValue", event, addedValue);
-		return event;
-	}
-
-	private static void setField(final String name,
-			final CollectionAddedToEvent<?, ?> event, final Object sourceValue)
-			throws NoSuchFieldException, IllegalAccessException {
-		final Field sourceField = CollectionAddedToEvent.class
-				.getDeclaredField(name);
-		sourceField.setAccessible(true);
-		sourceField.set(event, sourceValue);
-	}
-
-	private EventBusService getEventBusService() {
-		if (!searchedForEventBusService) {
-			final List<ObjectAdapter> serviceAdapters = servicesProvider
-					.getServices();
-			for (ObjectAdapter serviceAdapter : serviceAdapters) {
-				final Object service = serviceAdapter.getObject();
-				if (service instanceof EventBusService) {
-					eventBusService = (EventBusService) service;
-					break;
-				}
-			}
-		}
-		searchedForEventBusService = true;
-		return eventBusService;
-	}
-
-	// //////////////////////////////////////
-	// MultiTypedFacet
-
-	@SuppressWarnings("unchecked")
-	@Override
-	public Class<? extends Facet>[] facetTypes() {
-		return Lists.newArrayList(PostsAddedToCollectionEventFacet.class,
-				CollectionAddToFacet.class).toArray(
-				new Class[] {});
-	}
-
-	@SuppressWarnings("unchecked")
-	@Override
-	public <T extends Facet> T getFacet(Class<T> facet) {
-		return (T) this;
-	}
-
-
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/event/PostsCollectionAddedToEventAnnotationFacetFactory.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/event/PostsCollectionAddedToEventAnnotationFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/event/PostsCollectionAddedToEventAnnotationFacetFactory.java
new file mode 100644
index 0000000..504dd64
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/event/PostsCollectionAddedToEventAnnotationFacetFactory.java
@@ -0,0 +1,78 @@
+/*
+ *  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.core.progmodel.facets.collections.event;
+
+import java.lang.reflect.Method;
+
+import org.apache.isis.applib.annotation.PostsCollectionAddedToEvent;
+import org.apache.isis.applib.annotation.WrapperPolicy;
+import org.apache.isis.applib.services.eventbus.CollectionAddedToEvent;
+import org.apache.isis.core.metamodel.adapter.ServicesProvider;
+import org.apache.isis.core.metamodel.adapter.ServicesProviderAware;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facetapi.FacetUtil;
+import org.apache.isis.core.metamodel.facetapi.FeatureType;
+import org.apache.isis.core.metamodel.facets.Annotations;
+import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
+import org.apache.isis.core.metamodel.facets.accessor.PropertyOrCollectionAccessorFacet;
+import org.apache.isis.core.metamodel.facets.collections.event.PostsCollectionAddedToEventFacet;
+import org.apache.isis.core.metamodel.facets.collections.modify.CollectionAddToFacet;
+
+public class PostsCollectionAddedToEventAnnotationFacetFactory extends FacetFactoryAbstract implements ServicesProviderAware {
+
+    private ServicesProvider servicesProvider;
+
+    public PostsCollectionAddedToEventAnnotationFacetFactory() {
+        super(FeatureType.COLLECTIONS_ONLY);
+    }
+
+    @Override
+    public void process(final ProcessMethodContext processMethodContext) {
+        final Method method = processMethodContext.getMethod();
+        FacetUtil.addFacet(create(method, processMethodContext.getFacetHolder()));
+    }
+
+    private PostsCollectionAddedToEventFacet create(Method method, final FacetHolder holder) {
+        final PostsCollectionAddedToEvent annotation = Annotations.getAnnotation(method, PostsCollectionAddedToEvent.class);
+        if(annotation == null) {
+            return null;
+        }
+        
+        final PropertyOrCollectionAccessorFacet getterFacet = holder.getFacet(PropertyOrCollectionAccessorFacet.class);
+        if(getterFacet == null) {
+            return null;
+        } 
+        final CollectionAddToFacet collectionAddToFacet = holder.getFacet(CollectionAddToFacet.class);
+        if(collectionAddToFacet == null) {
+            return null;
+        }
+        // the collectionAddToFacet will end up as the underlying facet of the PostsCollectionAddedToEventFacetAnnotation
+
+        final Class<? extends CollectionAddedToEvent<?,?>> changedEventType = annotation.value();
+        final WrapperPolicy wrapperPolicy = annotation.wrapperPolicy();
+        return new PostsCollectionAddedToEventFacetAnnotation(changedEventType, wrapperPolicy, getterFacet, collectionAddToFacet, servicesProvider, holder);
+    }
+
+    @Override
+    public void setServicesProvider(ServicesProvider servicesProvider) {
+        this.servicesProvider = servicesProvider;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/event/PostsCollectionAddedToEventFacetAnnotation.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/event/PostsCollectionAddedToEventFacetAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/event/PostsCollectionAddedToEventFacetAnnotation.java
new file mode 100644
index 0000000..f1e30ec
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/collections/event/PostsCollectionAddedToEventFacetAnnotation.java
@@ -0,0 +1,173 @@
+/*
+ *  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.core.progmodel.facets.collections.event;
+
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.Set;
+
+import com.google.common.collect.Lists;
+
+import org.apache.isis.applib.FatalException;
+import org.apache.isis.applib.Identifier;
+import org.apache.isis.applib.annotation.WrapperPolicy;
+import org.apache.isis.applib.services.eventbus.CollectionAddedToEvent;
+import org.apache.isis.applib.services.eventbus.EventBusService;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.ServicesProvider;
+import org.apache.isis.core.metamodel.adapter.util.AdapterUtils;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facetapi.FacetUtil;
+import org.apache.isis.core.metamodel.facets.accessor.PropertyOrCollectionAccessorFacet;
+import org.apache.isis.core.metamodel.facets.collections.event.PostsCollectionAddedToEventFacet;
+import org.apache.isis.core.metamodel.facets.collections.event.PostsCollectionAddedToEventFacetAbstract;
+import org.apache.isis.core.metamodel.facets.collections.modify.CollectionAddToFacet;
+
+public class PostsCollectionAddedToEventFacetAnnotation 
+        extends PostsCollectionAddedToEventFacetAbstract {
+
+    private final PropertyOrCollectionAccessorFacet getterFacet;
+	private final CollectionAddToFacet collectionAddToFacet;
+	private final ServicesProvider servicesProvider;
+
+	private EventBusService eventBusService;
+	private boolean searchedForEventBusService = false;
+
+	public PostsCollectionAddedToEventFacetAnnotation(
+			final Class<? extends CollectionAddedToEvent<?, ?>> eventType,
+            final WrapperPolicy wrapperPolicy,
+			final PropertyOrCollectionAccessorFacet getterFacet,
+			final CollectionAddToFacet collectionAddToFacet,
+			final ServicesProvider servicesProvider, 
+			final FacetHolder holder) {
+		super(eventType, wrapperPolicy, holder);
+        this.getterFacet = getterFacet;
+		this.collectionAddToFacet = collectionAddToFacet;
+		this.servicesProvider = servicesProvider;
+	}
+
+	@Override
+	public void add(ObjectAdapter targetAdapter, ObjectAdapter referencedObjectAdapter) {
+		if (this.collectionAddToFacet == null) {
+			return;
+		}
+		eventBusService = getEventBusService();
+		if (eventBusService == null) {
+			collectionAddToFacet.add(targetAdapter, referencedObjectAdapter);
+			return;
+		}
+
+		final Object referencedObject = AdapterUtils.unwrap(referencedObjectAdapter);
+		
+		// get hold of underlying collection
+		final Object collection = getterFacet.getProperty(targetAdapter);
+
+		// don't post event if has set semantics and contains object
+		if(collection instanceof Set) {
+            Set<?> set = (Set<?>) collection;
+            if(set.contains(referencedObject)) {
+                return;
+            }
+		}
+
+		// either doesn't contain object, or doesn't have set semantics, so post event
+		collectionAddToFacet.add(targetAdapter, referencedObjectAdapter);
+		
+		postEvent(targetAdapter, getIdentified().getIdentifier(), referencedObject);
+	}
+
+	@SuppressWarnings({ "rawtypes", "unchecked" })
+	private void postEvent(
+	        final ObjectAdapter targetAdapter,
+            final Identifier identifier,
+			final Object addedReference) {
+	    
+		final Object source = targetAdapter.getObject();
+		try {
+			final Class type = value();
+			final CollectionAddedToEvent<?, ?> event = newEvent(type, source, identifier, addedReference);
+			eventBusService.post(event);
+		} catch (Exception e) {
+			throw new FatalException(e);
+		}
+	}
+
+	static <S, T> CollectionAddedToEvent<S, T> newEvent(
+			final Class<? extends CollectionAddedToEvent<S, T>> type,
+			final S source, 
+			final Identifier identifier,
+			final T value)
+			throws InstantiationException, IllegalAccessException,
+			NoSuchFieldException {
+		final CollectionAddedToEvent<S, T> event = type.newInstance();
+
+		setField("source", event, source);
+		setField("identifier", event, identifier);
+		setField("value", event, value);
+		return event;
+	}
+
+	private static void setField(final String name,
+			final CollectionAddedToEvent<?, ?> event, final Object sourceValue)
+			throws NoSuchFieldException, IllegalAccessException {
+		final Field sourceField = CollectionAddedToEvent.class
+				.getDeclaredField(name);
+		sourceField.setAccessible(true);
+		sourceField.set(event, sourceValue);
+	}
+
+	private EventBusService getEventBusService() {
+		if (!searchedForEventBusService) {
+			final List<ObjectAdapter> serviceAdapters = servicesProvider
+					.getServices();
+			for (ObjectAdapter serviceAdapter : serviceAdapters) {
+				final Object service = serviceAdapter.getObject();
+				if (service instanceof EventBusService) {
+					eventBusService = (EventBusService) service;
+					break;
+				}
+			}
+		}
+		searchedForEventBusService = true;
+		return eventBusService;
+	}
+
+	// //////////////////////////////////////
+	// MultiTypedFacet
+	// //////////////////////////////////////
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public Class<? extends Facet>[] facetTypes() {
+		return Lists.newArrayList(
+		            type(), // ie CollectionAddedToFacet
+    		        PostsCollectionAddedToEventFacet.class
+				).toArray(
+				new Class[] {});
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public <T extends Facet> T getFacet(Class<T> facet) {
+		return (T) this;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/properties/event/PostsPropertyChangedEventAnnotationFacetFactory.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/properties/event/PostsPropertyChangedEventAnnotationFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/properties/event/PostsPropertyChangedEventAnnotationFacetFactory.java
index 3e87ff7..1a75d60 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/properties/event/PostsPropertyChangedEventAnnotationFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/properties/event/PostsPropertyChangedEventAnnotationFacetFactory.java
@@ -24,6 +24,7 @@ import java.util.Comparator;
 import java.util.List;
 
 import org.apache.isis.applib.annotation.PostsPropertyChangedEvent;
+import org.apache.isis.applib.annotation.WrapperPolicy;
 import org.apache.isis.applib.services.eventbus.PropertyChangedEvent;
 import org.apache.isis.core.commons.config.IsisConfiguration;
 import org.apache.isis.core.metamodel.adapter.ServicesProvider;
@@ -75,14 +76,22 @@ public class PostsPropertyChangedEventAnnotationFacetFactory extends FacetFactor
         if (clearFacet == null && setterFacet == null) {
             return null;
         }
+        
+        
+        // REVIEW: I'm a bit uncertain about this; this facet is multi-valued, but the setUnderlying(...) stuff only
+        // works for single valued types.
+        // the wrapperFactory stuff looks for underlying to find the imperative method, I think this only works in this
+        // case because (by accident rather than design) there is also the PropertyInitializationFacet wrapping the setter.
         if(setterFacet != null) {
             holder.removeFacet(setterFacet);
         }
         if(clearFacet != null) {
             holder.removeFacet(clearFacet);
         }
+        
         final Class<? extends PropertyChangedEvent<?, ?>> changedEventType = annotation.value();
-        return new PostsPropertyChangedEventFacetAnnotation(changedEventType, getterFacet, setterFacet, clearFacet, servicesProvider, holder);
+        final WrapperPolicy wrapperPolicy = annotation.wrapperPolicy();
+        return new PostsPropertyChangedEventFacetAnnotation(changedEventType, wrapperPolicy, getterFacet, setterFacet, clearFacet, servicesProvider, holder);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/properties/event/PostsPropertyChangedEventFacetAnnotation.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/properties/event/PostsPropertyChangedEventFacetAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/properties/event/PostsPropertyChangedEventFacetAnnotation.java
index 406ac36..afc96bb 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/properties/event/PostsPropertyChangedEventFacetAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/properties/event/PostsPropertyChangedEventFacetAnnotation.java
@@ -26,7 +26,8 @@ import com.google.common.base.Objects;
 import com.google.common.collect.Lists;
 
 import org.apache.isis.applib.FatalException;
-import org.apache.isis.applib.RecoverableException;
+import org.apache.isis.applib.Identifier;
+import org.apache.isis.applib.annotation.WrapperPolicy;
 import org.apache.isis.applib.services.eventbus.EventBusService;
 import org.apache.isis.applib.services.eventbus.PropertyChangedEvent;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
@@ -50,13 +51,14 @@ public class PostsPropertyChangedEventFacetAnnotation extends PostsPropertyChang
     private boolean searchedForEventBusService = false;
 
     public PostsPropertyChangedEventFacetAnnotation(
-            final Class<? extends PropertyChangedEvent<?, ?>> changedEventType, 
+            final Class<? extends PropertyChangedEvent<?, ?>> eventType, 
+            final WrapperPolicy wrapperPolicy,
             final PropertyOrCollectionAccessorFacet getterFacet, 
             final PropertySetterFacet setterFacet, 
             final PropertyClearFacet clearFacet, 
             final ServicesProvider servicesProvider, 
             final FacetHolder holder) {
-        super(changedEventType, holder);
+        super(eventType, wrapperPolicy, holder);
         this.getterFacet = getterFacet;
         this.setterFacet = setterFacet;
         this.clearFacet = clearFacet;
@@ -64,50 +66,56 @@ public class PostsPropertyChangedEventFacetAnnotation extends PostsPropertyChang
     }
 
     @Override
-    public void setProperty(ObjectAdapter inObject, ObjectAdapter value) {
-        if(this.setterFacet == null) {
+    public void setProperty(ObjectAdapter targetAdapter, ObjectAdapter valueAdapter) {
+        if(setterFacet == null) {
             return;
         }
         eventBusService = getEventBusService();
         if(eventBusService == null) {
-            setterFacet.setProperty(inObject, value);
+            setterFacet.setProperty(targetAdapter, valueAdapter);
             return;
         }
         
-        final Object oldValue = this.getterFacet.getProperty(inObject);
-        this.setterFacet.setProperty(inObject, value);
-        final Object newValue = this.getterFacet.getProperty(inObject);
-        postEventIfChanged(inObject, oldValue, newValue);
+        final Object oldValue = getterFacet.getProperty(targetAdapter);
+        setterFacet.setProperty(targetAdapter, valueAdapter);
+        final Object newValue = getterFacet.getProperty(targetAdapter);
+        postEventIfChanged(targetAdapter, getIdentified().getIdentifier(), oldValue, newValue);
     }
 
     @Override
-    public void clearProperty(ObjectAdapter inObject) {
-        if(this.clearFacet == null) {
+    public void clearProperty(ObjectAdapter targetAdapter) {
+        if(clearFacet == null) {
             return;
         }
         eventBusService = getEventBusService();
         if(eventBusService == null) {
-            clearFacet.clearProperty(inObject);
+            clearFacet.clearProperty(targetAdapter);
             return;
         }
 
-        final Object oldValue = this.getterFacet.getProperty(inObject);
-        this.clearFacet.clearProperty(inObject);
-        final Object newValue = this.getterFacet.getProperty(inObject);
-        postEventIfChanged(inObject, oldValue, newValue);
+        final Object oldValue = getterFacet.getProperty(targetAdapter);
+        clearFacet.clearProperty(targetAdapter);
+        final Object newValue = getterFacet.getProperty(targetAdapter);
+        
+        postEventIfChanged(targetAdapter, getIdentified().getIdentifier(), oldValue, newValue);
     }
 
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
-    private void postEventIfChanged(ObjectAdapter inObject, final Object oldValue, final Object newValue) {
+    private void postEventIfChanged(
+            final ObjectAdapter targetAdapter, 
+            final Identifier identifier, 
+            final Object oldValue, 
+            final Object newValue) {
+        
         if(Objects.equal(oldValue, newValue)) {
             // do nothing.
             return;
         }
-        final Object source = inObject.getObject();
+        final Object source = targetAdapter.getObject();
         try {
             final Class type = value();
-            final PropertyChangedEvent<?, ?> event = newEvent(type, oldValue, newValue, source);
+            final PropertyChangedEvent<?, ?> event = newEvent(type, source, identifier, oldValue, newValue);
             
             eventBusService.post(event);
         } catch (Exception e) {
@@ -115,10 +123,16 @@ public class PostsPropertyChangedEventFacetAnnotation extends PostsPropertyChang
         }
     }
 
-    static <S,T> PropertyChangedEvent<S,T> newEvent(final Class<? extends PropertyChangedEvent<S, T>> type, final T oldValue, final T newValue, final S source) throws InstantiationException, IllegalAccessException, NoSuchFieldException {
+    static <S,T> PropertyChangedEvent<S,T> newEvent(
+            final Class<? extends PropertyChangedEvent<S, T>> type, 
+            final S source, 
+            final Identifier identifier,
+            final T oldValue, 
+            final T newValue) throws InstantiationException, IllegalAccessException, NoSuchFieldException {
         final PropertyChangedEvent<S, T> event = type.newInstance();
         
         setField("source", event, source);
+        setField("identifier", event, identifier);
         setField("oldValue", event, oldValue);
         setField("newValue", event, newValue);
         return event;
@@ -147,12 +161,16 @@ public class PostsPropertyChangedEventFacetAnnotation extends PostsPropertyChang
     
     // //////////////////////////////////////
     // MultiTypedFacet
-
+    // //////////////////////////////////////
 
     @SuppressWarnings("unchecked")
     @Override
     public Class<? extends Facet>[] facetTypes() {
-        return Lists.newArrayList(PostsPropertyChangedEventFacet.class, PropertySetterFacet.class, PropertyClearFacet.class).toArray(new Class[]{});
+        return Lists.newArrayList(
+                    PostsPropertyChangedEventFacet.class, 
+                    PropertySetterFacet.class, 
+                    PropertyClearFacet.class
+                ).toArray(new Class[]{});
     }
 
     @SuppressWarnings("unchecked")

http://git-wip-us.apache.org/repos/asf/isis/blob/2637a055/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java b/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
index 69c6e70..1e4598c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
+++ b/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/ProgrammingModelFacetsJava5.java
@@ -47,6 +47,7 @@ import org.apache.isis.core.progmodel.facets.collections.aggregated.ParentedSinc
 import org.apache.isis.core.progmodel.facets.collections.clear.CollectionClearFacetFactory;
 import org.apache.isis.core.progmodel.facets.collections.collection.CollectionFacetFactory;
 import org.apache.isis.core.progmodel.facets.collections.disabled.fromimmutable.DisabledFacetForCollectionDerivedFromImmutableTypeFacetFactory;
+import org.apache.isis.core.progmodel.facets.collections.event.PostsCollectionAddedToEventAnnotationFacetFactory;
 import org.apache.isis.core.progmodel.facets.collections.modify.CollectionAddRemoveAndValidateFacetFactory;
 import org.apache.isis.core.progmodel.facets.collections.notpersisted.annotation.NotPersistedAnnotationForCollectionFacetFactory;
 import org.apache.isis.core.progmodel.facets.collections.sortedby.SortedByAnnotationFacetFactory;
@@ -362,8 +363,11 @@ public final class ProgrammingModelFacetsJava5 extends ProgrammingModelAbstract
         addFactory(DisabledFacetForPropertyDerivedFromImmutableTypeFacetFactory.class);
         addFactory(DisabledFacetForCollectionDerivedFromImmutableTypeFacetFactory.class);
 
+        // must come after the property/collection/action accessor+mutator facet factories
         addFactory(PostsPropertyChangedEventAnnotationFacetFactory.class);
+        addFactory(PostsCollectionAddedToEventAnnotationFacetFactory.class);
 
+        
         addFactory(ImmutableMarkerInterfaceFacetFactory.class);
 
         addFactory(ViewModelIntefaceFacetFactory.class);