This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git

commit b9adf68d3cb78424c6c081a95d79911d5692d07c
Author: danhaywood <d...@haywood-associates.co.uk>
AuthorDate: Wed Nov 21 22:35:23 2018 +0100

    ISIS-2043: adds domainEvents for @DomainObject
---
 .../org/apache/isis/applib/annotation/Action.java  |  6 --
 .../apache/isis/applib/annotation/Collection.java  |  6 --
 .../isis/applib/annotation/DomainObject.java       | 81 ++++++++++++++++++++++
 .../apache/isis/applib/annotation/Property.java    |  6 --
 .../action/ActionAnnotationFacetFactory.java       | 22 ++++--
 .../CollectionAnnotationFacetFactory.java          | 27 ++++++--
 .../DomainObjectAnnotationFacetFactory.java        | 54 +++++++++++++++
 ...EventDefaultFacetForDomainObjectAnnotation.java | 54 +++++++++++++++
 ...EventDefaultFacetForDomainObjectAnnotation.java | 53 ++++++++++++++
 ...EventDefaultFacetForDomainObjectAnnotation.java | 53 ++++++++++++++
 .../property/PropertyAnnotationFacetFactory.java   | 65 ++++++++++++++---
 .../simple/subscribers/SimpleObjectListener.java   |  4 ++
 12 files changed, 395 insertions(+), 36 deletions(-)

