You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2020/01/05 17:54:54 UTC

[isis] 02/04: ISIS-2255: when reverse lookup of mixin, also consider properties and collections.

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 d9b47234e3a8861f5349182104488e26a8280476
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Sun Jan 5 17:20:26 2020 +0000

    ISIS-2255: when reverse lookup of mixin, also consider properties and collections.
---
 .../specloader/specimpl/MixedInMember.java         |  2 +
 .../specimpl/OneToManyAssociationMixedIn.java      |  8 ++-
 .../specimpl/OneToOneAssociationMixedIn.java       |  6 +++
 .../handlers/DomainObjectInvocationHandler.java    | 58 ++++++++++++++--------
 4 files changed, 51 insertions(+), 23 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/MixedInMember.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/MixedInMember.java
index 46a5d65..cc101af 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/MixedInMember.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/MixedInMember.java
@@ -20,6 +20,7 @@ package org.apache.isis.metamodel.specloader.specimpl;
 
 import org.apache.isis.applib.annotation.Mixin;
 import org.apache.isis.metamodel.spec.ObjectSpecification;
+import org.apache.isis.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.metamodel.spec.feature.ObjectMember;
 
 /**
@@ -34,5 +35,6 @@ public interface MixedInMember extends ObjectMember {
 
     ObjectSpecification getMixinType();
 
+    boolean hasMixinAction(ObjectAction objectAction);
 }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java
index 91dcaad..afa9e49 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java
@@ -42,6 +42,7 @@ import org.apache.isis.metamodel.interactions.VisibilityContext;
 import org.apache.isis.metamodel.services.publishing.PublisherDispatchService;
 import org.apache.isis.metamodel.spec.ManagedObject;
 import org.apache.isis.metamodel.spec.ObjectSpecification;
+import org.apache.isis.metamodel.spec.feature.ObjectAction;
 
 import lombok.Getter;
 import lombok.val;
@@ -82,7 +83,7 @@ public class OneToManyAssociationMixedIn extends OneToManyAssociationDefault imp
         // created from mixin actions.
         val type = actionTypeOfFacet != null
                 ? actionTypeOfFacet.value()
-                        : Object.class;
+                : (Class)Object.class;
                 
         return objectAction.getSpecificationLoader().loadSpecification(type);
     }
@@ -211,6 +212,11 @@ public class OneToManyAssociationMixedIn extends OneToManyAssociationDefault imp
         return getSpecificationLoader().loadSpecification(mixinType);
     }
 
+    @Override
+    public boolean hasMixinAction(final ObjectAction mixinAction) {
+        return this.mixinAction == mixinAction;
+    }
+
     private PublisherDispatchService getPublishingServiceInternal() {
         return getServiceRegistry().lookupServiceElseFail(PublisherDispatchService.class);
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java
index 97028f1..42e8ee0 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java
@@ -40,6 +40,7 @@ import org.apache.isis.metamodel.interactions.VisibilityContext;
 import org.apache.isis.metamodel.services.publishing.PublisherDispatchService;
 import org.apache.isis.metamodel.spec.ManagedObject;
 import org.apache.isis.metamodel.spec.ObjectSpecification;
+import org.apache.isis.metamodel.spec.feature.ObjectAction;
 
 import lombok.Getter;
 import lombok.val;
@@ -197,6 +198,11 @@ public class OneToOneAssociationMixedIn extends OneToOneAssociationDefault imple
         return getSpecificationLoader().loadSpecification(mixinType);
     }
 
+    @Override
+    public boolean hasMixinAction(final ObjectAction mixinAction) {
+        return this.mixinAction == mixinAction;
+    }
+
     private PublisherDispatchService getPublishingServiceInternal() {
         return getServiceRegistry().lookupServiceElseFail(PublisherDispatchService.class);
     }
diff --git a/core/runtime-services/src/main/java/org/apache/isis/runtime/services/wrapper/handlers/DomainObjectInvocationHandler.java b/core/runtime-services/src/main/java/org/apache/isis/runtime/services/wrapper/handlers/DomainObjectInvocationHandler.java
index fa7286b..ad992b5 100644
--- a/core/runtime-services/src/main/java/org/apache/isis/runtime/services/wrapper/handlers/DomainObjectInvocationHandler.java
+++ b/core/runtime-services/src/main/java/org/apache/isis/runtime/services/wrapper/handlers/DomainObjectInvocationHandler.java
@@ -29,7 +29,6 @@ import java.util.function.Supplier;
 import java.util.stream.Stream;
 
 import org.apache.isis.applib.annotation.Where;
-import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.applib.services.wrapper.DisabledException;
 import org.apache.isis.applib.services.wrapper.HiddenException;
 import org.apache.isis.applib.services.wrapper.InteractionException;
@@ -45,6 +44,7 @@ import org.apache.isis.applib.services.wrapper.events.VisibilityEvent;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.collections._Arrays;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.metamodel.consent.InteractionResult;
 import org.apache.isis.metamodel.context.MetaModelContext;
@@ -63,6 +63,7 @@ import org.apache.isis.metamodel.spec.feature.OneToManyAssociation;
 import org.apache.isis.metamodel.spec.feature.OneToOneAssociation;
 import org.apache.isis.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.metamodel.specloader.specimpl.ContributeeMember;
+import org.apache.isis.metamodel.specloader.specimpl.MixedInMember;
 import org.apache.isis.metamodel.specloader.specimpl.ObjectActionContributee;
 import org.apache.isis.metamodel.specloader.specimpl.ObjectActionMixedIn;
 import org.apache.isis.metamodel.specloader.specimpl.dflt.ObjectSpecificationDefault;
@@ -152,7 +153,8 @@ public class DomainObjectInvocationHandler<T> extends DelegatingInvocationHandle
         }
 
 
-        final ObjectSpecification targetNoSpec = targetAdapter.getSpecification();
+        final ObjectSpecification targetSpec = targetAdapter.getSpecification();
+        final ObjectSpecification targetNoSpec = targetSpec;
 
         // save method, through the proxy
         if (isSaveMethod(method)) {
@@ -223,34 +225,44 @@ public class DomainObjectInvocationHandler<T> extends DelegatingInvocationHandle
 
             val objectAction = (ObjectAction) objectMember;
 
-            ObjectAction actualObjectAction;
-            ManagedObject actualTargetAdapter;
 
-            val mixinFacet = targetAdapter.getSpecification().getFacet(MixinFacet.class);
+            val mixinFacet = targetSpec.getFacet(MixinFacet.class);
             if(mixinFacet != null) {
 
                 // rather than invoke on a (transient) mixin, instead try to
-                // figure out the corresponding ObjectActionMixedIn
-                actualTargetAdapter = mixinFacet.mixedIn(targetAdapter, MixinFacet.Policy.IGNORE_FAILURES);
-                actualObjectAction = determineMixinAction(actualTargetAdapter, objectAction);
-
-                if(actualTargetAdapter == null || actualObjectAction == null) {
-                    // revert to original behaviour
-                    actualTargetAdapter = targetAdapter;
-                    actualObjectAction = objectAction;
+                // figure out the corresponding contributed member on the contributee.
+                final ManagedObject contributeeAdapter =
+                        mixinFacet.mixedIn(targetAdapter, MixinFacet.Policy.IGNORE_FAILURES);
+
+                if (contributeeAdapter == null) {
+                    throw _Exceptions.illegalState(String.format("Could not locate contributeeAdapter for action '%s'", objectAction.getId()));
+                }
+                final ObjectMember mixinMember = determineMixinMember(contributeeAdapter, objectAction);
+
+                if (mixinMember != null) {
+                    if(mixinMember instanceof ObjectAction) {
+                        return handleActionMethod(contributeeAdapter, args, (ObjectAction)mixinMember, contributeeMember);
+                    }
+                    if(mixinMember instanceof OneToOneAssociation) {
+                        return handleGetterMethodOnProperty(contributeeAdapter, new Object[0], (OneToOneAssociation)mixinMember);
+                    }
+                    if(mixinMember instanceof OneToManyAssociation) {
+                        return handleGetterMethodOnCollection(contributeeAdapter, new Object[0], (OneToManyAssociation)mixinMember, method, memberName);
+                    }
+                } else {
+                    throw _Exceptions.illegalState(String.format(
+                            "Could not locate mixin member for action '%s' on spec '%s'", objectAction.getId(), targetSpec));
                 }
-            } else {
-                actualTargetAdapter = targetAdapter;
-                actualObjectAction = objectAction;
             }
 
-            return handleActionMethod(actualTargetAdapter, args, actualObjectAction, contributeeMember);
+            // this is just a regular non-mixin action.
+            return handleActionMethod(targetAdapter, args, objectAction, contributeeMember);
         }
 
         throw new UnsupportedOperationException(String.format("Unknown member type '%s'", objectMember));
     }
 
-    private static ObjectAction determineMixinAction(
+    private static ObjectMember determineMixinMember(
             final ManagedObject domainObjectAdapter,
             final ObjectAction objectAction) {
         
@@ -259,11 +271,13 @@ public class DomainObjectInvocationHandler<T> extends DelegatingInvocationHandle
         }
         val specification = domainObjectAdapter.getSpecification();
         val objectActions = specification.streamObjectActions(Contributed.INCLUDED);
+        val objectAssociations = specification.streamAssociations(Contributed.INCLUDED);
 
-        return objectActions
-                .filter(action->action instanceof ObjectActionMixedIn)
-                .map(action->(ObjectActionMixedIn) action)
-                .filter(mixedInAction->mixedInAction.hasMixinAction(objectAction))
+        final Stream<ObjectMember> objectMembers = Stream.concat(objectActions, objectAssociations);
+        return objectMembers
+                .filter(MixedInMember.class::isInstance)
+                .map(MixedInMember.class::cast)
+                .filter(mixedInMember->mixedInMember.hasMixinAction(objectAction))
                 .findFirst()
                 .orElse(null);