You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2020/05/10 16:32:12 UTC

[isis] branch master updated: ISIS-2340: fixing some regressions from prev. commit(s)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new d5eea5d  ISIS-2340: fixing some regressions from prev. commit(s)
d5eea5d is described below

commit d5eea5d2f500f6349e18d6dc3e75e825b2f83145
Author: Andi Huber <ah...@apache.org>
AuthorDate: Sun May 10 18:31:57 2020 +0200

    ISIS-2340: fixing some regressions from prev. commit(s)
    
    further simplifying
---
 .../core/metamodel/facets/DomainEventHelper.java   | 57 ++++++++++----------
 .../invocation/ActionDomainEventFacetAbstract.java |  6 +--
 .../action/invocation/ActionInvocationFacet.java   |  4 +-
 ...ctionInvocationFacetForDomainEventAbstract.java | 13 +++--
 ...ectionAddToFacetForDomainEventFromAbstract.java | 12 +++--
 .../modify/CollectionDomainEventFacetAbstract.java |  6 +--
 ...nRemoveFromFacetForDomainEventFromAbstract.java | 12 +++--
 .../facets/object/mixin/MixinFacetAbstract.java    | 21 ++++----
 .../parser/ParseableFacetUsingParser.java          |  7 +--
 .../modify/PropertyDomainEventFacetAbstract.java   |  6 +--
 ...tySetterOrClearFacetForDomainEventAbstract.java | 19 ++++---
 .../metamodel/interactions/InteractionContext.java | 56 +++++++++++++++----
 .../core/metamodel/spec/feature/ObjectAction.java  | 11 ++--
 .../metamodel/spec/interaction/ManagedAction.java  |  4 +-
 .../specloader/specimpl/ObjectActionDefault.java   | 32 ++++++-----
 .../specloader/specimpl/ObjectActionMixedIn.java   | 63 ++++------------------
 .../specloader/specimpl/ObjectMemberAbstract.java  |  9 ++--
 .../specimpl/OneToManyAssociationMixedIn.java      |  5 +-
 .../specimpl/OneToOneAssociationMixedIn.java       |  8 ++-
 .../command/CommandExecutorServiceDefault.java     |  5 +-
 .../handlers/DomainObjectInvocationHandler.java    |  8 +--
 .../jdo/dom/user/ApplicationUserRepository.java    |  4 +-
 .../viewer/vaadin/ui/pages/main/MainView.java      |  4 +-
 .../viewer/wicket/model/models/ActionModel.java    |  7 +--
 24 files changed, 190 insertions(+), 189 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/DomainEventHelper.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/DomainEventHelper.java
index 9fe41ef..adba4d4 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/DomainEventHelper.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/DomainEventHelper.java
@@ -19,6 +19,11 @@
 
 package org.apache.isis.core.metamodel.facets;
 
+import static org.apache.isis.core.commons.internal.base._Casts.uncheckedCast;
+import static org.apache.isis.core.commons.internal.reflection._Reflect.Filter.paramAssignableFrom;
+import static org.apache.isis.core.commons.internal.reflection._Reflect.Filter.paramAssignableFromValue;
+import static org.apache.isis.core.commons.internal.reflection._Reflect.Filter.paramCount;
+
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.util.Arrays;
@@ -38,17 +43,13 @@ import org.apache.isis.core.commons.internal.collections._Lists;
 import org.apache.isis.core.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.commons.internal.reflection._Reflect;
 import org.apache.isis.core.metamodel.facetapi.IdentifiedHolder;
+import org.apache.isis.core.metamodel.interactions.InteractionContext.Head;
 import org.apache.isis.core.metamodel.services.events.MetamodelEventService;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
 
-import static org.apache.isis.core.commons.internal.base._Casts.uncheckedCast;
-import static org.apache.isis.core.commons.internal.reflection._Reflect.Filter.paramAssignableFrom;
-import static org.apache.isis.core.commons.internal.reflection._Reflect.Filter.paramAssignableFromValue;
-import static org.apache.isis.core.commons.internal.reflection._Reflect.Filter.paramCount;
-
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
 import lombok.val;
@@ -72,13 +73,13 @@ public class DomainEventHelper {
             @NonNull final Class<? extends ActionDomainEvent<?>> eventType,
             final ObjectAction objectAction,
             final IdentifiedHolder identified,
-            final ManagedObject targetAdapter,
-            final ManagedObject mixedInAdapter,
+            final Head head,
             final Can<ManagedObject> argumentAdapters,
             final ManagedObject resultAdapter) {
         
-        return postEventForAction(phase, uncheckedCast(eventType), /*existingEvent*/null, objectAction, identified, 
-                targetAdapter, mixedInAdapter, argumentAdapters, resultAdapter);
+        return postEventForAction(phase, uncheckedCast(eventType), /*existingEvent*/null, 
+                objectAction, identified, 
+                head, argumentAdapters, resultAdapter);
     }
     
     // variant using existing event and not eventType (is derived from event)