diff --git 
a/core/applib/src/main/java/org/apache/isis/applib/annotation/Action.java 
b/core/applib/src/main/java/org/apache/isis/applib/annotation/Action.java
index d1178eb..4ac31f7 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/Action.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/Action.java
@@ -63,12 +63,6 @@ public @interface Action {
      * <p>
      * This subclass must provide a no-arg constructor; the fields are set 
reflectively.
      * </p>
-     *
-     * <p>
-     * Only domain services should be registered as subscribers; only domain 
services are guaranteed to be instantiated and
-     * resident in memory.  The typical implementation of a domain service 
subscriber is to identify the impacted entities,
-     * load them using a repository, and then to delegate to the event to them.
-     * </p>
      */
     Class<? extends ActionDomainEvent<?>> domainEvent() default 
ActionDomainEvent.Default.class;
 
diff --git 
a/core/applib/src/main/java/org/apache/isis/applib/annotation/Collection.java 
b/core/applib/src/main/java/org/apache/isis/applib/annotation/Collection.java
index 50b8f95..444881d 100644
--- 
a/core/applib/src/main/java/org/apache/isis/applib/annotation/Collection.java
+++ 
b/core/applib/src/main/java/org/apache/isis/applib/annotation/Collection.java
@@ -54,12 +54,6 @@ public @interface Collection {
      * </pre>
      *
      * <p>
-     * Only domain services should be registered as subscribers; only domain 
services are guaranteed to be instantiated and
-     * resident in memory.  The typical implementation of a domain service 
subscriber is to identify the impacted entities,
-     * load them using a repository, and then to delegate to the event to them.
-     * </p>
-     *
-     * <p>
      * This subclass must provide a no-arg constructor; the fields are set 
reflectively.
      * </p>
      */
diff --git 
a/core/applib/src/main/java/org/apache/isis/applib/annotation/DomainObject.java 
b/core/applib/src/main/java/org/apache/isis/applib/annotation/DomainObject.java
index 97a9512..abce74b 100644
--- 
a/core/applib/src/main/java/org/apache/isis/applib/annotation/DomainObject.java
+++ 
b/core/applib/src/main/java/org/apache/isis/applib/annotation/DomainObject.java
@@ -24,6 +24,8 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+import org.apache.isis.applib.services.eventbus.ActionDomainEvent;
+import org.apache.isis.applib.services.eventbus.CollectionDomainEvent;
 import org.apache.isis.applib.services.eventbus.ObjectCreatedEvent;
 import org.apache.isis.applib.services.eventbus.ObjectLoadedEvent;
 import org.apache.isis.applib.services.eventbus.ObjectPersistedEvent;
@@ -31,6 +33,7 @@ import 
org.apache.isis.applib.services.eventbus.ObjectPersistingEvent;
 import org.apache.isis.applib.services.eventbus.ObjectRemovingEvent;
 import org.apache.isis.applib.services.eventbus.ObjectUpdatedEvent;
 import org.apache.isis.applib.services.eventbus.ObjectUpdatingEvent;
+import org.apache.isis.applib.services.eventbus.PropertyDomainEvent;
 import org.apache.isis.applib.services.publish.PublisherService;
 
 /**
@@ -246,4 +249,82 @@ public @interface DomainObject {
      * </p>
      */
     Class<? extends ObjectRemovingEvent<?>> removingLifecycleEvent() default 
ObjectRemovingEvent.Default.class;
+
+
+    /**
+     * Indicates that an invocation of <i>any</i> action of the domain object 
(that do not themselves specify their own
+     * <tt>&#64;Action(domainEvent=...)</tt> should be posted to the
+     * {@link org.apache.isis.applib.services.eventbus.EventBusService event 
bus} using the specified custom
+     * (subclass of) {@link 
org.apache.isis.applib.services.eventbus.ActionDomainEvent}.
+     *
+     * <p>For example:
+     * </p>
+     *
+     * <pre>
+     * 
&#64;DomainObject(actionDomainEvent=SomeObject.GenericActionDomainEvent.class)
+     * public class SomeObject{
+     *     public static class GenericActionDomainEvent extends 
ActionDomainEvent&lt;Object&gt; { ... }
+     *
+     *     public void changeStartDate(final Date startDate) { ...}
+     *     ...
+     * }
+     * </pre>
+     *
+     * <p>
+     *     This will result in all actions as a more specific type to use) to 
emit this event.
+     * </p>
+     * <p>
+     * This subclass must provide a no-arg constructor; the fields are set 
reflectively.
+     * It must also use <tt>Object</tt> as its generic type.  This is to allow 
mixins to also emit the same event.
+     * </p>
+     */
+    Class<? extends ActionDomainEvent<?>> actionDomainEvent() default 
ActionDomainEvent.Default.class;
+
+    /**
+     * Indicates that changes to <i>any</i> property of the domain object 
(that do not themselves specify their own
+     * <tt>&#64;Property(domainEvent=...)</tt> should be posted to the
+     * {@link org.apache.isis.applib.services.eventbus.EventBusService event 
bus} using the specified custom
+     * (subclass of) {@link 
org.apache.isis.applib.services.eventbus.PropertyDomainEvent}.
+     *
+     * <p>For example:
+     * </p>
+     *
+     * <pre>
+     * 
&#64;DomainObject(propertyDomainEvent=SomeObject.GenericPropertyDomainEvent.class)
+     * public class SomeObject{
+     *
+     *    public LocalDate getStartDate() { ...}
+     * }
+     * </pre>
+     *
+     * <p>
+     * This subclass must provide a no-arg constructor; the fields are set 
reflectively.
+     * It must also use <tt>Object</tt> as its generic type.  This is to allow 
mixins to also emit the same event.
+     * </p>
+     */
+    Class<? extends PropertyDomainEvent<?,?>> propertyDomainEvent() default 
PropertyDomainEvent.Default.class;
+
+    /**
+     * Indicates that changes to <i>any</i> collection of the domain object 
(that do not themselves specify their own
+     * <tt>&#64;Collection(domainEvent=...)</tt>  should be posted to the
+     * {@link org.apache.isis.applib.services.eventbus.EventBusService event 
bus} using a custom (subclass of)
+     * {@link org.apache.isis.applib.services.eventbus.CollectionDomainEvent}.
+     *
+     * <p>For example:
+     * </p>
+     * <pre>
+     * 
&#64;DomainObject(collectionDomainEvent=Order.GenericCollectionDomainEvent.class)
+     * public class Order {
+     *
+     *   public SortedSet&lt;OrderLine&gt; getLineItems() { ...}
+     * }
+     * </pre>
+     *
+     * <p>
+     * This subclass must provide a no-arg constructor; the fields are set 
reflectively.
+     * It must also use <tt>Object</tt> as its generic type.  This is to allow 
mixins to also emit the same event.
+     * </p>
+     */
+    Class<? extends CollectionDomainEvent<?,?>> collectionDomainEvent() 
default CollectionDomainEvent.Default.class;
+
 }
\ No newline at end of file
diff --git 
a/core/applib/src/main/java/org/apache/isis/applib/annotation/Property.java 
b/core/applib/src/main/java/org/apache/isis/applib/annotation/Property.java
index ed91f9e..7d248d5 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/Property.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/Property.java
@@ -61,12 +61,6 @@ public @interface Property {
      * </pre>
      *
      * <p>
-     * Only domain services should be registered as subscribers; only domain 
services are guaranteed to be instantiated
-     * and resident in memory.  The typical implementation of a domain service 
subscriber is to identify the impacted
-     * entities, load them using a repository, and then to delegate to the 
event to them.
-     * </p>
-     *
-     * <p>
      * This subclass must provide a no-arg constructor; the fields are set 
reflectively.
      * </p>
      */
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactory.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactory.java
index b26586d..255f7c0 100644
--- 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactory.java
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactory.java
@@ -85,6 +85,7 @@ import 
org.apache.isis.core.metamodel.facets.actions.semantics.ActionSemanticsFa
 import org.apache.isis.core.metamodel.facets.all.hide.HiddenFacet;
 import org.apache.isis.core.metamodel.facets.members.disabled.DisabledFacet;
 import 
org.apache.isis.core.metamodel.facets.members.order.annotprop.MemberOrderFacetForActionAnnotation;
+import 
org.apache.isis.core.metamodel.facets.object.domainobject.domainevents.ActionDomainEventDefaultFacetForDomainObjectAnnotation;
 import org.apache.isis.core.metamodel.services.ServicesInjector;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.CollectionUtils;
@@ -172,19 +173,19 @@ public class ActionAnnotationFacetFactory extends 
FacetFactoryAbstract
 
             // search for @ActionInteraction(value=...)
             if(actionInteraction != null) {
-                actionDomainEventType = actionInteraction.value();
+                actionDomainEventType = 
defaultFromDomainObjectIfRequired(typeSpec, actionInteraction.value());
                 actionDomainEventFacet = new 
ActionDomainEventFacetForActionInteractionAnnotation(
                         actionDomainEventType, servicesInjector, 
getSpecificationLoader(), holder);
             } else
             // search for @Action(domainEvent=...)
-            if(action != null && action.domainEvent() != null) {
-                actionDomainEventType = action.domainEvent();
+            if(action != null) {
+                actionDomainEventType = 
defaultFromDomainObjectIfRequired(typeSpec, action.domainEvent());
                 actionDomainEventFacet = new 
ActionDomainEventFacetForActionAnnotation(
                         actionDomainEventType, servicesInjector, 
getSpecificationLoader(), holder);
             } else
             // else use default event type
             {
-                actionDomainEventType = ActionDomainEvent.Default.class;
+                actionDomainEventType = 
defaultFromDomainObjectIfRequired(typeSpec, ActionDomainEvent.Default.class);
                 actionDomainEventFacet = new ActionDomainEventFacetDefault(
                         actionDomainEventType, servicesInjector, 
getSpecificationLoader(), holder);
             }
@@ -238,6 +239,19 @@ public class ActionAnnotationFacetFactory extends 
FacetFactoryAbstract
         }
     }
 
+    private static Class<? extends ActionDomainEvent<?>> 
defaultFromDomainObjectIfRequired(
+            final ObjectSpecification typeSpec,
+            final Class<? extends ActionDomainEvent<?>> actionDomainEventType) 
{
+        if (actionDomainEventType == ActionDomainEvent.Default.class) {
+            final ActionDomainEventDefaultFacetForDomainObjectAnnotation 
typeFromDomainObject =
+                    
typeSpec.getFacet(ActionDomainEventDefaultFacetForDomainObjectAnnotation.class);
+            if (typeFromDomainObject != null) {
+                return typeFromDomainObject.getEventType();
+            }
+        }
+        return actionDomainEventType;
+    }
+
     void processHidden(final ProcessMethodContext processMethodContext) {
         final Method method = processMethodContext.getMethod();
         final FacetHolder holder = processMethodContext.getFacetHolder();
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/collection/CollectionAnnotationFacetFactory.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/collection/CollectionAnnotationFacetFactory.java
index 55e1fc1..1832bda 100644
--- 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/collection/CollectionAnnotationFacetFactory.java
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/collection/CollectionAnnotationFacetFactory.java
@@ -70,9 +70,11 @@ import 
org.apache.isis.core.metamodel.facets.collections.collection.typeof.TypeO
 import 
org.apache.isis.core.metamodel.facets.collections.modify.CollectionAddToFacet;
 import 
org.apache.isis.core.metamodel.facets.collections.modify.CollectionRemoveFromFacet;
 import org.apache.isis.core.metamodel.facets.members.disabled.DisabledFacet;
+import 
org.apache.isis.core.metamodel.facets.object.domainobject.domainevents.CollectionDomainEventDefaultFacetForDomainObjectAnnotation;
 import 
org.apache.isis.core.metamodel.facets.propcoll.accessor.PropertyOrCollectionAccessorFacet;
 import 
org.apache.isis.core.metamodel.facets.propcoll.notpersisted.NotPersistedFacet;
 import org.apache.isis.core.metamodel.services.ServicesInjector;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.CollectionUtils;
 import 
org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorComposite;
 import 
org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorForDeprecatedAnnotation;
@@ -105,6 +107,9 @@ public class CollectionAnnotationFacetFactory extends 
FacetFactoryAbstract imple
     void processModify(final ProcessMethodContext processMethodContext) {
 
         final Method method = processMethodContext.getMethod();
+
+        final Class<?> cls = processMethodContext.getCls();
+        final ObjectSpecification typeSpec = 
getSpecificationLoader().loadSpecification(cls);
         final FacetHolder holder = processMethodContext.getFacetHolder();
 
         final PropertyOrCollectionAccessorFacet getterFacet = 
holder.getFacet(PropertyOrCollectionAccessorFacet.class);
@@ -145,21 +150,21 @@ public class CollectionAnnotationFacetFactory extends 
FacetFactoryAbstract imple
 
         // search for @CollectionInteraction(value=...)
         if(collectionInteraction != null) {
-            collectionDomainEventType = collectionInteraction.value();
+            collectionDomainEventType = 
defaultFromDomainObjectIfRequired(typeSpec, collectionInteraction.value());
             collectionDomainEventFacet = 
collectionInteractionValidator.flagIfPresent(
                     new 
CollectionDomainEventFacetForCollectionInteractionAnnotation(
                         collectionDomainEventType, servicesInjector, 
getSpecificationLoader(), holder), processMethodContext);
         } else
         // search for @Collection(domainEvent=...)
-        if(collection != null && collection.domainEvent() != null) {
-            collectionDomainEventType = collection.domainEvent();
+        if(collection != null) {
+            collectionDomainEventType = 
defaultFromDomainObjectIfRequired(typeSpec, collection.domainEvent());
             collectionDomainEventFacet = new 
CollectionDomainEventFacetForCollectionAnnotation(
                     collectionDomainEventType, servicesInjector, 
getSpecificationLoader(), holder);
 
         } else
         // else use default event type
         {
-            collectionDomainEventType = CollectionDomainEvent.Default.class;
+            collectionDomainEventType = 
defaultFromDomainObjectIfRequired(typeSpec, 
CollectionDomainEvent.Default.class);
             collectionDomainEventFacet = new CollectionDomainEventFacetDefault(
                     collectionDomainEventType, servicesInjector, 
getSpecificationLoader(), holder);
         }
@@ -237,6 +242,20 @@ public class CollectionAnnotationFacetFactory extends 
FacetFactoryAbstract imple
 
     }
 
+    private static Class<? extends CollectionDomainEvent<?,?>> 
defaultFromDomainObjectIfRequired(
+            final ObjectSpecification typeSpec,
+            final Class<? extends CollectionDomainEvent<?,?>> 
collectionDomainEventType) {
+        if (collectionDomainEventType == CollectionDomainEvent.Default.class) {
+            final CollectionDomainEventDefaultFacetForDomainObjectAnnotation 
typeFromDomainObject =
+                    
typeSpec.getFacet(CollectionDomainEventDefaultFacetForDomainObjectAnnotation.class);
+            if (typeFromDomainObject != null) {
+                return typeFromDomainObject.getEventType();
+            }
+        }
+        return collectionDomainEventType;
+    }
+
+
     void processHidden(final ProcessMethodContext processMethodContext) {
         final Method method = processMethodContext.getMethod();
         final FacetHolder holder = processMethodContext.getFacetHolder();
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
index 2a35bba..35808b6 100644
--- 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
@@ -34,6 +34,8 @@ import org.apache.isis.applib.annotation.Nature;
 import org.apache.isis.applib.annotation.ObjectType;
 import org.apache.isis.applib.annotation.PublishedObject;
 import org.apache.isis.applib.services.HasTransactionId;
+import org.apache.isis.applib.services.eventbus.ActionDomainEvent;
+import org.apache.isis.applib.services.eventbus.CollectionDomainEvent;
 import org.apache.isis.applib.services.eventbus.ObjectCreatedEvent;
 import org.apache.isis.applib.services.eventbus.ObjectLoadedEvent;
 import org.apache.isis.applib.services.eventbus.ObjectPersistedEvent;
@@ -41,6 +43,7 @@ import 
org.apache.isis.applib.services.eventbus.ObjectPersistingEvent;
 import org.apache.isis.applib.services.eventbus.ObjectRemovingEvent;
 import org.apache.isis.applib.services.eventbus.ObjectUpdatedEvent;
 import org.apache.isis.applib.services.eventbus.ObjectUpdatingEvent;
+import org.apache.isis.applib.services.eventbus.PropertyDomainEvent;
 import org.apache.isis.core.commons.config.IsisConfiguration;
 import org.apache.isis.core.commons.lang.Nullable;
 import org.apache.isis.core.metamodel.facetapi.Facet;
@@ -68,6 +71,9 @@ import 
org.apache.isis.core.metamodel.facets.object.domainobject.autocomplete.Au
 import 
org.apache.isis.core.metamodel.facets.object.domainobject.autocomplete.AutoCompleteFacetForDomainObjectAnnotation;
 import 
org.apache.isis.core.metamodel.facets.object.domainobject.choices.ChoicesFacetForDomainObjectAnnotation;
 import 
org.apache.isis.core.metamodel.facets.object.domainobject.choices.ChoicesFacetFromBoundedAnnotation;
+import 
org.apache.isis.core.metamodel.facets.object.domainobject.domainevents.ActionDomainEventDefaultFacetForDomainObjectAnnotation;
+import 
org.apache.isis.core.metamodel.facets.object.domainobject.domainevents.CollectionDomainEventDefaultFacetForDomainObjectAnnotation;
+import 
org.apache.isis.core.metamodel.facets.object.domainobject.domainevents.PropertyDomainEventDefaultFacetForDomainObjectAnnotation;
 import 
org.apache.isis.core.metamodel.facets.object.domainobject.editing.ImmutableFacetForDomainObjectAnnotation;
 import 
org.apache.isis.core.metamodel.facets.object.domainobject.objectspecid.ObjectSpecIdFacetForDomainObjectAnnotation;
 import 
org.apache.isis.core.metamodel.facets.object.domainobject.objectspecid.ObjectSpecIdFacetForJdoPersistenceCapableAnnotation;
@@ -124,6 +130,7 @@ public class DomainObjectAnnotationFacetFactory extends 
FacetFactoryAbstract
         processObjectType(processClassContext);
         processNature(processClassContext);
         processLifecycleEvents(processClassContext);
+        processDomainEvents(processClassContext);
 
     }
 
@@ -391,7 +398,21 @@ public class DomainObjectAnnotationFacetFactory extends 
FacetFactoryAbstract
         processLifecycleEventRemoving(domainObject, holder);
         processLifecycleEventUpdated(domainObject, holder);
         processLifecycleEventUpdating(domainObject, holder);
+    }
+
 
+    private void processDomainEvents(final ProcessClassContext 
processClassContext) {
+
+        final Class<?> cls = processClassContext.getCls();
+        final DomainObject domainObject = Annotations.getAnnotation(cls, 
DomainObject.class);
+        if(domainObject == null) {
+            return;
+        }
+        final FacetHolder holder = processClassContext.getFacetHolder();
+
+        processDomainEventAction(domainObject, holder);
+        processDomainEventProperty(domainObject, holder);
+        processDomainEventCollection(domainObject, holder);
     }
 
     private void processLifecycleEventCreated(final DomainObject domainObject, 
final FacetHolder holder) {
@@ -513,6 +534,39 @@ public class DomainObjectAnnotationFacetFactory extends 
FacetFactoryAbstract
         }
     }
 
+    private void processDomainEventAction(final DomainObject domainObject, 
final FacetHolder holder) {
+        final Class<? extends ActionDomainEvent<?>> domainEvent = 
domainObject.actionDomainEvent();
+
+        if(domainEvent != ActionDomainEvent.Default.class) {
+            final ActionDomainEventDefaultFacetForDomainObjectAnnotation facet 
=
+                    new ActionDomainEventDefaultFacetForDomainObjectAnnotation(
+                        holder, domainEvent, getSpecificationLoader());
+            FacetUtil.addFacet(facet);
+        }
+    }
+
+    private void processDomainEventProperty(final DomainObject domainObject, 
final FacetHolder holder) {
+        final Class<? extends PropertyDomainEvent<?,?>> domainEvent = 
domainObject.propertyDomainEvent();
+
+        if(domainEvent != PropertyDomainEvent.Default.class) {
+            final PropertyDomainEventDefaultFacetForDomainObjectAnnotation 
facet =
+                    new 
PropertyDomainEventDefaultFacetForDomainObjectAnnotation(
+                        holder, domainEvent, getSpecificationLoader());
+            FacetUtil.addFacet(facet);
+        }
+    }
+
+    private void processDomainEventCollection(final DomainObject domainObject, 
final FacetHolder holder) {
+        final Class<? extends CollectionDomainEvent<?,?>> domainEvent = 
domainObject.collectionDomainEvent();
+
+        if(domainEvent != CollectionDomainEvent.Default.class) {
+            final CollectionDomainEventDefaultFacetForDomainObjectAnnotation 
facet =
+                    new 
CollectionDomainEventDefaultFacetForDomainObjectAnnotation(
+                        holder, domainEvent, getSpecificationLoader());
+            FacetUtil.addFacet(facet);
+        }
+    }
+
     // //////////////////////////////////////
 
     @Override
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/domainevents/ActionDomainEventDefaultFacetForDomainObjectAnnotation.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/domainevents/ActionDomainEventDefaultFacetForDomainObjectAnnotation.java
new file mode 100644
index 0000000..2bb8aef
--- /dev/null
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/domainevents/ActionDomainEventDefaultFacetForDomainObjectAnnotation.java
@@ -0,0 +1,54 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.core.metamodel.facets.object.domainobject.domainevents;
+
+import org.apache.isis.applib.services.eventbus.ActionDomainEvent;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.SingleClassValueFacetAbstract;
+import 
org.apache.isis.core.metamodel.facets.actions.action.invocation.ActionDomainEventFacet;
+import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
+
+/**
+ * This does <i>NOT</i> implement {@link ActionDomainEventFacet}, rather it is 
to record the default type to use
+ * for any actions as a fallback/default.
+ */
+public class ActionDomainEventDefaultFacetForDomainObjectAnnotation
+                    extends SingleClassValueFacetAbstract  {
+
+
+    private final Class<? extends ActionDomainEvent<?>> eventType;
+    public Class<? extends ActionDomainEvent<?>> getEventType() {
+        return eventType;
+    }
+
+    static Class<? extends Facet> type() {
+        return ActionDomainEventDefaultFacetForDomainObjectAnnotation.class;
+    }
+
+    public ActionDomainEventDefaultFacetForDomainObjectAnnotation(
+            final FacetHolder holder,
+            final Class<? extends ActionDomainEvent<?>> value,
+            final SpecificationLoader specificationLoader) {
+        super(type(), holder, value, specificationLoader);
+        this.eventType = value;
+    }
+
+}
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/domainevents/CollectionDomainEventDefaultFacetForDomainObjectAnnotation.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/domainevents/CollectionDomainEventDefaultFacetForDomainObjectAnnotation.java
new file mode 100644
index 0000000..627b09d
--- /dev/null
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/domainevents/CollectionDomainEventDefaultFacetForDomainObjectAnnotation.java
@@ -0,0 +1,53 @@
+/*
+ *  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.object.domainobject.domainevents;
+
+import org.apache.isis.applib.services.eventbus.CollectionDomainEvent;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.SingleClassValueFacetAbstract;
+import 
org.apache.isis.core.metamodel.facets.actions.action.invocation.ActionDomainEventFacet;
+import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
+
+/**
+ * This does <i>NOT</i> implement {@link ActionDomainEventFacet}, rather it is 
to record the default type to use
+ * for any actions as a fallback/default.
+ */
+public class CollectionDomainEventDefaultFacetForDomainObjectAnnotation
+                    extends SingleClassValueFacetAbstract  {
+
+    private final Class<? extends CollectionDomainEvent<?, ?>> eventType;
+    public Class<? extends CollectionDomainEvent<?, ?>> getEventType() {
+        return eventType;
+    }
+
+    static Class<? extends Facet> type() {
+        return 
CollectionDomainEventDefaultFacetForDomainObjectAnnotation.class;
+    }
+
+    public CollectionDomainEventDefaultFacetForDomainObjectAnnotation(
+            final FacetHolder holder,
+            final Class<? extends CollectionDomainEvent<?,?>> value,
+            final SpecificationLoader specificationLoader) {
+        super(type(), holder, value, specificationLoader);
+        this.eventType = value;
+    }
+
+}
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/domainevents/PropertyDomainEventDefaultFacetForDomainObjectAnnotation.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/domainevents/PropertyDomainEventDefaultFacetForDomainObjectAnnotation.java
new file mode 100644
index 0000000..4688bbd
--- /dev/null
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/domainevents/PropertyDomainEventDefaultFacetForDomainObjectAnnotation.java
@@ -0,0 +1,53 @@
+/*
+ *  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.object.domainobject.domainevents;
+
+import org.apache.isis.applib.services.eventbus.PropertyDomainEvent;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.SingleClassValueFacetAbstract;
+import 
org.apache.isis.core.metamodel.facets.actions.action.invocation.ActionDomainEventFacet;
+import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
+
+/**
+ * This does <i>NOT</i> implement {@link ActionDomainEventFacet}, rather it is 
to record the default type to use
+ * for any actions as a fallback/default.
+ */
+public class PropertyDomainEventDefaultFacetForDomainObjectAnnotation
+                    extends SingleClassValueFacetAbstract  {
+
+    private final Class<? extends PropertyDomainEvent<?, ?>> eventType;
+    public Class<? extends PropertyDomainEvent<?, ?>> getEventType() {
+        return eventType;
+    }
+
+    static Class<? extends Facet> type() {
+        return PropertyDomainEventDefaultFacetForDomainObjectAnnotation.class;
+    }
+
+    public PropertyDomainEventDefaultFacetForDomainObjectAnnotation(
+            final FacetHolder holder,
+            final Class<? extends PropertyDomainEvent<?,?>> value,
+            final SpecificationLoader specificationLoader) {
+        super(type(), holder, value, specificationLoader);
+        this.eventType = value;
+    }
+
+}
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 7f919f7..47db77a 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
@@ -19,18 +19,37 @@
 
 package org.apache.isis.core.metamodel.facets.properties.property;
 
-import org.apache.isis.applib.annotation.*;
+import java.lang.reflect.Method;
+
+import javax.annotation.Nullable;
+
+import org.apache.isis.applib.annotation.Disabled;
+import org.apache.isis.applib.annotation.Hidden;
+import org.apache.isis.applib.annotation.Mandatory;
+import org.apache.isis.applib.annotation.MaxLength;
+import org.apache.isis.applib.annotation.MustSatisfy;
+import org.apache.isis.applib.annotation.NotPersisted;
+import org.apache.isis.applib.annotation.Optional;
+import org.apache.isis.applib.annotation.PostsPropertyChangedEvent;
+import org.apache.isis.applib.annotation.Property;
+import org.apache.isis.applib.annotation.PropertyInteraction;
+import org.apache.isis.applib.annotation.RegEx;
 import org.apache.isis.applib.services.HasTransactionId;
 import org.apache.isis.applib.services.eventbus.PropertyChangedEvent;
 import org.apache.isis.applib.services.eventbus.PropertyDomainEvent;
 import org.apache.isis.core.commons.config.IsisConfiguration;
-import org.apache.isis.core.metamodel.facetapi.*;
+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.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.FacetedMethod;
 import org.apache.isis.core.metamodel.facets.actions.command.CommandFacet;
 import org.apache.isis.core.metamodel.facets.all.hide.HiddenFacet;
 import org.apache.isis.core.metamodel.facets.members.disabled.DisabledFacet;
+import 
org.apache.isis.core.metamodel.facets.object.domainobject.domainevents.PropertyDomainEventDefaultFacetForDomainObjectAnnotation;
 import 
org.apache.isis.core.metamodel.facets.objectvalue.fileaccept.FileAcceptFacet;
 import 
org.apache.isis.core.metamodel.facets.objectvalue.mandatory.MandatoryFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.maxlen.MaxLengthFacet;
@@ -50,7 +69,18 @@ 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.*;
+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;
+import 
org.apache.isis.core.metamodel.facets.properties.property.modify.PropertyClearFacetForPostsPropertyChangedEventAnnotation;
+import 
org.apache.isis.core.metamodel.facets.properties.property.modify.PropertyDomainEventFacetAbstract;
+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.PropertySetterFacetForDomainEventFromDefault;
+import 
org.apache.isis.core.metamodel.facets.properties.property.modify.PropertySetterFacetForDomainEventFromPropertyAnnotation;
+import 
org.apache.isis.core.metamodel.facets.properties.property.modify.PropertySetterFacetForDomainEventFromPropertyInteractionAnnotation;
+import 
org.apache.isis.core.metamodel.facets.properties.property.modify.PropertySetterFacetForPostsPropertyChangedEventAnnotation;
 import 
org.apache.isis.core.metamodel.facets.properties.property.mustsatisfy.MustSatisfySpecificationFacetForMustSatisfyAnnotationOnProperty;
 import 
org.apache.isis.core.metamodel.facets.properties.property.mustsatisfy.MustSatisfySpecificationFacetForPropertyAnnotation;
 import 
org.apache.isis.core.metamodel.facets.properties.property.notpersisted.NotPersistedFacetForNotPersistedAnnotationOnProperty;
@@ -62,14 +92,12 @@ import 
org.apache.isis.core.metamodel.facets.properties.publish.PublishedPropert
 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.services.ServicesInjector;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import 
org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorComposite;
 import 
org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorForConflictingOptionality;
 import 
org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorForDeprecatedAnnotation;
 import org.apache.isis.core.metamodel.util.EventUtil;
 
-import javax.annotation.Nullable;
-import java.lang.reflect.Method;
-
 public class PropertyAnnotationFacetFactory extends FacetFactoryAbstract 
implements MetaModelValidatorRefiner {
 
     private final MetaModelValidatorForDeprecatedAnnotation 
postsPropertyChangedEventValidator = new 
MetaModelValidatorForDeprecatedAnnotation(PostsPropertyChangedEvent.class);
@@ -108,6 +136,9 @@ public class PropertyAnnotationFacetFactory extends 
FacetFactoryAbstract impleme
     void processModify(final ProcessMethodContext processMethodContext) {
 
         final Method method = processMethodContext.getMethod();
+
+        final Class<?> cls = processMethodContext.getCls();
+        final ObjectSpecification typeSpec = 
getSpecificationLoader().loadSpecification(cls);
         final FacetedMethod holder = processMethodContext.getFacetHolder();
 
         final PropertyOrCollectionAccessorFacet getterFacet = 
holder.getFacet(PropertyOrCollectionAccessorFacet.class);
@@ -136,21 +167,21 @@ public class PropertyAnnotationFacetFactory extends 
FacetFactoryAbstract impleme
 
         // search for @PropertyInteraction(value=...)
         if(propertyInteraction != null) {
-            propertyDomainEventType = propertyInteraction.value();
+            propertyDomainEventType = 
defaultFromDomainObjectIfRequired(typeSpec, propertyInteraction.value());
             propertyDomainEventFacet = 
propertyInteractionValidator.flagIfPresent(
                     new 
PropertyDomainEventFacetForPropertyInteractionAnnotation(
                         propertyDomainEventType, getterFacet, 
servicesInjector, getSpecificationLoader(), holder), processMethodContext);
         } else
         // search for @Property(domainEvent=...)
-        if(property != null && property.domainEvent() != null) {
-            propertyDomainEventType = property.domainEvent();
+        if(property != null) {
+            propertyDomainEventType = 
defaultFromDomainObjectIfRequired(typeSpec, property.domainEvent());
             propertyDomainEventFacet = new 
PropertyDomainEventFacetForPropertyAnnotation(
                     propertyDomainEventType, getterFacet, servicesInjector, 
getSpecificationLoader(), holder);
 
         } else
         // else use default event type
         {
-            propertyDomainEventType = PropertyDomainEvent.Default.class;
+            propertyDomainEventType = 
defaultFromDomainObjectIfRequired(typeSpec, PropertyDomainEvent.Default.class);
             propertyDomainEventFacet = new PropertyDomainEventFacetDefault(
                     propertyDomainEventType, getterFacet, servicesInjector, 
getSpecificationLoader(), holder);
         }
@@ -228,6 +259,20 @@ public class PropertyAnnotationFacetFactory extends 
FacetFactoryAbstract impleme
         }
     }
 
+    private static Class<? extends PropertyDomainEvent<?,?>> 
defaultFromDomainObjectIfRequired(
+            final ObjectSpecification typeSpec,
+            final Class<? extends PropertyDomainEvent<?,?>> 
propertyDomainEventType) {
+        if (propertyDomainEventType == PropertyDomainEvent.Default.class) {
+            final PropertyDomainEventDefaultFacetForDomainObjectAnnotation 
typeFromDomainObject =
+                    
typeSpec.getFacet(PropertyDomainEventDefaultFacetForDomainObjectAnnotation.class);
+            if (typeFromDomainObject != null) {
+                return typeFromDomainObject.getEventType();
+            }
+        }
+        return propertyDomainEventType;
+    }
+
+
 
     void processHidden(final ProcessMethodContext processMethodContext) {
         final Method method = processMethodContext.getMethod();
diff --git 
a/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/subscribers/SimpleObjectListener.java
 
b/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/subscribers/SimpleObjectListener.java
new file mode 100644
index 0000000..c377c55
--- /dev/null
+++ 
b/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/subscribers/SimpleObjectListener.java
@@ -0,0 +1,4 @@
+package domainapp.modules.simple.subscribers;
+
+public class SimpleObjectListener {
+}

Reply via email to