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 2016/05/13 18:13:52 UTC

[10/50] [abbrv] isis git commit: ISIS-1398: removing duplication in the PropertySetterFacet and PropertyClearFacet hierarchies.

ISIS-1398: removing duplication in the PropertySetterFacet and PropertyClearFacet hierarchies.

Specifically:
- removed PropertyClearFacetForDomainEventAbstract
- generalized the equivalent setter abstract to delegate to either an underlying setterFacet or clearFacet


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

Branch: refs/heads/master
Commit: bb54a109f1269c7e67ebc254117a47d163a5b2f5
Parents: 6341730
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Mon May 2 11:29:44 2016 +0100
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Mon May 2 11:29:44 2016 +0100

----------------------------------------------------------------------
 ...onInvocationFacetForDomainEventAbstract.java |   6 +-
 .../PropertyAnnotationFacetFactory.java         |   8 +-
 ...ropertyClearFacetForDomainEventAbstract.java | 235 --------------
 ...ertyClearFacetForDomainEventFromDefault.java |   8 +-
 ...cetForDomainEventFromPropertyAnnotation.java |   8 +-
 ...nEventFromPropertyInteractionAnnotation.java |   8 +-
 ...tForPostsPropertyChangedEventAnnotation.java |   8 +-
 ...opertySetterFacetForDomainEventAbstract.java | 236 --------------
 ...rtySetterFacetForDomainEventFromDefault.java |   9 +-
 ...cetForDomainEventFromPropertyAnnotation.java |   8 +-
 ...nEventFromPropertyInteractionAnnotation.java |   8 +-
 ...tForPostsPropertyChangedEventAnnotation.java |   8 +-
 ...etterOrClearFacetForDomainEventAbstract.java | 310 +++++++++++++++++++
 13 files changed, 358 insertions(+), 502 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/bb54a109/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java