@@ -87,14 +88,13 @@ public class DomainEventHelper {
             @NonNull final ActionDomainEvent<?> existingEvent,
             final ObjectAction objectAction,
             final IdentifiedHolder identified,
-            final ManagedObject targetAdapter,
-            final ManagedObject mixedInAdapter,
+            final Head head,
             final Can<ManagedObject> argumentAdapters,
             final ManagedObject resultAdapter) {
         
         return postEventForAction(phase, 
                 uncheckedCast(existingEvent.getClass()), existingEvent, objectAction, identified, 
-                targetAdapter, mixedInAdapter, argumentAdapters, resultAdapter);
+                head, argumentAdapters, resultAdapter);
     }
 
     private <S> ActionDomainEvent<S> postEventForAction(
@@ -103,8 +103,7 @@ public class DomainEventHelper {
             final ActionDomainEvent<S> existingEvent,
             final ObjectAction objectAction,
             final IdentifiedHolder identified,
-            final ManagedObject targetAdapter,
-            final ManagedObject mixedInAdapter,
+            final Head head,
             final Can<ManagedObject> argumentAdapters,
             final ManagedObject resultAdapter) {
         
@@ -118,15 +117,15 @@ public class DomainEventHelper {
                 event = existingEvent;
             } else {
                 // all other phases, create a new event
-                final S source = uncheckedCast(ManagedObject.unwrapSingle(targetAdapter));
+                final S source = uncheckedCast(ManagedObject.unwrapSingle(head.getTarget()));
                 final Object[] arguments = ManagedObject.unwrapMultipleAsArray(argumentAdapters);
                 final Identifier identifier = identified.getIdentifier();
                 event = newActionDomainEvent(eventType, identifier, source, arguments);
 
                 // copy over if have
-                if(mixedInAdapter != null ) {
-                    event.setMixedIn(mixedInAdapter.getPojo());
-                }
+                head.getMixedIn()
+                .ifPresent(mixedInAdapter->
+                    event.setMixedIn(mixedInAdapter.getPojo()));
 
                 if(objectAction != null) {
                     // should always be the case...
@@ -215,8 +214,7 @@ public class DomainEventHelper {
             final Class<? extends PropertyDomainEvent<S, T>> eventType,
                     final PropertyDomainEvent<S, T> existingEvent,
                     final IdentifiedHolder identified,
-                    final ManagedObject targetAdapter,
-                    final ManagedObject mixedInAdapter,
+                    final Head head,
                     final T oldValue,
                     final T newValue) {
         
@@ -224,7 +222,7 @@ public class DomainEventHelper {
 
         try {
             final PropertyDomainEvent<S, T> event;
-            final S source = uncheckedCast(ManagedObject.unwrapSingle(targetAdapter));
+            final S source = uncheckedCast(ManagedObject.unwrapSingle(head.getTarget()));
             final Identifier identifier = identified.getIdentifier();
 
             if(existingEvent != null && phase.isExecuted()) {
@@ -235,9 +233,9 @@ public class DomainEventHelper {
                 event = newPropertyDomainEvent(eventType, identifier, source, oldValue, newValue);
 
                 // copy over if have
-                if(mixedInAdapter != null ) {
-                    event.setMixedIn(mixedInAdapter.getPojo());
-                }
+                head.getMixedIn()
+                .ifPresent(mixedInAdapter->
+                    event.setMixedIn(mixedInAdapter.getPojo()));
 
             }
 
@@ -304,8 +302,7 @@ public class DomainEventHelper {
             final Class<? extends CollectionDomainEvent<S, T>> eventType,
                     final CollectionDomainEvent<S, T> existingEvent,
                     final IdentifiedHolder identified,
-                    final ManagedObject targetAdapter,
-                    final ManagedObject mixedInAdapter,
+                    final Head head,
                     final CollectionDomainEvent.Of of,
                     final T reference) {
         
@@ -318,14 +315,14 @@ public class DomainEventHelper {
                 event = existingEvent;
             } else {
                 // all other phases, create a new event
-                final S source = uncheckedCast(ManagedObject.unwrapSingle(targetAdapter));
+                final S source = uncheckedCast(ManagedObject.unwrapSingle(head.getTarget()));
                 final Identifier identifier = identified.getIdentifier();
                 event = newCollectionDomainEvent(eventType, phase, identifier, source, of, reference);
 
                 // copy over if have
-                if(mixedInAdapter != null ) {
-                    event.setMixedIn(mixedInAdapter.getPojo());
-                }
+                head.getMixedIn()
+                .ifPresent(mixedInAdapter->
+                    event.setMixedIn(mixedInAdapter.getPojo()));
             }
 
             event.setEventPhase(phase);
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionDomainEventFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionDomainEventFacetAbstract.java
index 65d6846..3f31059 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionDomainEventFacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionDomainEventFacetAbstract.java
@@ -77,7 +77,7 @@ implements ActionDomainEventFacet {
                         AbstractDomainEvent.Phase.HIDE,
                         getEventType(),
                         actionFrom(ic), getIdentified(),
-                        ic.getTarget(), ic.getMixedIn(), argumentAdaptersFrom(ic),
+                        ic.getHead(), argumentAdaptersFrom(ic),
                         null);
         if (event != null && event.isHidden()) {
             return "Hidden by subscriber";
@@ -93,7 +93,7 @@ implements ActionDomainEventFacet {
                         AbstractDomainEvent.Phase.DISABLE,
                         getEventType(),
                         actionFrom(ic), getIdentified(),
-                        ic.getTarget(), ic.getMixedIn(), argumentAdaptersFrom(ic),
+                        ic.getHead(), argumentAdaptersFrom(ic),
                         null);
         if (event != null && event.isDisabled()) {
             final TranslatableString reasonTranslatable = event.getDisabledReasonTranslatable();
@@ -118,7 +118,7 @@ implements ActionDomainEventFacet {
                         AbstractDomainEvent.Phase.VALIDATE,
                         getEventType(),
                         actionFrom(ic), getIdentified(),
-                        ic.getTarget(), ic.getMixedIn(), aic.getArgs(),
+                        ic.getHead(), aic.getArgs(),
                         null);
         if (event != null && event.isInvalid()) {
             final TranslatableString reasonTranslatable = event.getInvalidityReasonTranslatable();
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacet.java
index 8458c8e3..7653722 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacet.java
@@ -22,6 +22,7 @@ package org.apache.isis.core.metamodel.facets.actions.action.invocation;
 import org.apache.isis.core.commons.collections.Can;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.interactions.InteractionContext.Head;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
@@ -38,8 +39,7 @@ public interface ActionInvocationFacet extends Facet {
 
     ManagedObject invoke(
             ObjectAction owningAction,
-            ManagedObject targetAdapter,
-            ManagedObject mixedInAdapter,  // null for regular or contributed (not mixin) actions
+            Head head,
             Can<ManagedObject> argumentAdapters,
             InteractionInitiatedBy interactionInitiatedBy);
     
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 3b44d6d..b2b8cc0 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
@@ -61,6 +61,7 @@ import org.apache.isis.core.metamodel.facets.ImperativeFacet;
 import org.apache.isis.core.metamodel.facets.actions.publish.PublishedActionFacet;
 import org.apache.isis.core.metamodel.facets.actions.semantics.ActionSemanticsFacet;
 import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
+import org.apache.isis.core.metamodel.interactions.InteractionContext.Head;
 import org.apache.isis.core.metamodel.services.ixn.InteractionDtoServiceInternal;
 import org.apache.isis.core.metamodel.services.publishing.PublisherDispatchService;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
@@ -116,11 +117,13 @@ implements ImperativeFacet {
     @Override
     public ManagedObject invoke(
             final ObjectAction owningAction,
-            final ManagedObject targetAdapter,
-            final ManagedObject mixedInAdapter,
+            final Head head,
             final Can<ManagedObject> argumentAdapters,
             final InteractionInitiatedBy interactionInitiatedBy) {
 
+        val targetAdapter = head.getTarget();
+        val mixedInAdapter = head.getMixedIn().orElse(null);
+        
         final ManagedObject executionResult = 
                 getTransactionService().executeWithinTransaction(()->
                     doInvoke(owningAction, targetAdapter, mixedInAdapter, argumentAdapters, 
@@ -433,6 +436,8 @@ implements ImperativeFacet {
                 .asActionInvocationDto(owningAction, mixinElseRegularAdapter, argumentAdapters.toList());
                 
                 currentExecution.setDto(invocationDto);
+                
+                val head = Head.mixedIn(targetAdapter, mixedInAdapter);
 
 
                 // set the startedAt (and update command if this is the top-most member execution)
@@ -449,7 +454,7 @@ implements ImperativeFacet {
                         AbstractDomainEvent.Phase.EXECUTING,
                         getEventType(),
                         owningAction, owningAction,
-                        targetAdapter, mixedInAdapter, argumentAdapters,
+                        head, argumentAdapters,
                         null);
 
                 // set event onto the execution
@@ -465,7 +470,7 @@ implements ImperativeFacet {
                 domainEventHelper.postEventForAction(
                         AbstractDomainEvent.Phase.EXECUTED,
                         actionDomainEvent,
-                        owningAction, owningAction, targetAdapter, mixedInAdapter, argumentAdapters,
+                        owningAction, owningAction, head, argumentAdapters,
                         resultAdapterPossiblyCloned);
 
                 final Object returnValue = actionDomainEvent.getReturnValue();
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/collection/modify/CollectionAddToFacetForDomainEventFromAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/collection/modify/CollectionAddToFacetForDomainEventFromAbstract.java
index 31e8d4b..e013fce 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/collection/modify/CollectionAddToFacetForDomainEventFromAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/collection/modify/CollectionAddToFacetForDomainEventFromAbstract.java
@@ -32,6 +32,7 @@ import org.apache.isis.core.metamodel.facets.DomainEventHelper;
 import org.apache.isis.core.metamodel.facets.SingleValueFacetAbstract;
 import org.apache.isis.core.metamodel.facets.collections.modify.CollectionAddToFacet;
 import org.apache.isis.core.metamodel.facets.propcoll.accessor.PropertyOrCollectionAccessorFacet;
+import org.apache.isis.core.metamodel.interactions.InteractionContext.Head;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 
 import static org.apache.isis.core.commons.internal.base._Casts.uncheckedCast;
@@ -66,7 +67,8 @@ implements CollectionAddToFacet {
     @Override
     public void add(
             final ManagedObject targetAdapter,
-            final ManagedObject referencedObjectAdapter, final InteractionInitiatedBy interactionInitiatedBy) {
+            final ManagedObject referencedObjectAdapter, 
+            final InteractionInitiatedBy interactionInitiatedBy) {
         if (this.collectionAddToFacet == null) {
             return;
         }
@@ -84,10 +86,10 @@ implements CollectionAddToFacet {
             }
         }
 
-
+        final Head head = Head.simple(targetAdapter);
+        
         // either doesn't contain object, or doesn't have set semantics, so
         // execute the add wrapped between the executing and executed events ...
-        final ManagedObject mixedInAdapter = null;
 
         // ... post the executing event
 
@@ -95,7 +97,7 @@ implements CollectionAddToFacet {
                 domainEventHelper.postEventForCollection(
                         AbstractDomainEvent.Phase.EXECUTING,
                         getEventType(), null,
-                        getIdentified(), targetAdapter, mixedInAdapter,
+                        getIdentified(), head,
                         CollectionDomainEvent.Of.ADD_TO,
                         referencedObject);
 
@@ -106,7 +108,7 @@ implements CollectionAddToFacet {
         domainEventHelper.postEventForCollection(
                 AbstractDomainEvent.Phase.EXECUTED,
                 getEventType(), uncheckedCast(event),
-                getIdentified(), targetAdapter, mixedInAdapter,
+                getIdentified(), head,
                 CollectionDomainEvent.Of.ADD_TO,
                 referencedObject);
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/collection/modify/CollectionDomainEventFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/collection/modify/CollectionDomainEventFacetAbstract.java
index ff259b0..37bb38d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/collection/modify/CollectionDomainEventFacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/collection/modify/CollectionDomainEventFacetAbstract.java
@@ -76,7 +76,7 @@ public abstract class CollectionDomainEventFacetAbstract extends SingleClassValu
                 domainEventHelper.postEventForCollection(
                         AbstractDomainEvent.Phase.HIDE,
                         getEventType(), null,
-                        getIdentified(), ic.getTarget(), ic.getMixedIn(),
+                        getIdentified(), ic.getHead(),
                         CollectionDomainEvent.Of.ACCESS,
                         null);
         if (event != null && event.isHidden()) {
@@ -92,7 +92,7 @@ public abstract class CollectionDomainEventFacetAbstract extends SingleClassValu
                 domainEventHelper.postEventForCollection(
                         AbstractDomainEvent.Phase.DISABLE,
                         getEventType(), null,
-                        getIdentified(), ic.getTarget(), ic.getMixedIn(),
+                        getIdentified(), ic.getHead(),
                         CollectionDomainEvent.Of.ACCESS,
                         null);
         if (event != null && event.isDisabled()) {
@@ -124,7 +124,7 @@ public abstract class CollectionDomainEventFacetAbstract extends SingleClassValu
                 domainEventHelper.postEventForCollection(
                         AbstractDomainEvent.Phase.VALIDATE,
                         getEventType(), null,
-                        getIdentified(), ic.getTarget(), ic.getMixedIn(),
+                        getIdentified(), ic.getHead(),
                         of,
                         proposed);
         if (event != null && event.isInvalid()) {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/collection/modify/CollectionRemoveFromFacetForDomainEventFromAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/collection/modify/CollectionRemoveFromFacetForDomainEventFromAbstract.java
index edd1404..47c1741 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/collection/modify/CollectionRemoveFromFacetForDomainEventFromAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/collections/collection/modify/CollectionRemoveFromFacetForDomainEventFromAbstract.java
@@ -19,6 +19,8 @@
 
 package org.apache.isis.core.metamodel.facets.collections.collection.modify;
 
+import static org.apache.isis.core.commons.internal.base._Casts.uncheckedCast;
+
 import java.util.Collection;
 import java.util.Map;
 
@@ -33,10 +35,9 @@ import org.apache.isis.core.metamodel.facets.DomainEventHelper;
 import org.apache.isis.core.metamodel.facets.SingleValueFacetAbstract;
 import org.apache.isis.core.metamodel.facets.collections.modify.CollectionRemoveFromFacet;
 import org.apache.isis.core.metamodel.facets.propcoll.accessor.PropertyOrCollectionAccessorFacet;
+import org.apache.isis.core.metamodel.interactions.InteractionContext.Head;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 
-import static org.apache.isis.core.commons.internal.base._Casts.uncheckedCast;
-
 
 public abstract class CollectionRemoveFromFacetForDomainEventFromAbstract
 extends SingleValueFacetAbstract<Class<? extends CollectionDomainEvent<?,?>>>
@@ -86,16 +87,17 @@ implements CollectionRemoveFromFacet {
             return;
         }
 
+        final Head head = Head.simple(targetAdapter);
+        
         // contains the element, so
         // execute the remove wrapped between the executing and executed events ...
-        final ManagedObject mixedInAdapter = null;
 
         // ... post the executing event
         final CollectionDomainEvent<?, ?> event =
                 domainEventHelper.postEventForCollection(
                         AbstractDomainEvent.Phase.EXECUTING,
                         getEventType(), null,
-                        getIdentified(), targetAdapter, mixedInAdapter,
+                        getIdentified(), head,
                         CollectionDomainEvent.Of.REMOVE_FROM,
                         referencedObject);
 
@@ -106,7 +108,7 @@ implements CollectionRemoveFromFacet {
         domainEventHelper.postEventForCollection(
                 AbstractDomainEvent.Phase.EXECUTED,
                 getEventType(), uncheckedCast(event),
-                getIdentified(), targetAdapter, mixedInAdapter,
+                getIdentified(), head,
                 CollectionDomainEvent.Of.REMOVE_FROM,
                 referencedObject);
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetAbstract.java
index 081d62f..606b64a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetAbstract.java
@@ -24,6 +24,7 @@ import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.Map;
 
+import org.apache.isis.core.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.commons.internal.reflection._Reflect;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
@@ -67,28 +68,24 @@ implements MixinFacet {
     @Override
     public Object instantiate(final Object domainPojo) {
         if(constructor == null) {
-            return null; // invalid mix-in declaration; ought we to fail-fast?
+            throw _Exceptions.unrecoverableFormatted(
+                    "invalid mix-in declaration of type %s, missing contructor", mixinType);
         }
         if(domainPojo == null) {
             return null;
         }
         if(!isMixinFor(domainPojo.getClass())) {
-            // shouldn't happen; ought we to fail-fast instead?
-            return null;
+            throw _Exceptions.unrecoverableFormatted(
+                    "invalid mix-in declaration of type %s, unexpect owner type %s", 
+                    mixinType, domainPojo.getClass());
         }
         try {
             val mixinPojo = constructor.newInstance(domainPojo);
             getServiceInjector().injectServicesInto(mixinPojo);
             return mixinPojo;
-        } catch (InvocationTargetException e) {
-            // shouldn't happen; ought we to fail-fast instead?
-            return null;
-        } catch (InstantiationException e) {
-            // shouldn't happen; ought we to fail-fast instead?
-            return null;
-        } catch (IllegalAccessException e) {
-            // shouldn't happen; ought we to fail-fast instead?
-            return null;
+        } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) {
+            throw _Exceptions.unrecoverableFormatted(
+                    "invalid mix-in declaration of type %s, failing instance construction with %s", mixinType, e);
         }
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/parseable/parser/ParseableFacetUsingParser.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/parseable/parser/ParseableFacetUsingParser.java
index 1516f30..c4a3598 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/parseable/parser/ParseableFacetUsingParser.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/parseable/parser/ParseableFacetUsingParser.java
@@ -73,7 +73,9 @@ implements ParseableFacet {
 
         // check string is valid
         // (eg pick up any @RegEx on value type)
-        if (getFacetHolder().containsFacet(ValueFacet.class)) {
+        if (contextAdapter!=null 
+                && getFacetHolder().containsFacet(ValueFacet.class)) {
+            
             val entryAdapter = getObjectManager().adapt(entry);
             final Identifier identifier = getIdentified().getIdentifier();
             final ParseValueContext parseValueContext =
@@ -99,8 +101,7 @@ implements ParseableFacet {
             final ObjectSpecification specification = adapter.getSpecification();
             final ObjectValidityContext validateContext =
                     specification.createValidityInteractionContext(
-                            adapter, interactionInitiatedBy
-                            );
+                            adapter, interactionInitiatedBy);
             validate(validateContext);
 
             return adapter;
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyDomainEventFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyDomainEventFacetAbstract.java
index f3e47b1..665c9db 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyDomainEventFacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertyDomainEventFacetAbstract.java
@@ -93,7 +93,7 @@ extends SingleClassValueFacetAbstract implements PropertyDomainEventFacet {
                 domainEventHelper.postEventForProperty(
                         AbstractDomainEvent.Phase.HIDE,
                         getEventType(), null,
-                        getIdentified(), ic.getTarget(), ic.getMixedIn(),
+                        getIdentified(), ic.getHead(),
                         null, null);
         if (event != null && event.isHidden()) {
             return "Hidden by subscriber";
@@ -108,7 +108,7 @@ extends SingleClassValueFacetAbstract implements PropertyDomainEventFacet {
                 domainEventHelper.postEventForProperty(
                         AbstractDomainEvent.Phase.DISABLE,
                         getEventType(), null,
-                        getIdentified(), ic.getTarget(), ic.getMixedIn(),
+                        getIdentified(), ic.getHead(),
                         null, null);
         if (event != null && event.isDisabled()) {
             final TranslatableString reasonTranslatable = event.getDisabledReasonTranslatable();
@@ -141,7 +141,7 @@ extends SingleClassValueFacetAbstract implements PropertyDomainEventFacet {
                 domainEventHelper.postEventForProperty(
                         AbstractDomainEvent.Phase.VALIDATE,
                         getEventType(), null,
-                        getIdentified(), ic.getTarget(), ic.getMixedIn(),
+                        getIdentified(), ic.getHead(),
                         oldValue, proposedValue);
         if (event != null && event.isInvalid()) {
             final TranslatableString reasonTranslatable = event.getInvalidityReasonTranslatable();
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
index 845ac93..cea72e1 100644
--- 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
@@ -19,6 +19,8 @@
 
 package org.apache.isis.core.metamodel.facets.properties.property.modify;
 
+import static org.apache.isis.core.commons.internal.base._Casts.uncheckedCast;
+
 import java.util.Map;
 import java.util.Objects;
 
@@ -42,14 +44,13 @@ import org.apache.isis.core.metamodel.facets.propcoll.accessor.PropertyOrCollect
 import org.apache.isis.core.metamodel.facets.properties.publish.PublishedPropertyFacet;
 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.interactions.InteractionContext.Head;
 import org.apache.isis.core.metamodel.services.ixn.InteractionDtoServiceInternal;
 import org.apache.isis.core.metamodel.services.publishing.PublisherDispatchService;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
 import org.apache.isis.schema.ixn.v2.PropertyEditDto;
 
-import static org.apache.isis.core.commons.internal.base._Casts.uncheckedCast;
-
 import lombok.val;
 
 public abstract class PropertySetterOrClearFacetForDomainEventAbstract
@@ -132,7 +133,7 @@ extends SingleValueFacetAbstract<Class<? extends PropertyDomainEvent<?,?>>> {
             final InteractionInitiatedBy interactionInitiatedBy) {
 
         setOrClearProperty(Style.CLEAR,
-                owningProperty, targetAdapter, /*mixedInAdapter*/ null, interactionInitiatedBy);
+                owningProperty, targetAdapter, /*newValueAdapter*/ null, interactionInitiatedBy);
 
     }
 
@@ -154,10 +155,8 @@ extends SingleValueFacetAbstract<Class<? extends PropertyDomainEvent<?,?>>> {
             final ManagedObject newValueAdapter,
             final InteractionInitiatedBy interactionInitiatedBy) {
 
-        final ManagedObject mixedInAdapter = null;
-
         getTransactionService().executeWithinTransaction(()->{
-            doSetOrClearProperty(style, owningProperty, targetAdapter, mixedInAdapter, newValueAdapter, interactionInitiatedBy);
+            doSetOrClearProperty(style, owningProperty, Head.simple(targetAdapter), newValueAdapter, interactionInitiatedBy);
         });
 
     }
@@ -165,8 +164,7 @@ extends SingleValueFacetAbstract<Class<? extends PropertyDomainEvent<?,?>>> {
     private void doSetOrClearProperty(
             final Style style,
             final OneToOneAssociation owningProperty,
-            final ManagedObject targetAdapter,
-            final ManagedObject mixedInAdapter,
+            final Head head,
             final ManagedObject newValueAdapter,
             final InteractionInitiatedBy interactionInitiatedBy) {
 
@@ -202,6 +200,7 @@ extends SingleValueFacetAbstract<Class<? extends PropertyDomainEvent<?,?>>> {
 
         } else {
 
+            val targetAdapter = head.getTarget();
             final Object target = ManagedObject.unwrapSingle(targetAdapter);
             final Object argValue = ManagedObject.unwrapSingle(newValueAdapter);
 
@@ -240,7 +239,7 @@ extends SingleValueFacetAbstract<Class<? extends PropertyDomainEvent<?,?>>> {
                                 domainEventHelper.postEventForProperty(
                                         AbstractDomainEvent.Phase.EXECUTING,
                                         getEventType(), null,
-                                        getIdentified(), targetAdapter, mixedInAdapter,
+                                        getIdentified(), head,
                                         oldValue, newValue);
 
                         // set event onto the execution
@@ -260,7 +259,7 @@ extends SingleValueFacetAbstract<Class<? extends PropertyDomainEvent<?,?>>> {
                             domainEventHelper.postEventForProperty(
                                     AbstractDomainEvent.Phase.EXECUTED,
                                     getEventType(), uncheckedCast(event),
-                                    getIdentified(), targetAdapter, mixedInAdapter,
+                                    getIdentified(), head,
                                     oldValue, actualNewValue);
                         }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/InteractionContext.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/InteractionContext.java
index 977ab0b..1255054 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/InteractionContext.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/InteractionContext.java
@@ -20,10 +20,14 @@
 package org.apache.isis.core.metamodel.interactions;
 
 import java.util.Objects;
+import java.util.Optional;
+
+import javax.annotation.Nullable;
 
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.applib.services.wrapper.events.InteractionEvent;
+import org.apache.isis.core.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.metamodel.consent.InteractionContextType;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.Facet;
@@ -66,7 +70,7 @@ public abstract class InteractionContext {
      * Model that holds the objects involved with the interaction.
      * @since 2.0
      */
-    @Value(staticConstructor = "of")
+    @Value(staticConstructor = "of2")
     public static class Head {
         /**
          * The owning object that this interaction is associated with.
@@ -78,10 +82,43 @@ public abstract class InteractionContext {
          */
         @NonNull private final ManagedObject target;
         
+        /** in support of legacy code */
+        public static Head of(@NonNull ManagedObject owner, @NonNull ManagedObject target) {
+            if(ManagedObject.isSpecified(owner) 
+                    && owner.getSpecification().getBeanSort().isMixin()
+                    && owner.getPojo()==null) {
+                throw _Exceptions.unrecoverableFormatted("owner not spec. %s", owner);
+            }
+            if(ManagedObject.isSpecified(target)                    
+                    && target.getSpecification().getBeanSort().isMixin()
+                    && target.getPojo()==null) {
+                throw _Exceptions.unrecoverableFormatted("target not spec. %s", target);
+            }
+            return of2(owner, target);
+        }
+        
         /** when owner equals target (no mixin) */
         public static Head simple(ManagedObject owner) {
             return Head.of(owner, owner);
         }
+        
+        /** 
+         * as used by the domain event subsystem
+         * @return optionally the owner, if the target is a mixin 
+         */
+        public Optional<ManagedObject> getMixedIn() {
+            return Objects.equals(getOwner(), getTarget()) 
+                    ? Optional.empty()
+                    : Optional.of(getOwner());
+        }
+
+        /** in support of legacy code */
+        public static Head mixedIn(@NonNull ManagedObject target, @Nullable ManagedObject mixedIn) {
+            return mixedIn==null
+                    ? of(target, target)
+                    : of(mixedIn, target);
+        }
+        
     }
     
     /**
@@ -121,17 +158,10 @@ public abstract class InteractionContext {
     @Getter private final Head head;
     
     /**
-     * The target object that this interaction is associated with.
-     */
-    @Getter private final ManagedObject target;
-
-    /**
      * Where the element is to be rendered.
      */
     @Getter private final Where where;
     
-    @Getter private final ManagedObject mixedIn; // for mixin members only, obviously
-
     protected InteractionContext(
             final InteractionContextType interactionType,
             final InteractionInitiatedBy invocationMethod,
@@ -143,12 +173,16 @@ public abstract class InteractionContext {
         this.identifier = identifier;
         this.head = head;
         this.where = where;
-        
-        this.target = head.getTarget();
-        this.mixedIn = Objects.equals(head.getOwner(), head.getTarget()) ? null : head.getOwner();
     }
 
+    /**
+     * The target object that this interaction is associated with.
+     */
+    public ManagedObject getTarget() {
+        return head.getTarget();
+    }
 
+    
     /**
      * Convenience method that indicates whether the
      * {@link #getInitiatedBy() interaction was invoked} by the framework.
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
index c7a70e1..6c79feb 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
@@ -17,6 +17,8 @@
 
 package org.apache.isis.core.metamodel.spec.feature;
 
+import static org.apache.isis.core.commons.internal.base._NullSafe.stream;
+
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
@@ -50,6 +52,7 @@ import org.apache.isis.core.metamodel.facets.members.cssclassfa.CssClassFaFacet;
 import org.apache.isis.core.metamodel.facets.members.order.MemberOrderFacet;
 import org.apache.isis.core.metamodel.facets.object.promptStyle.PromptStyleFacet;
 import org.apache.isis.core.metamodel.facets.object.wizard.WizardFacet;
+import org.apache.isis.core.metamodel.interactions.InteractionContext.Head;
 import org.apache.isis.core.metamodel.layout.memberorderfacet.MemberOrderFacetComparator;
 import org.apache.isis.core.metamodel.spec.ActionType;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
@@ -57,8 +60,6 @@ import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.specimpl.MixedInMember;
 import org.apache.isis.core.metamodel.specloader.specimpl.PendingParameterModelHead;
 
-import static org.apache.isis.core.commons.internal.base._NullSafe.stream;
-
 import lombok.NonNull;
 import lombok.val;
 
@@ -108,8 +109,7 @@ public interface ObjectAction extends ObjectMember {
      * @param mixedInAdapter - will be null for regular actions, and for mixin actions.  When a mixin action invokes its underlying mixedIn action, then will be populated (so that the ActionDomainEvent can correctly provide the underlying mixin)
      */
     ManagedObject executeWithRuleChecking(
-            ManagedObject target,
-            ManagedObject mixedInAdapter,
+            Head head,
             Can<ManagedObject> parameters,
             InteractionInitiatedBy interactionInitiatedBy,
             Where where) throws AuthorizationException;
@@ -123,8 +123,7 @@ public interface ObjectAction extends ObjectMember {
      * (so that the ActionDomainEvent can correctly provide the underlying mixin)
      */
     ManagedObject execute(
-            ManagedObject targetAdapter,
-            ManagedObject mixedInAdapter,
+            Head head,
             Can<ManagedObject> parameters,
             InteractionInitiatedBy interactionInitiatedBy);
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/interaction/ManagedAction.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/interaction/ManagedAction.java
index 6389ee0..cfb0da0 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/interaction/ManagedAction.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/interaction/ManagedAction.java
@@ -23,6 +23,7 @@ import java.util.Optional;
 import org.apache.isis.core.commons.collections.Can;
 import org.apache.isis.core.commons.internal.base._Either;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
+import org.apache.isis.core.metamodel.interactions.InteractionContext.Head;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 
@@ -76,9 +77,8 @@ public final class ManagedAction extends ManagedMember {
             
         //TODO validate params, and handle invocation exceptions
         
-        final ManagedObject mixedInAdapter = null; // filled in automatically ?
         val actionResult = getAction()
-                .execute(getOwner(), mixedInAdapter , actionParameters, InteractionInitiatedBy.USER);
+                .execute(Head.simple(getOwner()) , actionParameters, InteractionInitiatedBy.USER);
         
         return _Either.left(actionResult);
         
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionDefault.java
index fe7c9d1..c592bc5 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionDefault.java
@@ -388,12 +388,13 @@ public class ObjectActionDefault extends ObjectMemberAbstract implements ObjectA
 
     @Override
     public ManagedObject executeWithRuleChecking(
-            final ManagedObject target,
-            final ManagedObject mixedInAdapter,
+            final Head head,
             final Can<ManagedObject> arguments,
             final InteractionInitiatedBy interactionInitiatedBy,
             final Where where) {
 
+        val target = head.getOwner();
+        
         // see it?
         final Consent visibility = isVisible(target, interactionInitiatedBy, where);
         if (visibility.isVetoed()) {
@@ -412,7 +413,7 @@ public class ObjectActionDefault extends ObjectMemberAbstract implements ObjectA
             throw new RecoverableException(validity.getReason());
         }
 
-        return execute(target, mixedInAdapter, arguments, interactionInitiatedBy);
+        return execute(head, arguments, interactionInitiatedBy);
     }
 
     /**
@@ -420,41 +421,38 @@ public class ObjectActionDefault extends ObjectMemberAbstract implements ObjectA
      * {@link #executeInternal(ManagedObject, ManagedObject, List, InteractionInitiatedBy) executeInternal}
      * to invoke the {@link ActionInvocationFacet invocation facet}.
      *
-     * @param mixedInAdapter - will be null for regular actions, and for mixin actions.  When a mixin action invokes its underlying mixedIn action, then will be populated (so that the ActionDomainEvent can correctly provide the underlying mixin)
+     * @param mixedInAdapter - will be null for regular actions, and for mixin actions.  
+     * When a mixin action invokes its underlying mixedIn action, then will be populated 
+     * (so that the ActionDomainEvent can correctly provide the underlying mixin)
      */
     @Override
     public ManagedObject execute(
-            final ManagedObject targetAdapter,
-            final ManagedObject mixedInAdapter,
+            final Head head,
             final Can<ManagedObject> argumentAdapters,
             final InteractionInitiatedBy interactionInitiatedBy) {
 
-        setupCommand(targetAdapter, argumentAdapters);
-
-        return this.executeInternal(targetAdapter, mixedInAdapter, argumentAdapters, interactionInitiatedBy);
+        setupCommand(head.getTarget(), argumentAdapters);
+        
+        return this.executeInternal(head, argumentAdapters, interactionInitiatedBy);
     }
 
     /**
-     * private API, called by mixins and contributees.
+     * private API, called by mixins
      */
-    public ManagedObject executeInternal(
-            final ManagedObject targetAdapter,
-            final ManagedObject mixedInAdapter,
+    protected ManagedObject executeInternal(
+            final Head head,
             final Can<ManagedObject> argumentAdapters,
             final InteractionInitiatedBy interactionInitiatedBy) {
         
         val actionInvocationFacet = getFacet(ActionInvocationFacet.class);
         return actionInvocationFacet
-                .invoke(this, targetAdapter, mixedInAdapter, argumentAdapters, interactionInitiatedBy);
+                .invoke(this, head, argumentAdapters, interactionInitiatedBy);
     }
 
     protected ActionInvocationFacet getActionInvocationFacet() {
         return getFacetedMethod().getFacet(ActionInvocationFacet.class);
     }
 
-
-
-
     // -- defaults
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
index 25ba9d1..da2ca53 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
@@ -22,21 +22,17 @@ import java.util.List;
 
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.core.commons.collections.Can;
+import org.apache.isis.core.commons.internal.assertions._Assert;
 import org.apache.isis.core.commons.internal.base._Strings;
-import org.apache.isis.core.commons.internal.collections._Lists;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facetapi.FacetHolderImpl;
 import org.apache.isis.core.metamodel.facetapi.FacetUtil;
-import org.apache.isis.core.metamodel.facetapi.FeatureType;
-import org.apache.isis.core.metamodel.facets.FacetedMethodParameter;
-import org.apache.isis.core.metamodel.facets.TypedHolder;
 import org.apache.isis.core.metamodel.facets.all.named.NamedFacetInferred;
 import org.apache.isis.core.metamodel.interactions.InteractionContext.Head;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
-import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
 
 import lombok.Getter;
 import lombok.NonNull;
@@ -65,11 +61,6 @@ public class ObjectActionMixedIn extends ObjectActionDefault implements MixedInM
     @Getter(onMethod = @__(@Override))
     private final FacetHolder facetHolder = new FacetHolderImpl();
 
-    /**
-     * Lazily initialized by {@link #getParameters()} (so don't use directly!)
-     */
-    private Can<ObjectActionParameter> parameters;
-
     private final Identifier identifier;
 
     public ObjectActionMixedIn(
@@ -102,9 +93,9 @@ public class ObjectActionMixedIn extends ObjectActionDefault implements MixedInM
     }
 
     @Override
-    protected Head headFor(final ManagedObject mixedInAdapter) {
-        val mixinAdapter = mixinAdapterFor(mixinType, mixedInAdapter);
-        return Head.of(mixedInAdapter, mixinAdapter);
+    protected Head headFor(final ManagedObject owner) {
+        val target = mixinAdapterFor(mixinType, owner);
+        return Head.of(owner, target);
     }
     
     @Override
@@ -140,36 +131,6 @@ public class ObjectActionMixedIn extends ObjectActionDefault implements MixedInM
     public PendingParameterModelHead newPendingParameterModelHead(@NonNull ManagedObject actionOwner) {
         return PendingParameterModelHead.of(this, actionOwner, mixinAdapterFor(actionOwner));
     }
-//    
-//    @Override
-//    protected synchronized Can<ObjectActionParameter> determineParameters() {
-//        if (parameters != null) {
-//            // because possible race condition (caller isn't synchronized)
-//            return parameters;
-//        }
-//        val mixinActionParameters = mixinAction.getParameters();
-//        final List<FacetedMethodParameter> paramPeers = getFacetedMethod().getParameters();
-//
-//        final List<ObjectActionParameter> mixedInParameters = _Lists.newArrayList();
-//
-//        for(int paramIndex = 0; paramIndex < mixinActionParameters.size(); paramIndex++) {
-//
-//            val mixinParameter =
-//                    (ObjectActionParameterAbstract) mixinActionParameters.getElseFail(paramIndex);
-//
-//            final TypedHolder paramPeer = paramPeers.get(paramIndex);
-//            getSpecificationLoader().loadSpecification(paramPeer.getType());
-//
-//            final ObjectActionParameterMixedIn mixedInParameter =
-//                    mixinParameter.getPeer().getFeatureType() == FeatureType.ACTION_PARAMETER_SCALAR
-//                    ? new OneToOneActionParameterMixedIn(mixinParameter, this)
-//                    : new OneToManyActionParameterMixedIn(mixinParameter, this);
-//            mixedInParameters.add(mixedInParameter);
-//        }
-//        return Can.ofCollection(mixedInParameters);
-//    }
-//    
-
 
     @Override
     public Can<ManagedObject> getDefaults(final ManagedObject mixedInAdapter) {
@@ -191,19 +152,17 @@ public class ObjectActionMixedIn extends ObjectActionDefault implements MixedInM
 
     @Override
     public ManagedObject execute(
-            final ManagedObject target,         // will be the mixedInAdapter
-            final ManagedObject mixedInAdapter, // will be passed in as null
+            final Head head,
             final Can<ManagedObject> arguments,
             final InteractionInitiatedBy interactionInitiatedBy) {
 
-
-        final ManagedObject targetAdapter = mixinAdapterFor(mixinType, target);
-        final ManagedObject actualMixedInAdapter = target;
-
-        setupCommand(actualMixedInAdapter, arguments);
-
+        final ManagedObject owner = head.getOwner();
+        final ManagedObject target = mixinAdapterFor(mixinType, owner);
+        _Assert.assertEquals(target.getSpecification(), head.getTarget().getSpecification());
+        
+        setupCommand(head.getTarget(), arguments);
         return mixinAction.executeInternal(
-                targetAdapter, actualMixedInAdapter, arguments,
+                head, arguments,
                 interactionInitiatedBy);
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java
index 38b6ea1..55ee3db 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java
@@ -56,6 +56,7 @@ import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
 import org.apache.isis.schema.cmd.v2.CommandDto;
 
+import lombok.NonNull;
 import lombok.val;
 
 public abstract class ObjectMemberAbstract 
@@ -244,13 +245,13 @@ implements ObjectMember, MetaModelContext.Delegating, FacetHolder.Delegating {
      * For mixins
      */
     ManagedObject mixinAdapterFor(
-            final Class<?> mixinType,
-            final ManagedObject mixedInAdapter) {
+            @NonNull final Class<?> mixinType,
+            @NonNull final ManagedObject mixedInAdapter) {
         
         val spec = getSpecificationLoader().loadSpecification(mixinType);
         val mixinFacet = spec.getFacet(MixinFacet.class);
-        val mixinPojo = mixinFacet.instantiate(mixedInAdapter.getPojo());
-        return ManagedObject.of(spec, mixinPojo);
+        val mixinPojo = mixinFacet.instantiate(Objects.requireNonNull(mixedInAdapter.getPojo()));
+        return ManagedObject.of(spec, Objects.requireNonNull(mixinPojo));
     }
 
     static String determineNameFrom(final ObjectAction mixinAction) {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java
index 909f37e..8e7cfbc 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java
@@ -150,13 +150,12 @@ public class OneToManyAssociationMixedIn extends OneToManyAssociationDefault imp
 
     @Override
     public ManagedObject get(
-            final ManagedObject mixedInAdapter,
+            final ManagedObject ownerAdapter,
             final InteractionInitiatedBy interactionInitiatedBy) {
         
-        final ManagedObject mixinAdapter = mixinAdapterFor(mixinType, mixedInAdapter);
         return getPublishingServiceInternal().withPublishingSuppressed(
                 () -> mixinAction.executeInternal(
-                        mixinAdapter, mixedInAdapter, Can.empty(), interactionInitiatedBy));
+                        headFor(ownerAdapter), Can.empty(), interactionInitiatedBy));
     }
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java
index 7607079..af0f350 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java
@@ -23,6 +23,7 @@ import java.util.List;
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.core.commons.collections.Can;
+import org.apache.isis.core.commons.internal.assertions._Assert;
 import org.apache.isis.core.commons.internal.base._Strings;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
@@ -137,11 +138,14 @@ public class OneToOneAssociationMixedIn extends OneToOneAssociationDefault imple
             final ManagedObject mixedInAdapter,
             final InteractionInitiatedBy interactionInitiatedBy) {
 
+        val head = headFor(mixedInAdapter);
+        
         val mixinAdapter = mixinAdapterFor(mixinType, mixedInAdapter);
+        _Assert.assertEquals(mixedInAdapter, head.getMixedIn().orElse(null));
+        
 
         return getPublisherDispatchService().withPublishingSuppressed(
-                () -> mixinAction.executeInternal(
-                        mixinAdapter, mixedInAdapter, Can.empty(), interactionInitiatedBy)
+                () -> mixinAction.executeInternal(head, Can.empty(), interactionInitiatedBy)
         );
     }
 
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java
index 926ad19..c744d24 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java
@@ -54,6 +54,7 @@ import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facets.actions.action.invocation.CommandUtil;
+import org.apache.isis.core.metamodel.interactions.InteractionContext.Head;
 import org.apache.isis.core.metamodel.objectmanager.load.ObjectLoader;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
@@ -189,8 +190,8 @@ public class CommandExecutorServiceDefault implements CommandExecutorService {
                 // it will switch the targetAdapter to be the mixedInAdapter transparently
                 val argAdapters = argAdaptersFor(actionDto);
 
-                val resultAdapter = objectAction.execute(
-                        targetAdapter, null, argAdapters, InteractionInitiatedBy.FRAMEWORK);
+                val resultAdapter = objectAction.execute(Head.simple(targetAdapter)
+                        , argAdapters, InteractionInitiatedBy.FRAMEWORK);
 
                 // flush any Isis PersistenceCommands pending
                 // (else might get transient objects for the return value)
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/DomainObjectInvocationHandler.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/DomainObjectInvocationHandler.java
index 907ddb2..c451d1f 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/DomainObjectInvocationHandler.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/DomainObjectInvocationHandler.java
@@ -51,6 +51,7 @@ import org.apache.isis.core.metamodel.facets.ImperativeFacet;
 import org.apache.isis.core.metamodel.facets.ImperativeFacet.Intent;
 import org.apache.isis.core.metamodel.facets.object.entity.EntityFacet;
 import org.apache.isis.core.metamodel.facets.object.mixin.MixinFacet;
+import org.apache.isis.core.metamodel.interactions.InteractionContext.Head;
 import org.apache.isis.core.metamodel.objectmanager.ObjectManager;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
@@ -643,11 +644,12 @@ public class DomainObjectInvocationHandler<T> extends DelegatingInvocationHandle
         });
         
         return runExecutionTask(()->{
-
             val interactionInitiatedBy = getInteractionInitiatedBy();
-            val mixedInAdapter = (ManagedObject)null; // if a mixin action, then it will automatically fill in.
+            val head2 = objectAction.newPendingParameterModelHead(targetAdapter);
+            val head = Head.of(head2.getActionOwner(), head2.getActionTarget()); 
+            
             val returnedAdapter = objectAction.execute(
-                    targetAdapter, mixedInAdapter, argAdapters,
+                    head, argAdapters,
                     interactionInitiatedBy);
             return ManagedObject.unwrapSingle(returnedAdapter);
             
diff --git a/extensions/security/secman/persistence-jdo/src/main/java/org/apache/isis/extensions/secman/jdo/dom/user/ApplicationUserRepository.java b/extensions/security/secman/persistence-jdo/src/main/java/org/apache/isis/extensions/secman/jdo/dom/user/ApplicationUserRepository.java
index 500d6f0..abce573 100644
--- a/extensions/security/secman/persistence-jdo/src/main/java/org/apache/isis/extensions/secman/jdo/dom/user/ApplicationUserRepository.java
+++ b/extensions/security/secman/persistence-jdo/src/main/java/org/apache/isis/extensions/secman/jdo/dom/user/ApplicationUserRepository.java
@@ -33,6 +33,7 @@ import org.apache.isis.applib.services.factory.FactoryService;
 import org.apache.isis.applib.services.queryresultscache.QueryResultsCache;
 import org.apache.isis.applib.services.repository.RepositoryService;
 import org.apache.isis.core.commons.internal.base._Casts;
+import org.apache.isis.core.commons.internal.base._NullSafe;
 import org.apache.isis.core.commons.internal.collections._Sets;
 import org.apache.isis.core.commons.internal.exceptions._Exceptions;
 import org.apache.isis.extensions.secman.api.SecurityModuleConfig;
@@ -137,8 +138,7 @@ implements org.apache.isis.extensions.secman.api.user.ApplicationUserRepository<
             org.apache.isis.extensions.secman.api.role.ApplicationRole genericRole) {
         
         val role = _Casts.<ApplicationRole>uncheckedCast(genericRole);
-        return role.getUsers()
-                .stream()
+        return _NullSafe.stream(role.getUsers())
                 .collect(_Sets.toUnmodifiableSorted());
     }
     
diff --git a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/pages/main/MainView.java b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/pages/main/MainView.java
index dd83715..2a09806 100644
--- a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/pages/main/MainView.java
+++ b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/pages/main/MainView.java
@@ -34,6 +34,7 @@ import com.vaadin.flow.theme.lumo.Lumo;
 import org.apache.isis.core.commons.collections.Can;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
+import org.apache.isis.core.metamodel.interactions.InteractionContext.Head;
 import org.apache.isis.core.webapp.context.IsisWebAppCommonContext;
 import org.apache.isis.incubator.viewer.vaadin.model.action.ActionVaa;
 import org.apache.isis.incubator.viewer.vaadin.ui.components.UiComponentFactoryVaa;
@@ -105,8 +106,7 @@ implements BeforeEnterObserver {
 
         val result = objectAction
                 .execute(
-                        actionOwner,
-                        null,
+                        Head.simple(actionOwner),
                         Can.empty(),
                         InteractionInitiatedBy.USER
                         );
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
index 14e5628..7ea5d51 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
@@ -192,11 +192,12 @@ implements FormUiModel, FormExecutorContext {
         final Can<ManagedObject> arguments = argCache().snapshot();
         final ObjectAction action = getMetaModel();
 
-        // if this action is a mixin, then it will fill in the details automatically.
-        val mixedInAdapter = (ManagedObject)null;
+        val head2 = action.newPendingParameterModelHead(targetAdapter);
+        val head = Head.of(head2.getActionOwner(), head2.getActionTarget());
+        
         val resultAdapter =
                 action.executeWithRuleChecking(
-                        targetAdapter, mixedInAdapter, arguments,
+                        head, arguments,
                         InteractionInitiatedBy.USER,
                         WHERE_FOR_ACTION_INVOCATION);