Repository: isis Updated Branches: refs/heads/master 5522f4bd5 -> ffd9f08c9
ISIS-1425: making the wrapper factory intelligent enough to handle (dereference) programmatically instantiated mixins Project: http://git-wip-us.apache.org/repos/asf/isis/repo Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/ffd9f08c Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/ffd9f08c Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/ffd9f08c Branch: refs/heads/master Commit: ffd9f08c9487d1c785d8ebd10fb99c0da3aa47fe Parents: 5522f4b Author: Dan Haywood <d...@haywood-associates.co.uk> Authored: Fri Jun 3 18:48:29 2016 +0100 Committer: Dan Haywood <d...@haywood-associates.co.uk> Committed: Fri Jun 3 18:48:29 2016 +0100 ---------------------------------------------------------------------- .../facets/object/mixin/MixinFacet.java | 6 +++ .../facets/object/mixin/MixinFacetAbstract.java | 32 +++++++++++++ .../handlers/DomainObjectInvocationHandler.java | 47 +++++++++++++++++--- 3 files changed, 78 insertions(+), 7 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/isis/blob/ffd9f08c/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacet.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacet.java index b3d4e40..8aed8ad 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacet.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacet.java @@ -21,6 +21,7 @@ package org.apache.isis.core.metamodel.facets.object.mixin; import org.apache.isis.applib.annotation.DomainObject; import org.apache.isis.applib.annotation.Nature; +import org.apache.isis.core.metamodel.adapter.ObjectAdapter; import org.apache.isis.core.metamodel.facetapi.Facet; import org.apache.isis.core.metamodel.spec.ObjectSpecification; @@ -35,6 +36,11 @@ public interface MixinFacet extends Facet { boolean isMixinFor(Class<?> candidateDomainType); /** + * Returns the (adapter of the) domain object that a mixin adapter contains. + */ + ObjectAdapter mixedIn(ObjectAdapter mixinAdapter); + + /** * Returns the mixin around the provided domain object */ Object instantiate(Object domainPojo); http://git-wip-us.apache.org/repos/asf/isis/blob/ffd9f08c/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetAbstract.java ---------------------------------------------------------------------- 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 f5cb292..cabb093 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 @@ -20,8 +20,12 @@ package org.apache.isis.core.metamodel.facets.object.mixin; import java.lang.reflect.Constructor; +import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; +import org.apache.isis.applib.services.title.TitleService; +import org.apache.isis.core.metamodel.adapter.ObjectAdapter; +import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager; import org.apache.isis.core.metamodel.facetapi.Facet; import org.apache.isis.core.metamodel.facetapi.FacetHolder; import org.apache.isis.core.metamodel.facets.MarkerFacetAbstract; @@ -85,4 +89,32 @@ public abstract class MixinFacetAbstract extends MarkerFacetAbstract implements } } + @Override + public ObjectAdapter mixedIn(ObjectAdapter mixinAdapter) { + + final Object mixin = mixinAdapter.getObject(); + + final Field[] declaredFields = mixinType.getDeclaredFields(); + for (final Field declaredField : declaredFields) { + if(declaredField.getType().isAssignableFrom(constructorType)) { + declaredField.setAccessible(true); + try { + Object o = declaredField.get(mixin); + return getAdapterManager().adapterFor(o); + } catch (IllegalAccessException e) { + throw new RuntimeException("Unable to access " + declaredField + " for " + getTitleService().titleOf(mixin)); + } + } + } + throw new RuntimeException("Could not find the \"mixed-in\" domain object within " + getTitleService().titleOf(mixin) + " (tried to guess by looking at all private fields and matching one against the constructor parameter)"); + } + + private AdapterManager getAdapterManager() { + return servicesInjector.getPersistenceSessionServiceInternal(); + } + + private TitleService getTitleService() { + return servicesInjector.lookupService(TitleService.class); + } + } http://git-wip-us.apache.org/repos/asf/isis/blob/ffd9f08c/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/DomainObjectInvocationHandler.java ---------------------------------------------------------------------- diff --git a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/DomainObjectInvocationHandler.java b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/DomainObjectInvocationHandler.java index 16f1819..fafe407 100644 --- a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/DomainObjectInvocationHandler.java +++ b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/DomainObjectInvocationHandler.java @@ -32,6 +32,8 @@ import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Sets; +import org.apache.isis.core.metamodel.facets.object.mixin.MixinFacet; +import org.apache.isis.core.metamodel.specloader.specimpl.ObjectActionMixedIn; import org.datanucleus.enhancement.Persistable; import org.apache.isis.applib.annotation.Where; @@ -253,13 +255,43 @@ public class DomainObjectInvocationHandler<T> extends DelegatingInvocationHandle throw new UnsupportedOperationException(String.format("Cannot invoke supporting method '%s'; use only the 'invoke' method", memberName)); } - final ObjectAction noa = (ObjectAction) objectMember; - return handleActionMethod(targetAdapter, args, noa, contributeeMember); + final ObjectAction objectAction = (ObjectAction) objectMember; + + final ObjectAction actualObjectAction; + final ObjectAdapter actualTargetAdapter; + + final MixinFacet mixinFacet = targetAdapter.getSpecification().getFacet(MixinFacet.class); + if(mixinFacet != null) { + + // rather than invoke on a (transient) mixin, instead figure out the corresponding ObjectActoinMixedIn + actualTargetAdapter = mixinFacet.mixedIn(targetAdapter); + actualObjectAction = determineMixinAction(objectAction, actualTargetAdapter); + + } else { + actualTargetAdapter = targetAdapter; + actualObjectAction = objectAction; + } + + return handleActionMethod(actualTargetAdapter, args, actualObjectAction, contributeeMember); } throw new UnsupportedOperationException(String.format("Unknown member type '%s'", objectMember)); } + private ObjectAction determineMixinAction(final ObjectAction objectAction, final ObjectAdapter actualTargetAdapter) { + final ObjectSpecification specification = actualTargetAdapter.getSpecification(); + final List<ObjectAction> objectActions = specification.getObjectActions(Contributed.INCLUDED); + for (final ObjectAction action : objectActions) { + if(action instanceof ObjectActionMixedIn) { + ObjectActionMixedIn mixedInAction = (ObjectActionMixedIn) action; + if(mixedInAction.hasMixinAction(objectAction)) { + return mixedInAction; + } + } + } + throw new RuntimeException("Unable to find the mixed-in action corresponding to " + objectAction.getIdentifier().toFullIdentityString()); + } + public InteractionInitiatedBy getInteractionInitiatedBy() { return getExecutionMode().shouldEnforceRules()? InteractionInitiatedBy.USER: InteractionInitiatedBy.FRAMEWORK; } @@ -618,11 +650,12 @@ public class DomainObjectInvocationHandler<T> extends DelegatingInvocationHandle if (getExecutionMode().shouldExecute()) { final InteractionInitiatedBy interactionInitiatedBy = getInteractionInitiatedBy(); - final ObjectAdapter mixedInAdapter = null; // mixin action will automatically fill in. - final ObjectAdapter returnedAdapter = - objectAction.execute( - targetAdapter, mixedInAdapter, argAdapters, - interactionInitiatedBy); + + final ObjectAdapter mixedInAdapter = null; // if a mixin action, then it will automatically fill in. + + final ObjectAdapter returnedAdapter = objectAction.execute( + targetAdapter, mixedInAdapter, argAdapters, + interactionInitiatedBy); return ObjectAdapter.Util.unwrap(returnedAdapter); }