index ef7c3fc..f40cd95 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java
@@ -196,7 +196,7 @@ public abstract class ActionInvocationFacetForDomainEventAbstract
             final ObjectAdapter[] arguments,
             final InteractionInitiatedBy interactionInitiatedBy) {
 
-        // similar code in Property{Setter/Clear}FacetFDEA
+        // similar code in PropertySetterOrClearFacetFDEA
 
         final CommandContext commandContext = getCommandContext();
         final Command command = commandContext.getCommand();
@@ -237,7 +237,7 @@ public abstract class ActionInvocationFacetForDomainEventAbstract
             final ObjectAdapter targetAdapter,
             final ObjectAdapter[] argumentAdapters) {
 
-        // similar code in Property{Setter/Clear}FacetFDEA
+        // similar code in PropertySetterOrClearFacetFDEA
 
         try {
             owningAction.setupActionInvocationContext(targetAdapter);
@@ -296,7 +296,7 @@ public abstract class ActionInvocationFacetForDomainEventAbstract
             final ObjectAdapter[] argumentAdapters)
             throws IllegalAccessException, InvocationTargetException {
 
-        // similar code in Property{Setter/Clear}FacetFDEA
+        // similar code in PropertySetterOrClearFacetFDEA
 
         final CommandContext commandContext = getCommandContext();
         final Command command = commandContext.getCommand();

http://git-wip-us.apache.org/repos/asf/isis/blob/bb54a109/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactory.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactory.java
index a1d7c16..3053f08 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactory.java
@@ -20,6 +20,7 @@
 package org.apache.isis.core.metamodel.facets.properties.property;
 
 import java.lang.reflect.Method;
+
 import org.apache.isis.applib.annotation.Disabled;
 import org.apache.isis.applib.annotation.Hidden;
 import org.apache.isis.applib.annotation.Mandatory;
@@ -60,7 +61,6 @@ import org.apache.isis.core.metamodel.facets.properties.property.mandatory.Manda
 import org.apache.isis.core.metamodel.facets.properties.property.mandatory.MandatoryFacetInvertedByOptionalAnnotationOnProperty;
 import org.apache.isis.core.metamodel.facets.properties.property.maxlength.MaxLengthFacetForMaxLengthAnnotationOnProperty;
 import org.apache.isis.core.metamodel.facets.properties.property.maxlength.MaxLengthFacetForPropertyAnnotation;
-import org.apache.isis.core.metamodel.facets.properties.property.modify.PropertyClearFacetForDomainEventAbstract;
 import org.apache.isis.core.metamodel.facets.properties.property.modify.PropertyClearFacetForDomainEventFromDefault;
 import org.apache.isis.core.metamodel.facets.properties.property.modify.PropertyClearFacetForDomainEventFromPropertyAnnotation;
 import org.apache.isis.core.metamodel.facets.properties.property.modify.PropertyClearFacetForDomainEventFromPropertyInteractionAnnotation;
@@ -69,7 +69,6 @@ import org.apache.isis.core.metamodel.facets.properties.property.modify.Property
 import org.apache.isis.core.metamodel.facets.properties.property.modify.PropertyDomainEventFacetDefault;
 import org.apache.isis.core.metamodel.facets.properties.property.modify.PropertyDomainEventFacetForPropertyAnnotation;
 import org.apache.isis.core.metamodel.facets.properties.property.modify.PropertyDomainEventFacetForPropertyInteractionAnnotation;
-import org.apache.isis.core.metamodel.facets.properties.property.modify.PropertySetterFacetForDomainEventAbstract;
 import org.apache.isis.core.metamodel.facets.properties.property.modify.PropertySetterFacetForDomainEventFromDefault;
 import org.apache.isis.core.metamodel.facets.properties.property.modify.PropertySetterFacetForDomainEventFromPropertyAnnotation;
 import org.apache.isis.core.metamodel.facets.properties.property.modify.PropertySetterFacetForDomainEventFromPropertyInteractionAnnotation;
@@ -188,7 +187,7 @@ public class PropertyAnnotationFacetFactory extends FacetFactoryAbstract impleme
         final PropertySetterFacet setterFacet = holder.getFacet(PropertySetterFacet.class);
         if(setterFacet != null) {
             // the current setter facet will end up as the underlying facet
-            final PropertySetterFacetForDomainEventAbstract replacementFacet;
+            final PropertySetterFacet replacementFacet;
             // deprecated
             if(postsPropertyChangedEvent != null) {
                 final Class<? extends PropertyChangedEvent<?, ?>> propertySetEventType = postsPropertyChangedEvent.value();
@@ -216,7 +215,7 @@ public class PropertyAnnotationFacetFactory extends FacetFactoryAbstract impleme
         final PropertyClearFacet clearFacet = holder.getFacet(PropertyClearFacet.class);
         if(clearFacet != null) {
             // the current clear facet will end up as the underlying facet
-            final PropertyClearFacetForDomainEventAbstract replacementFacet;
+            final PropertyClearFacet replacementFacet;
 
             // deprecated
             if(postsPropertyChangedEvent != null) {
@@ -234,6 +233,7 @@ public class PropertyAnnotationFacetFactory extends FacetFactoryAbstract impleme
                 replacementFacet = new PropertyClearFacetForDomainEventFromPropertyAnnotation(
                         propertyDomainEventType, getterFacet, clearFacet, propertyDomainEventFacet, holder, servicesInjector);
             } else
+            // default
             {
                 replacementFacet = new PropertyClearFacetForDomainEventFromDefault(
                         propertyDomainEventType, getterFacet, clearFacet, propertyDomainEventFacet, holder, servicesInjector);

http://git-wip-us.apache.org/repos/asf/isis/blob/bb54a109/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForDomainEventAbstract.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForDomainEventAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForDomainEventAbstract.java
deleted file mode 100644
index 882b598..0000000
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForDomainEventAbstract.java
+++ /dev/null
@@ -1,235 +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.properties.property.modify;
-
-import com.google.common.base.Objects;
-
-import org.apache.isis.applib.services.clock.ClockService;
-import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.applib.services.command.CommandContext;
-import org.apache.isis.applib.services.command.spi.CommandService;
-import org.apache.isis.applib.services.eventbus.AbstractDomainEvent;
-import org.apache.isis.applib.services.eventbus.PropertyDomainEvent;
-import org.apache.isis.applib.services.iactn.Interaction;
-import org.apache.isis.applib.services.iactn.InteractionContext;
-import org.apache.isis.core.commons.exceptions.IsisException;
-import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
-import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
-import org.apache.isis.core.metamodel.facetapi.Facet;
-import org.apache.isis.core.metamodel.facetapi.FacetHolder;
-import org.apache.isis.core.metamodel.facets.DomainEventHelper;
-import org.apache.isis.core.metamodel.facets.SingleValueFacetAbstract;
-import org.apache.isis.core.metamodel.facets.propcoll.accessor.PropertyOrCollectionAccessorFacet;
-import org.apache.isis.core.metamodel.facets.properties.update.clear.PropertyClearFacet;
-import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
-import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
-
-public abstract class PropertyClearFacetForDomainEventAbstract
-        extends SingleValueFacetAbstract<Class<? extends PropertyDomainEvent<?,?>>>
-        implements PropertyClearFacet {
-
-
-    public static Class<? extends Facet> type() {
-        return PropertyClearFacet.class;
-    }
-
-    private final DomainEventHelper domainEventHelper;
-
-    private final PropertyOrCollectionAccessorFacet getterFacet;
-    private final PropertyClearFacet clearFacet;
-    private final PropertyDomainEventFacetAbstract propertyDomainEventFacet;
-
-    private final ServicesInjector servicesInjector;
-
-    public PropertyClearFacetForDomainEventAbstract(
-            final Class<? extends PropertyDomainEvent<?, ?>> eventType,
-            final PropertyOrCollectionAccessorFacet getterFacet,
-            final PropertyClearFacet clearFacet,
-            final PropertyDomainEventFacetAbstract propertyDomainEventFacet,
-            final ServicesInjector servicesInjector,
-            final FacetHolder holder) {
-        super(type(), eventType, holder);
-        this.getterFacet = getterFacet;
-        this.clearFacet = clearFacet;
-        this.propertyDomainEventFacet = propertyDomainEventFacet;
-        this.servicesInjector = servicesInjector;
-        this.domainEventHelper = new DomainEventHelper(servicesInjector);
-    }
-
-    @Override
-    public void clearProperty(
-            final OneToOneAssociation owningProperty, final ObjectAdapter targetAdapter,
-            final InteractionInitiatedBy interactionInitiatedBy) {
-
-        // similar code in PropertySetterFacetFDEA and ActionInvocationFacetFDEA
-
-        if(clearFacet == null) {
-            return;
-        }
-
-        // ... post the executing event
-        final Object oldValue = getterFacet.getProperty(targetAdapter, interactionInitiatedBy);
-        final PropertyDomainEvent<?, ?> event =
-                domainEventHelper.postEventForProperty(
-                        AbstractDomainEvent.Phase.EXECUTING,
-                        eventType(), null,
-                        getIdentified(), targetAdapter,
-                        oldValue, null);
-
-        clearPropertyInternal(owningProperty, targetAdapter, interactionInitiatedBy);
-
-        // reading the actual value from the target object, playing it safe...
-        final Object actualNewValue = getterFacet.getProperty(targetAdapter, interactionInitiatedBy);
-        if (!Objects.equal(oldValue, actualNewValue)) {
-
-            // ... and post the event (reusing event from before)
-            domainEventHelper.postEventForProperty(
-                    AbstractDomainEvent.Phase.EXECUTED,
-                    eventType(), verify(event),
-                    getIdentified(), targetAdapter,
-                    oldValue, actualNewValue);
-
-        }
-
-    }
-
-    private void clearPropertyInternal(
-            final OneToOneAssociation owningProperty,
-            final ObjectAdapter targetAdapter,
-            final InteractionInitiatedBy interactionInitiatedBy) {
-
-        // similar code in PropertySetterFacetFDEA and ActionInvocationFacetFDEA
-
-        final ObjectAdapter valueAdapter = null;
-        owningProperty.setupCommand(targetAdapter, valueAdapter);
-
-        invokeThruCommand(owningProperty, targetAdapter, interactionInitiatedBy);
-    }
-
-    private void invokeThruCommand(
-            final OneToOneAssociation owningProperty,
-            final ObjectAdapter targetAdapter,
-            final InteractionInitiatedBy interactionInitiatedBy) {
-
-        // similar code in PropertySetterFacetFDEA and ActionInvocationFacetFDEA
-
-        final CommandContext commandContext = getCommandContext();
-        final Command command = commandContext.getCommand();
-
-        final InteractionContext interactionContext = getInteractionContext();
-        final Interaction interaction = interactionContext.getInteraction();
-
-        final String propertyId = owningProperty.getIdentifier().toClassAndNameIdentityString();
-
-
-        if( command.getExecutor() == Command.Executor.USER &&
-                command.getExecuteIn() == org.apache.isis.applib.annotation.Command.ExecuteIn.BACKGROUND) {
-
-            // deal with background commands
-
-            // persist command so can it can subsequently be invoked in the 'background'
-            final CommandService commandService = getCommandService();
-            if (!commandService.persistIfPossible(command)) {
-                throw new IsisException(String.format(
-                        "Unable to persist command for property '%s'; CommandService does not support persistent commands ",
-                        propertyId));
-            }
-
-        } else {
-
-            // otherwise, go ahead and execute action in the 'foreground'
-
-            final Object target = ObjectAdapter.Util.unwrap(targetAdapter);
-
-            final Object argValue = null;
-            final Interaction.PropertyArgs propertyArgs = new Interaction.PropertyArgs(propertyId, target, argValue);
-            final Interaction.MemberCallable<?> callable = new Interaction.MemberCallable<Interaction.PropertyArgs>() {
-                @Override public Object call(final Interaction.PropertyArgs propertyArgs11) {
-
-                    // ... perform the property clear
-                    clearFacet.clearProperty(owningProperty, targetAdapter, interactionInitiatedBy);
-
-                    return null;
-                }
-            };
-
-            interaction.execute(callable, propertyArgs, getClockService(), command);
-
-            final Interaction.Execution priorExecution = interaction.getPriorExecution();
-
-            final RuntimeException executionExceptionIfAny = priorExecution.getException();
-            if(executionExceptionIfAny != null) {
-                throw executionExceptionIfAny;
-            }
-
-            //
-            // at this point in ActionInvocationFacetFDEA, the action is optionally published via the
-            // PublishingServiceInternal.  However, we currently do not support the concept of publishing simple
-            // property modifications.
-            //
-        }
-
-    }
-
-    /**
-     * Optional hook to allow the facet implementation for the deprecated {@link org.apache.isis.applib.annotation.PostsPropertyChangedEvent} annotation
-     * to discard the event if of a different type.
-     */
-    protected PropertyDomainEvent<?, ?> verify(PropertyDomainEvent<?, ?> event) {
-        return event;
-    }
-
-    private Class<? extends PropertyDomainEvent<?, ?>> eventType() {
-        return value();
-    }
-
-
-    private CommandContext getCommandContext() {
-        return lookupService(CommandContext.class);
-    }
-
-    private InteractionContext getInteractionContext() {
-        return lookupService(InteractionContext.class);
-    }
-
-    private CommandService getCommandService() {
-        return lookupService(CommandService.class);
-    }
-
-    private ClockService getClockService() {
-        return lookupService(ClockService.class);
-    }
-
-    private <T> T lookupService(final Class<T> serviceClass) {
-        T service = lookupServiceIfAny(serviceClass);
-        if(service == null) {
-            throw new IllegalStateException("The '" + serviceClass.getName() + "' service is not registered!");
-        }
-        return service;
-    }
-    private <T> T lookupServiceIfAny(final Class<T> serviceClass) {
-        return getServicesInjector().lookupService(serviceClass);
-    }
-
-    private ServicesInjector getServicesInjector() {
-        return servicesInjector;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/bb54a109/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForDomainEventFromDefault.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForDomainEventFromDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForDomainEventFromDefault.java
index ce0c9b1..7a1d076 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForDomainEventFromDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForDomainEventFromDefault.java
@@ -26,7 +26,8 @@ import org.apache.isis.core.metamodel.facets.properties.update.clear.PropertyCle
 import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
 
 public class PropertyClearFacetForDomainEventFromDefault
-        extends PropertyClearFacetForDomainEventAbstract {
+        extends PropertySetterOrClearFacetForDomainEventAbstract
+        implements PropertyClearFacet {
 
 
     public PropertyClearFacetForDomainEventFromDefault(
@@ -34,7 +35,8 @@ public class PropertyClearFacetForDomainEventFromDefault
             final PropertyOrCollectionAccessorFacet getterFacet,
             final PropertyClearFacet clearFacet,
             final PropertyDomainEventFacetAbstract propertyInteractionFacet,
-            final FacetHolder holder, final ServicesInjector servicesInjector) {
-        super(eventType, getterFacet, clearFacet, propertyInteractionFacet, servicesInjector, holder);
+            final FacetHolder holder,
+            final ServicesInjector servicesInjector) {
+        super(eventType, getterFacet, null, clearFacet, propertyInteractionFacet, servicesInjector, holder);
     }
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/bb54a109/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForDomainEventFromPropertyAnnotation.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForDomainEventFromPropertyAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForDomainEventFromPropertyAnnotation.java
index 226f6fd..3ed3617 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForDomainEventFromPropertyAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForDomainEventFromPropertyAnnotation.java
@@ -26,7 +26,8 @@ import org.apache.isis.core.metamodel.facets.properties.update.clear.PropertyCle
 import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
 
 public class PropertyClearFacetForDomainEventFromPropertyAnnotation
-        extends PropertyClearFacetForDomainEventAbstract {
+        extends PropertySetterOrClearFacetForDomainEventAbstract
+        implements PropertyClearFacet {
 
 
     public PropertyClearFacetForDomainEventFromPropertyAnnotation(
@@ -34,7 +35,8 @@ public class PropertyClearFacetForDomainEventFromPropertyAnnotation
             final PropertyOrCollectionAccessorFacet getterFacet,
             final PropertyClearFacet clearFacet,
             final PropertyDomainEventFacetAbstract propertyInteractionFacet,
-            final FacetHolder holder, final ServicesInjector servicesInjector) {
-        super(eventType, getterFacet, clearFacet, propertyInteractionFacet, servicesInjector, holder);
+            final FacetHolder holder,
+            final ServicesInjector servicesInjector) {
+        super(eventType, getterFacet, null, clearFacet, propertyInteractionFacet, servicesInjector, holder);
     }
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/bb54a109/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForDomainEventFromPropertyInteractionAnnotation.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForDomainEventFromPropertyInteractionAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForDomainEventFromPropertyInteractionAnnotation.java
index c421278..307256a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForDomainEventFromPropertyInteractionAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForDomainEventFromPropertyInteractionAnnotation.java
@@ -30,7 +30,8 @@ import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
  */
 @Deprecated
 public class PropertyClearFacetForDomainEventFromPropertyInteractionAnnotation
-        extends PropertyClearFacetForDomainEventAbstract {
+        extends PropertySetterOrClearFacetForDomainEventAbstract
+        implements PropertyClearFacet {
 
 
     public PropertyClearFacetForDomainEventFromPropertyInteractionAnnotation(
@@ -38,7 +39,8 @@ public class PropertyClearFacetForDomainEventFromPropertyInteractionAnnotation
             final PropertyOrCollectionAccessorFacet getterFacet,
             final PropertyClearFacet clearFacet,
             final PropertyDomainEventFacetAbstract propertyInteractionFacet,
-            final FacetHolder holder, final ServicesInjector servicesInjector) {
-        super(eventType, getterFacet, clearFacet, propertyInteractionFacet, servicesInjector, holder);
+            final FacetHolder holder,
+            final ServicesInjector servicesInjector) {
+        super(eventType, getterFacet, null, clearFacet, propertyInteractionFacet, servicesInjector, holder);
     }
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/bb54a109/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForPostsPropertyChangedEventAnnotation.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForPostsPropertyChangedEventAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForPostsPropertyChangedEventAnnotation.java
index 5f32e82..2fc86b9 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForPostsPropertyChangedEventAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyClearFacetForPostsPropertyChangedEventAnnotation.java
@@ -30,7 +30,8 @@ import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
  */
 @Deprecated
 public class PropertyClearFacetForPostsPropertyChangedEventAnnotation
-        extends PropertyClearFacetForDomainEventAbstract {
+        extends PropertySetterOrClearFacetForDomainEventAbstract
+        implements PropertyClearFacet {
 
 
     public PropertyClearFacetForPostsPropertyChangedEventAnnotation(
@@ -38,8 +39,9 @@ public class PropertyClearFacetForPostsPropertyChangedEventAnnotation
             final PropertyOrCollectionAccessorFacet getterFacet,
             final PropertyClearFacet clearFacet,
             final PropertyDomainEventFacetAbstract propertyInteractionFacet,
-            final FacetHolder holder, final ServicesInjector servicesInjector) {
-        super(eventType, getterFacet, clearFacet, propertyInteractionFacet, servicesInjector, holder);
+            final FacetHolder holder,
+            final ServicesInjector servicesInjector) {
+        super(eventType, getterFacet, null, clearFacet, propertyInteractionFacet, servicesInjector, holder);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/isis/blob/bb54a109/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventAbstract.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventAbstract.java
deleted file mode 100644
index 1509e41..0000000
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventAbstract.java
+++ /dev/null
@@ -1,236 +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.properties.property.modify;
-
-import com.google.common.base.Objects;
-
-import org.apache.isis.applib.services.clock.ClockService;
-import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.applib.services.command.CommandContext;
-import org.apache.isis.applib.services.command.spi.CommandService;
-import org.apache.isis.applib.services.eventbus.AbstractDomainEvent;
-import org.apache.isis.applib.services.eventbus.PropertyDomainEvent;
-import org.apache.isis.applib.services.iactn.Interaction;
-import org.apache.isis.applib.services.iactn.InteractionContext;
-import org.apache.isis.core.commons.exceptions.IsisException;
-import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
-import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
-import org.apache.isis.core.metamodel.facetapi.Facet;
-import org.apache.isis.core.metamodel.facetapi.FacetHolder;
-import org.apache.isis.core.metamodel.facets.DomainEventHelper;
-import org.apache.isis.core.metamodel.facets.SingleValueFacetAbstract;
-import org.apache.isis.core.metamodel.facets.propcoll.accessor.PropertyOrCollectionAccessorFacet;
-import org.apache.isis.core.metamodel.facets.properties.update.modify.PropertySetterFacet;
-import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
-import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
-
-public abstract class PropertySetterFacetForDomainEventAbstract
-        extends SingleValueFacetAbstract<Class<? extends PropertyDomainEvent<?,?>>>
-        implements PropertySetterFacet {
-
-    public static Class<? extends Facet> type() {
-        return PropertySetterFacet.class;
-    }
-
-    private final DomainEventHelper domainEventHelper;
-
-    private final PropertyOrCollectionAccessorFacet getterFacet;
-    private final PropertySetterFacet setterFacet;
-    private final PropertyDomainEventFacetAbstract propertyDomainEventFacet;
-
-    private final ServicesInjector servicesInjector;
-
-
-    public PropertySetterFacetForDomainEventAbstract(
-            final Class<? extends PropertyDomainEvent<?, ?>> eventType,
-            final PropertyOrCollectionAccessorFacet getterFacet,
-            final PropertySetterFacet setterFacet,
-            final PropertyDomainEventFacetAbstract propertyDomainEventFacet,
-            final ServicesInjector servicesInjector,
-            final FacetHolder holder) {
-        super(type(), eventType, holder);
-        this.getterFacet = getterFacet;
-        this.setterFacet = setterFacet;
-        this.propertyDomainEventFacet = propertyDomainEventFacet;
-        this.servicesInjector = servicesInjector;
-        this.domainEventHelper = new DomainEventHelper(servicesInjector);
-    }
-
-    @Override
-    public void setProperty(
-            final OneToOneAssociation owningAssociation,
-            final ObjectAdapter targetAdapter,
-            final ObjectAdapter newValueAdapter,
-            final InteractionInitiatedBy interactionInitiatedBy) {
-
-        // similar code in PropertyClearFacetFDEA and ActionInvocationFacetFDEA
-
-        if(setterFacet == null) {
-            return;
-        }
-
-        // ... post the executing event
-        final Object oldValue = getterFacet.getProperty(targetAdapter, interactionInitiatedBy);
-        final Object newValue = ObjectAdapter.Util.unwrap(newValueAdapter);
-
-        final PropertyDomainEvent<?, ?> event =
-                domainEventHelper.postEventForProperty(
-                        AbstractDomainEvent.Phase.EXECUTING,
-                        eventType(), null,
-                        getIdentified(), targetAdapter,
-                        oldValue, newValue);
-
-        setPropertyInternal(owningAssociation, targetAdapter, newValueAdapter, interactionInitiatedBy);
-
-        // reading the actual value from the target object, playing it safe...
-        final Object actualNewValue = getterFacet.getProperty(targetAdapter, interactionInitiatedBy);
-        if (!Objects.equal(oldValue, actualNewValue)) {
-
-            // ... post the executed event
-            domainEventHelper.postEventForProperty(
-                    AbstractDomainEvent.Phase.EXECUTED,
-                    eventType(), verify(event),
-                    getIdentified(), targetAdapter,
-                    oldValue, actualNewValue);
-        }
-    }
-
-    public void setPropertyInternal(
-            final OneToOneAssociation owningAssociation,
-            final ObjectAdapter targetAdapter,
-            final ObjectAdapter newValueAdapter,
-            final InteractionInitiatedBy interactionInitiatedBy) {
-
-        // similar code in PropertyClearFacetFDEA and ActionInvocationFacetFDEA
-
-        owningAssociation.setupCommand(targetAdapter, newValueAdapter);
-
-        invokeThruCommand(owningAssociation, targetAdapter, newValueAdapter, interactionInitiatedBy);
-    }
-
-    private void invokeThruCommand(
-            final OneToOneAssociation owningProperty,
-            final ObjectAdapter targetAdapter,
-            final ObjectAdapter valueAdapter,
-            final InteractionInitiatedBy interactionInitiatedBy) {
-
-        // similar code in PropertyClearFacetFDEA and ActionInvocationFacetFDEA
-
-        final CommandContext commandContext = getCommandContext();
-        final Command command = commandContext.getCommand();
-
-        final InteractionContext interactionContext = getInteractionContext();
-        final Interaction interaction = interactionContext.getInteraction();
-
-        final String propertyId = owningProperty.getIdentifier().toClassAndNameIdentityString();
-
-        if( command.getExecutor() == Command.Executor.USER &&
-                command.getExecuteIn() == org.apache.isis.applib.annotation.Command.ExecuteIn.BACKGROUND) {
-
-            // deal with background commands
-
-            // persist command so can it can subsequently be invoked in the 'background'
-            final CommandService commandService = getCommandService();
-            if (!commandService.persistIfPossible(command)) {
-                throw new IsisException(String.format(
-                        "Unable to persist command for property '%s'; CommandService does not support persistent commands ",
-                        propertyId));
-            }
-
-        } else {
-
-            // otherwise, go ahead and execute action in the 'foreground'
-
-            final Object target = ObjectAdapter.Util.unwrap(targetAdapter);
-            final Object argValue = ObjectAdapter.Util.unwrap(valueAdapter);
-
-            final Interaction.PropertyArgs propertyArgs = new Interaction.PropertyArgs(propertyId, target, argValue);
-            final Interaction.MemberCallable<?> callable = new Interaction.MemberCallable<Interaction.PropertyArgs>() {
-                        @Override public Object call(final Interaction.PropertyArgs propertyArgs11) {
-
-                            setterFacet.setProperty(
-                                    owningProperty, targetAdapter, valueAdapter, interactionInitiatedBy);
-                            return null;
-                        }
-                    };
-
-            interaction.execute(callable, propertyArgs, getClockService(), command);
-
-            final Interaction.Execution priorExecution = interaction.getPriorExecution();
-
-            final RuntimeException executionExceptionIfAny = priorExecution.getException();
-            if(executionExceptionIfAny != null) {
-                throw executionExceptionIfAny;
-            }
-
-            //
-            // at this point in ActionInvocationFacetFDEA, the action is optionally published via the
-            // PublishingServiceInternal.  However, we currently do not support the concept of publishing simple
-            // property modifications.
-            //
-        }
-    }
-
-    private Class<? extends PropertyDomainEvent<?, ?>> eventType() {
-        return value();
-    }
-
-    /**
-     * Optional hook to allow the facet implementation for the deprecated {@link org.apache.isis.applib.annotation.PostsPropertyChangedEvent} annotation
-     * to discard the event if of a different type.
-     */
-    protected PropertyDomainEvent<?, ?> verify(PropertyDomainEvent<?, ?> event) {
-        return event;
-    }
-
-
-
-    private ServicesInjector getServicesInjector() {
-        return servicesInjector;
-    }
-
-    private CommandContext getCommandContext() {
-        return lookupService(CommandContext.class);
-    }
-
-    private InteractionContext getInteractionContext() {
-        return lookupService(InteractionContext.class);
-    }
-
-    private CommandService getCommandService() {
-        return lookupService(CommandService.class);
-    }
-
-    private ClockService getClockService() {
-        return lookupService(ClockService.class);
-    }
-
-    private <T> T lookupService(final Class<T> serviceClass) {
-        T service = lookupServiceIfAny(serviceClass);
-        if(service == null) {
-            throw new IllegalStateException("The '" + serviceClass.getName() + "' service is not registered!");
-        }
-        return service;
-    }
-    private <T> T lookupServiceIfAny(final Class<T> serviceClass) {
-        return getServicesInjector().lookupService(serviceClass);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/isis/blob/bb54a109/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventFromDefault.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventFromDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventFromDefault.java
index 25f4e5a..396bcdf 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventFromDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventFromDefault.java
@@ -26,7 +26,8 @@ import org.apache.isis.core.metamodel.facets.properties.update.modify.PropertySe
 import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
 
 public class PropertySetterFacetForDomainEventFromDefault
-        extends PropertySetterFacetForDomainEventAbstract {
+        extends PropertySetterOrClearFacetForDomainEventAbstract
+        implements PropertySetterFacet {
 
 
     public PropertySetterFacetForDomainEventFromDefault(
@@ -34,7 +35,9 @@ public class PropertySetterFacetForDomainEventFromDefault
             final PropertyOrCollectionAccessorFacet getterFacet,
             final PropertySetterFacet setterFacet,
             final PropertyDomainEventFacetAbstract propertyInteractionFacet,
-            final FacetHolder holder, final ServicesInjector servicesInjector) {
-        super(eventType, getterFacet, setterFacet, propertyInteractionFacet, servicesInjector, holder);
+            final FacetHolder holder,
+            final ServicesInjector servicesInjector) {
+        super(eventType, getterFacet, setterFacet, null, propertyInteractionFacet, servicesInjector, holder);
     }
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/bb54a109/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventFromPropertyAnnotation.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventFromPropertyAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventFromPropertyAnnotation.java
index 10a80dd..f3e4217 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventFromPropertyAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventFromPropertyAnnotation.java
@@ -26,7 +26,8 @@ import org.apache.isis.core.metamodel.facets.properties.update.modify.PropertySe
 import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
 
 public class PropertySetterFacetForDomainEventFromPropertyAnnotation
-        extends PropertySetterFacetForDomainEventAbstract {
+        extends PropertySetterOrClearFacetForDomainEventAbstract
+        implements PropertySetterFacet {
 
 
     public PropertySetterFacetForDomainEventFromPropertyAnnotation(
@@ -34,7 +35,8 @@ public class PropertySetterFacetForDomainEventFromPropertyAnnotation
             final PropertyOrCollectionAccessorFacet getterFacet,
             final PropertySetterFacet setterFacet,
             final PropertyDomainEventFacetAbstract propertyInteractionFacet,
-            final FacetHolder holder, final ServicesInjector servicesInjector) {
-        super(eventType, getterFacet, setterFacet, propertyInteractionFacet, servicesInjector, holder);
+            final FacetHolder holder,
+            final ServicesInjector servicesInjector) {
+        super(eventType, getterFacet, setterFacet, null, propertyInteractionFacet, servicesInjector, holder);
     }
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/bb54a109/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventFromPropertyInteractionAnnotation.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventFromPropertyInteractionAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventFromPropertyInteractionAnnotation.java
index d7cb709..f977679 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventFromPropertyInteractionAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventFromPropertyInteractionAnnotation.java
@@ -30,7 +30,8 @@ import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
  */
 @Deprecated
 public class PropertySetterFacetForDomainEventFromPropertyInteractionAnnotation
-        extends PropertySetterFacetForDomainEventAbstract {
+        extends PropertySetterOrClearFacetForDomainEventAbstract
+        implements PropertySetterFacet {
 
 
     public PropertySetterFacetForDomainEventFromPropertyInteractionAnnotation(
@@ -38,7 +39,8 @@ public class PropertySetterFacetForDomainEventFromPropertyInteractionAnnotation
             final PropertyOrCollectionAccessorFacet getterFacet,
             final PropertySetterFacet setterFacet,
             final PropertyDomainEventFacetAbstract propertyInteractionFacet,
-            final FacetHolder holder, final ServicesInjector servicesInjector) {
-        super(eventType, getterFacet, setterFacet, propertyInteractionFacet, servicesInjector, holder);
+            final FacetHolder holder,
+            final ServicesInjector servicesInjector) {
+        super(eventType, getterFacet, setterFacet, null, propertyInteractionFacet, servicesInjector, holder);
     }
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/bb54a109/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForPostsPropertyChangedEventAnnotation.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForPostsPropertyChangedEventAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForPostsPropertyChangedEventAnnotation.java
index ec49a3a..81b6742 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForPostsPropertyChangedEventAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForPostsPropertyChangedEventAnnotation.java
@@ -30,7 +30,8 @@ import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
  */
 @Deprecated
 public class PropertySetterFacetForPostsPropertyChangedEventAnnotation
-        extends PropertySetterFacetForDomainEventAbstract {
+        extends PropertySetterOrClearFacetForDomainEventAbstract
+        implements PropertySetterFacet {
 
 
     public PropertySetterFacetForPostsPropertyChangedEventAnnotation(
@@ -38,8 +39,9 @@ public class PropertySetterFacetForPostsPropertyChangedEventAnnotation
             final PropertyOrCollectionAccessorFacet getterFacet,
             final PropertySetterFacet setterFacet,
             final PropertyDomainEventFacetAbstract propertyInteractionFacet,
-            final FacetHolder holder, final ServicesInjector servicesInjector) {
-        super(eventType, getterFacet, setterFacet, propertyInteractionFacet, servicesInjector, holder);
+            final FacetHolder holder,
+            final ServicesInjector servicesInjector) {
+        super(eventType, getterFacet, setterFacet, null, propertyInteractionFacet, servicesInjector, holder);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/isis/blob/bb54a109/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterOrClearFacetForDomainEventAbstract.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterOrClearFacetForDomainEventAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterOrClearFacetForDomainEventAbstract.java
new file mode 100644
index 0000000..a6496e5
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterOrClearFacetForDomainEventAbstract.java
@@ -0,0 +1,310 @@
+/*
+ *  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.properties.property.modify;
+
+import com.google.common.base.Objects;
+
+import org.apache.isis.applib.services.clock.ClockService;
+import org.apache.isis.applib.services.command.Command;
+import org.apache.isis.applib.services.command.CommandContext;
+import org.apache.isis.applib.services.command.spi.CommandService;
+import org.apache.isis.applib.services.eventbus.AbstractDomainEvent;
+import org.apache.isis.applib.services.eventbus.PropertyDomainEvent;
+import org.apache.isis.applib.services.iactn.Interaction;
+import org.apache.isis.applib.services.iactn.InteractionContext;
+import org.apache.isis.core.commons.exceptions.IsisException;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.DomainEventHelper;
+import org.apache.isis.core.metamodel.facets.SingleValueFacetAbstract;
+import org.apache.isis.core.metamodel.facets.propcoll.accessor.PropertyOrCollectionAccessorFacet;
+import org.apache.isis.core.metamodel.facets.properties.update.clear.PropertyClearFacet;
+import org.apache.isis.core.metamodel.facets.properties.update.modify.PropertySetterFacet;
+import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+
+public abstract class PropertySetterOrClearFacetForDomainEventAbstract
+        extends SingleValueFacetAbstract<Class<? extends PropertyDomainEvent<?,?>>> {
+
+    public static Class<? extends Facet> type() {
+        return PropertySetterFacet.class;
+    }
+
+    private final DomainEventHelper domainEventHelper;
+
+    private final PropertyOrCollectionAccessorFacet getterFacet;
+    private final PropertySetterFacet setterFacet;
+    private final PropertyClearFacet clearFacet;
+    private final PropertyDomainEventFacetAbstract propertyDomainEventFacet;
+
+    private final ServicesInjector servicesInjector;
+
+
+    public PropertySetterOrClearFacetForDomainEventAbstract(
+            final Class<? extends PropertyDomainEvent<?, ?>> eventType,
+            final PropertyOrCollectionAccessorFacet getterFacet,
+            final PropertySetterFacet setterFacet,
+            final PropertyClearFacet clearFacet,
+            final PropertyDomainEventFacetAbstract propertyDomainEventFacet,
+            final ServicesInjector servicesInjector,
+            final FacetHolder holder) {
+        super(type(), eventType, holder);
+        this.getterFacet = getterFacet;
+        this.setterFacet = setterFacet;
+        this.clearFacet = clearFacet;
+        this.propertyDomainEventFacet = propertyDomainEventFacet;
+        this.servicesInjector = servicesInjector;
+        this.domainEventHelper = new DomainEventHelper(servicesInjector);
+    }
+
+    enum Type {
+        SET {
+            @Override
+            boolean meetsPrereqs(final PropertySetterOrClearFacetForDomainEventAbstract facet) {
+                return facet.setterFacet != null;
+            }
+
+            @Override
+            void invoke(
+                    final PropertySetterOrClearFacetForDomainEventAbstract facet,
+                    final OneToOneAssociation owningProperty,
+                    final ObjectAdapter targetAdapter,
+                    final ObjectAdapter valueAdapterOrNull,
+                    final InteractionInitiatedBy interactionInitiatedBy) {
+                facet.setterFacet.setProperty(
+                        owningProperty, targetAdapter, valueAdapterOrNull, interactionInitiatedBy);
+
+            }
+        },
+        CLEAR {
+            @Override
+            boolean meetsPrereqs(final PropertySetterOrClearFacetForDomainEventAbstract facet) {
+                return facet.clearFacet != null;
+            }
+
+            @Override
+            void invoke(
+                    final PropertySetterOrClearFacetForDomainEventAbstract facet,
+                    final OneToOneAssociation owningProperty,
+                    final ObjectAdapter targetAdapter,
+                    final ObjectAdapter valueAdapterOrNull,
+                    final InteractionInitiatedBy interactionInitiatedBy) {
+
+                facet.clearFacet.clearProperty(
+                        owningProperty, targetAdapter, interactionInitiatedBy);
+
+            }
+        };
+
+        abstract boolean meetsPrereqs(final PropertySetterOrClearFacetForDomainEventAbstract facet);
+
+        abstract void invoke(
+                final PropertySetterOrClearFacetForDomainEventAbstract facet,
+                final OneToOneAssociation owningProperty,
+                final ObjectAdapter targetAdapter,
+                final ObjectAdapter valueAdapterOrNull,
+                final InteractionInitiatedBy interactionInitiatedBy);
+    }
+
+    public void clearProperty(
+            final OneToOneAssociation owningProperty,
+            final ObjectAdapter targetAdapter,
+            final InteractionInitiatedBy interactionInitiatedBy) {
+
+        setOrClearProperty(Type.CLEAR,
+                owningProperty, targetAdapter, null, interactionInitiatedBy);
+
+    }
+
+    public void setProperty(
+            final OneToOneAssociation owningProperty,
+            final ObjectAdapter targetAdapter,
+            final ObjectAdapter newValueAdapter,
+            final InteractionInitiatedBy interactionInitiatedBy) {
+
+        setOrClearProperty(Type.SET,
+                owningProperty, targetAdapter, newValueAdapter, interactionInitiatedBy);
+
+    }
+
+    private void setOrClearProperty(
+            final Type type,
+            final OneToOneAssociation owningAssociation,
+            final ObjectAdapter targetAdapter,
+            final ObjectAdapter newValueAdapter,
+            final InteractionInitiatedBy interactionInitiatedBy) {
+
+        // similar code in ActionInvocationFacetFDEA
+
+        if(!type.meetsPrereqs(this)) {
+            return;
+        }
+
+        // ... post the executing event
+        final Object oldValue = getterFacet.getProperty(targetAdapter, interactionInitiatedBy);
+        final Object newValue = ObjectAdapter.Util.unwrap(newValueAdapter);
+
+        final PropertyDomainEvent<?, ?> event =
+                domainEventHelper.postEventForProperty(
+                        AbstractDomainEvent.Phase.EXECUTING,
+                        eventType(), null,
+                        getIdentified(), targetAdapter,
+                        oldValue, newValue);
+
+        setPropertyInternal(type, owningAssociation, targetAdapter, newValueAdapter, interactionInitiatedBy);
+
+        // reading the actual value from the target object, playing it safe...
+        final Object actualNewValue = getterFacet.getProperty(targetAdapter, interactionInitiatedBy);
+        if (!Objects.equal(oldValue, actualNewValue)) {
+
+            // ... post the executed event
+            domainEventHelper.postEventForProperty(
+                    AbstractDomainEvent.Phase.EXECUTED,
+                    eventType(), verify(event),
+                    getIdentified(), targetAdapter,
+                    oldValue, actualNewValue);
+        }
+    }
+
+    public void setPropertyInternal(
+            final Type type,
+            final OneToOneAssociation owningProperty,
+            final ObjectAdapter targetAdapter,
+            final ObjectAdapter newValueAdapter,
+            final InteractionInitiatedBy interactionInitiatedBy) {
+
+        // similar code in ActionInvocationFacetFDEA
+
+        owningProperty.setupCommand(targetAdapter, newValueAdapter);
+
+        invokeThruCommand(type, owningProperty, targetAdapter, newValueAdapter, interactionInitiatedBy);
+    }
+
+    private void invokeThruCommand(
+            final Type type,
+            final OneToOneAssociation owningProperty,
+            final ObjectAdapter targetAdapter,
+            final ObjectAdapter valueAdapterOrNull,
+            final InteractionInitiatedBy interactionInitiatedBy) {
+
+        // similar code in ActionInvocationFacetFDEA
+
+        final CommandContext commandContext = getCommandContext();
+        final Command command = commandContext.getCommand();
+
+        final InteractionContext interactionContext = getInteractionContext();
+        final Interaction interaction = interactionContext.getInteraction();
+
+        final String propertyId = owningProperty.getIdentifier().toClassAndNameIdentityString();
+
+        if( command.getExecutor() == Command.Executor.USER &&
+                command.getExecuteIn() == org.apache.isis.applib.annotation.Command.ExecuteIn.BACKGROUND) {
+
+            // deal with background commands
+
+            // persist command so can it can subsequently be invoked in the 'background'
+            final CommandService commandService = getCommandService();
+            if (!commandService.persistIfPossible(command)) {
+                throw new IsisException(String.format(
+                        "Unable to persist command for property '%s'; CommandService does not support persistent commands ",
+                        propertyId));
+            }
+
+        } else {
+
+            // otherwise, go ahead and execute action in the 'foreground'
+
+            final Object target = ObjectAdapter.Util.unwrap(targetAdapter);
+            final Object argValue = ObjectAdapter.Util.unwrap(valueAdapterOrNull);
+
+            final Interaction.PropertyArgs propertyArgs = new Interaction.PropertyArgs(propertyId, target, argValue);
+            final Interaction.MemberCallable<?> callable = new Interaction.MemberCallable<Interaction.PropertyArgs>() {
+                        @Override public Object call(final Interaction.PropertyArgs propertyArgs11) {
+
+                            type.invoke(PropertySetterOrClearFacetForDomainEventAbstract.this, owningProperty, targetAdapter, valueAdapterOrNull, interactionInitiatedBy);
+                            return null;
+                        }
+                    };
+
+            interaction.execute(callable, propertyArgs, getClockService(), command);
+
+            final Interaction.Execution priorExecution = interaction.getPriorExecution();
+
+            final RuntimeException executionExceptionIfAny = priorExecution.getException();
+            if(executionExceptionIfAny != null) {
+                throw executionExceptionIfAny;
+            }
+
+            //
+            // at this point in ActionInvocationFacetFDEA, the action is optionally published via the
+            // PublishingServiceInternal.  However, we currently do not support the concept of publishing simple
+            // property modifications.
+            //
+        }
+    }
+
+    private Class<? extends PropertyDomainEvent<?, ?>> eventType() {
+        return value();
+    }
+
+    /**
+     * Optional hook to allow the facet implementation for the deprecated {@link org.apache.isis.applib.annotation.PostsPropertyChangedEvent} annotation
+     * to discard the event if of a different type.
+     */
+    protected PropertyDomainEvent<?, ?> verify(PropertyDomainEvent<?, ?> event) {
+        return event;
+    }
+
+
+
+    private ServicesInjector getServicesInjector() {
+        return servicesInjector;
+    }
+
+    private CommandContext getCommandContext() {
+        return lookupService(CommandContext.class);
+    }
+
+    private InteractionContext getInteractionContext() {
+        return lookupService(InteractionContext.class);
+    }
+
+    private CommandService getCommandService() {
+        return lookupService(CommandService.class);
+    }
+
+    private ClockService getClockService() {
+        return lookupService(ClockService.class);
+    }
+
+    private <T> T lookupService(final Class<T> serviceClass) {
+        T service = lookupServiceIfAny(serviceClass);
+        if(service == null) {
+            throw new IllegalStateException("The '" + serviceClass.getName() + "' service is not registered!");
+        }
+        return service;
+    }
+    private <T> T lookupServiceIfAny(final Class<T> serviceClass) {
+        return getServicesInjector().lookupService(serviceClass);
+    }
+
+}