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

[02/14] isis git commit: ISIS-1370: construct the aimDto before calling PublisherService. Also refactoring property setter facet and OneToOneAssociation to follow the same general structure as for action invocations, in particular for the set up of Com

ISIS-1370:  construct the aimDto before calling PublisherService.  Also refactoring property setter facet and OneToOneAssociation to follow the same general structure as for action invocations, in particular for the set up of Command objects.


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

Branch: refs/heads/ISIS-1291
Commit: 07342da5a1956fcd3a8ce52e752222be4340d5c4
Parents: 0d892e1
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Mon May 2 10:21:07 2016 +0100
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Mon May 2 10:21:07 2016 +0100

----------------------------------------------------------------------
 .../isis/applib/services/iactn/Interaction.java |  63 +++----
 .../utils/ActionInvocationMementoDtoUtils.java  |  32 ++--
 .../schema/utils/CommandMementoDtoUtils.java    |  20 ++-
 .../org/apache/isis/schema/utils/Roundtrip.java |  19 ++-
 ...onInvocationFacetForDomainEventAbstract.java |  35 ++--
 .../actions/action/invocation/CommandUtil.java  |  42 +++--
 ...opertySetterFacetForDomainEventAbstract.java |   6 +-
 .../update/modify/PropertySetterFacet.java      |   6 +-
 .../PropertySetterFacetViaModifyMethod.java     |  38 +++--
 .../PropertySetterFacetViaSetterMethod.java     |   3 +-
 .../services/command/CommandMementoService.java |  25 ++-
 .../publishing/PublishingServiceInternal.java   |   2 +
 .../metamodel/spec/feature/ObjectAction.java    |   2 +-
 .../spec/feature/OneToOneAssociation.java       |   5 +
 .../specimpl/ObjectActionDefault.java           | 167 ++++---------------
 .../specimpl/ObjectMemberAbstract.java          | 104 ++++++++++++
 .../specimpl/OneToOneAssociationDefault.java    |  41 ++++-
 .../PropertyAnnotationFacetFactoryTest.java     |   3 +-
 .../command/CommandMementoServiceDefault.java   |  35 +++-
 .../PublishingServiceInternalDefault.java       |  67 +++++---
 20 files changed, 450 insertions(+), 265 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/07342da5/core/applib/src/main/java/org/apache/isis/applib/services/iactn/Interaction.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/iactn/Interaction.java b/core/applib/src/main/java/org/apache/isis/applib/services/iactn/Interaction.java
index 06a5347..444877f 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/iactn/Interaction.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/iactn/Interaction.java
@@ -94,25 +94,27 @@ public class Interaction implements HasTransactionId {
 
     public static abstract class MemberArgs {
 
+        private final String memberId;
+
         public enum Type {
             PROPERTY,
             ACTION
         }
 
-        private final Command command;
         private final Object target;
         private final Type type;
 
         protected MemberArgs(
-                final Command command,
-                final Object target, final Type type) {
-            this.command = command;
+                final Type type,
+                final String memberId,
+                final Object target) {
+            this.memberId = memberId;
             this.target = target;
             this.type = type;
         }
 
-        public Command getCommand() {
-            return command;
+        public String getMemberId() {
+            return memberId;
         }
 
         public Object getTarget() {
@@ -129,10 +131,10 @@ public class Interaction implements HasTransactionId {
         private final List<Object> args;
 
         public ActionArgs(
-                final Command command,
+                final String actionId,
                 final Object target,
                 final List<Object> args) {
-            super(command, target, Type.ACTION);
+            super(Type.ACTION, actionId, target);
             this.args = args;
         }
 
@@ -145,10 +147,9 @@ public class Interaction implements HasTransactionId {
         private final Object argValue;
 
         public PropertyArgs(
-                final Command command,
-                final Object target,
+                final String propertyId, final Object target,
                 final Object argValue) {
-            super(command, target, Type.PROPERTY);
+            super(Type.PROPERTY, propertyId, target);
             this.argValue = argValue;
         }
 
@@ -160,41 +161,47 @@ public class Interaction implements HasTransactionId {
     public <T> T execute(
             final MemberCallable memberCallable,
             final ActionArgs actionArgs,
-            final ClockService clockService) {
-
-        final Timestamp startedAt = clockService.nowAsJavaSqlTimestamp();
-        final Execution execution = push(startedAt, actionArgs);
+            final ClockService clockService,
+            final Command command) {
 
-        final Command command = actionArgs.getCommand();
-        return execute(memberCallable, actionArgs, clockService, command, startedAt, execution);
+        final Execution execution = push(actionArgs, clockService, command);
 
+        return execute(memberCallable, actionArgs, clockService, execution);
     }
 
     public <T> T execute(
             final MemberCallable memberCallable,
             final PropertyArgs propertyArgs,
-            final ClockService clockService) {
+            final ClockService clockService,
+            final Command command) {
+
+        final Execution execution = push(propertyArgs, clockService, command);
+        return execute(memberCallable, propertyArgs, clockService, execution);
+    }
 
-        final Timestamp startedAt = clockService.nowAsJavaSqlTimestamp();
-        Execution execution = push(startedAt, propertyArgs);
 
-        final Command command = propertyArgs.getCommand();
-        return execute(memberCallable, propertyArgs, clockService, command, startedAt, execution);
+    private Execution push(
+            final MemberArgs memberArgs,
+            final ClockService clockService,
+            final Command command) {
+        final Timestamp startedAt = clockService.nowAsJavaSqlTimestamp();
+        final Execution execution = push(startedAt, memberArgs);
 
+        if(command.getStartedAt() == null) {
+            command.setStartedAt(startedAt);
+        }
+        return execution;
     }
 
+
     private <T> T execute(
             final MemberCallable memberCallable,
             final MemberArgs memberArgs,
             final ClockService clockService,
-            final Command command,
-            final Timestamp startedAt,
             final Execution currentExecution) {
+
         // as a convenience, since in all cases we want the command to start when the first interaction executes,
         // we populate the command here.
-        if(command.getStartedAt() == null) {
-            command.setStartedAt(startedAt);
-        }
 
         try {
             try {
@@ -313,8 +320,6 @@ public class Interaction implements HasTransactionId {
 
         //endregion
 
-
-
         //region > exception (property)
 
         private RuntimeException exception;

http://git-wip-us.apache.org/repos/asf/isis/blob/07342da5/core/applib/src/main/java/org/apache/isis/schema/utils/ActionInvocationMementoDtoUtils.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/schema/utils/ActionInvocationMementoDtoUtils.java b/core/applib/src/main/java/org/apache/isis/schema/utils/ActionInvocationMementoDtoUtils.java
index ed74b83..9c96fec 100644
--- a/core/applib/src/main/java/org/apache/isis/schema/utils/ActionInvocationMementoDtoUtils.java
+++ b/core/applib/src/main/java/org/apache/isis/schema/utils/ActionInvocationMementoDtoUtils.java
@@ -114,16 +114,17 @@ public final class ActionInvocationMementoDtoUtils {
     }
     //endregion
 
-    //region > actionIdentifier, target
+    //region > newDto
 
     public static ActionInvocationMementoDto newDto(
             final UUID transactionId,
             final int sequence,
-            final String actionIdentifier,
             final Bookmark targetBookmark,
+            final ActionDto actionDto,
             final String title,
             final String user,
-            final Timestamp timestamp) {
+            final Timestamp startedAt, final Timestamp completedAt,
+            final ReturnDto returnDto) {
 
         final ActionInvocationMementoDto aim = new ActionInvocationMementoDto();
 
@@ -145,11 +146,12 @@ public final class ActionInvocationMementoDtoUtils {
         invocation.setTitle(title);
         invocation.setUser(user);
 
-        ActionDto action = actionFor(invocation);
-        action.setActionIdentifier(actionIdentifier);
+        invocation.setAction(actionDto);
+        invocation.setReturned(returnDto);
 
-        PeriodDto timings = timingsFor(invocation);
-        timings.setStart(JavaSqlTimestampXmlGregorianCalendarAdapter.print(timestamp));
+        final PeriodDto timings = timingsFor(invocation);
+        timings.setStart(JavaSqlTimestampXmlGregorianCalendarAdapter.print(startedAt));
+        timings.setComplete(JavaSqlTimestampXmlGregorianCalendarAdapter.print(completedAt));
 
         return aim;
     }
@@ -333,14 +335,20 @@ public final class ActionInvocationMementoDtoUtils {
         return Collections.unmodifiableList(Lists.newArrayList(iterable));
     }
 
-    private static boolean setValue(
+    public static boolean setValue(
             final ReturnDto returnDto,
             final Class<?> type,
             final Object val) {
-        ValueDto valueDto = new ValueDto();
-        returnDto.setValue(valueDto);
-        setValueType(returnDto, type);
-        return CommonDtoUtils.setValue(valueDto, type, val);
+        if(val == null) {
+            returnDto.setNull(true);
+            return true;
+        } else {
+            returnDto.setNull(false);
+            final ValueDto valueDto = new ValueDto();
+            returnDto.setValue(valueDto);
+            setValueType(returnDto, type);
+            return CommonDtoUtils.setValue(valueDto, type, val);
+        }
     }
 
     private static boolean setValueType(

http://git-wip-us.apache.org/repos/asf/isis/blob/07342da5/core/applib/src/main/java/org/apache/isis/schema/utils/CommandMementoDtoUtils.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/schema/utils/CommandMementoDtoUtils.java b/core/applib/src/main/java/org/apache/isis/schema/utils/CommandMementoDtoUtils.java
index 9e7ae06..99cecbf 100644
--- a/core/applib/src/main/java/org/apache/isis/schema/utils/CommandMementoDtoUtils.java
+++ b/core/applib/src/main/java/org/apache/isis/schema/utils/CommandMementoDtoUtils.java
@@ -160,7 +160,8 @@ public final class CommandMementoDtoUtils {
     private static boolean addParamArgValue(
             final List<ParamDto> params,
             final String parameterName,
-            final Class<?> parameterType, final Object arg) {
+            final Class<?> parameterType,
+            final Object arg) {
         ParamDto paramDto = null;
         if(parameterType == String.class) {
             paramDto = newParamDto(params, parameterName, ValueType.STRING, arg);
@@ -213,9 +214,10 @@ public final class CommandMementoDtoUtils {
         }
 
         if(paramDto != null) {
-            final ValueDto valueDto = argumentFor(paramDto);
-
-            CommonDtoUtils.setValue(valueDto, parameterType, arg);
+            if (arg != null) {
+                final ValueDto valueDto = argumentFor(paramDto);
+                CommonDtoUtils.setValue(valueDto, parameterType, arg);
+            }
             return true;
         }
 
@@ -229,9 +231,13 @@ public final class CommandMementoDtoUtils {
             final Bookmark bookmark) {
         final ParamDto paramDto =
                 newParamDto(params, parameterName, ValueType.REFERENCE, bookmark);
-        final ValueDto valueDto = argumentFor(paramDto);
-        OidDto argValue = CommonDtoUtils.asOidDto(bookmark);
-        valueDto.setReference(argValue);
+
+        if (bookmark != null) {
+            final ValueDto valueDto = argumentFor(paramDto);
+
+            OidDto argValue = CommonDtoUtils.asOidDto(bookmark);
+            valueDto.setReference(argValue);
+        }
     }
 
     private static ParamDto newParamDto(

http://git-wip-us.apache.org/repos/asf/isis/blob/07342da5/core/applib/src/test/java/org/apache/isis/schema/utils/Roundtrip.java
----------------------------------------------------------------------
diff --git a/core/applib/src/test/java/org/apache/isis/schema/utils/Roundtrip.java b/core/applib/src/test/java/org/apache/isis/schema/utils/Roundtrip.java
index 5be8a88..b2a5cc7 100644
--- a/core/applib/src/test/java/org/apache/isis/schema/utils/Roundtrip.java
+++ b/core/applib/src/test/java/org/apache/isis/schema/utils/Roundtrip.java
@@ -20,6 +20,8 @@ import java.io.CharArrayReader;
 import java.io.CharArrayWriter;
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.sql.Timestamp;
+import java.util.Date;
 import java.util.UUID;
 
 import org.hamcrest.Matchers;
@@ -31,6 +33,8 @@ import org.junit.Test;
 
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.schema.aim.v2.ActionInvocationMementoDto;
+import org.apache.isis.schema.aim.v2.ReturnDto;
+import org.apache.isis.schema.cmd.v1.ActionDto;
 import org.apache.isis.schema.common.v1.OidDto;
 import org.apache.isis.schema.common.v1.ValueType;
 
@@ -45,12 +49,21 @@ public class Roundtrip {
     public void happyCase() throws Exception {
 
         // given
+        final ActionDto actionDto = new ActionDto();
+        actionDto.setActionIdentifier("com.mycompany.Customer#placeOrder");
+
+        final Timestamp startedAt = new Timestamp(new Date().getTime());
+        final Timestamp completedAt = new Timestamp(startedAt.getTime() + 1000);
+
+        final ReturnDto returnDto = new ReturnDto();
+        returnDto.setReturnType(ValueType.BOOLEAN);
+        returnDto.setNull(true);
+
         final ActionInvocationMementoDto aim = ActionInvocationMementoDtoUtils.newDto(
                 UUID.randomUUID(),
                 1,
-                "com.mycompany.myapp.Customer#placeOrder",
-                new Bookmark("CUS", "12345"), "John Customer", "freddyUser",
-                new java.sql.Timestamp(new java.util.Date().getTime()));
+                new Bookmark("CUS", "12345"), actionDto, "John Customer", "freddyUser",
+                startedAt, completedAt, returnDto);
 
         ActionInvocationMementoDtoUtils.addParamArg(aim, "aString", String.class, "Fred", null);
         ActionInvocationMementoDtoUtils.addParamArg(aim, "nullString", String.class, (String) null, null);

http://git-wip-us.apache.org/repos/asf/isis/blob/07342da5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java
index c2953e5..d57539b 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
@@ -235,14 +235,13 @@ public abstract class ActionInvocationFacetForDomainEventAbstract
     private InvocationResult invoke(
             final ObjectAction owningAction,
             final ObjectAdapter targetAdapter,
-            final ObjectAdapter[] arguments) {
+            final ObjectAdapter[] argumentAdapters) {
 
         try {
-            setupActionInvocationContext(owningAction, targetAdapter);
+            owningAction.setupActionInvocationContext(targetAdapter);
+            owningAction.setupCommand(targetAdapter, argumentAdapters);
 
-            owningAction.setupCommand(targetAdapter, arguments);
-
-            ObjectAdapter resultAdapter = invokeThruCommand(owningAction, targetAdapter, arguments);
+            ObjectAdapter resultAdapter = invokeThruCommand(owningAction, targetAdapter, argumentAdapters);
 
             return InvocationResult.forActionThatReturned(resultAdapter);
 
@@ -289,13 +288,6 @@ public abstract class ActionInvocationFacetForDomainEventAbstract
         return message;
     }
 
-    protected void setupActionInvocationContext(
-            final ObjectAction owningAction,
-            final ObjectAdapter targetAdapter) {
-
-        owningAction.setupActionInvocationContext(targetAdapter);
-    }
-
     protected ObjectAdapter invokeThruCommand(
             final ObjectAction owningAction,
             final ObjectAdapter targetAdapter,
@@ -308,19 +300,20 @@ public abstract class ActionInvocationFacetForDomainEventAbstract
         final InteractionContext interactionContext = getInteractionContext();
         final Interaction interaction = interactionContext.getInteraction();
 
+        final String actionId = owningAction.getIdentifier().toClassAndNameIdentityString();
 
         final ObjectAdapter resultAdapter;
         if( command.getExecutor() == Command.Executor.USER &&
-                command.getExecuteIn() == org.apache.isis.applib.annotation.Command.ExecuteIn.BACKGROUND) {
+            command.getExecuteIn() == org.apache.isis.applib.annotation.Command.ExecuteIn.BACKGROUND) {
 
             // deal with background commands
 
-            // persist command so can be this command can be in the 'background'
+            // persist command so can it can subsequently be invoked in the 'background'
             final CommandService commandService = getCommandService();
             if (!commandService.persistIfPossible(command)) {
                 throw new IsisException(String.format(
-                        "Unable to schedule action '%s' to run in background; CommandService does not support persistent commands ",
-                                owningAction.getIdentifier().toClassAndNameIdentityString()));
+                        "Unable to persist command for action '%s'; CommandService does not support persistent commands ",
+                        actionId));
             }
             resultAdapter = getAdapterManager().adapterFor(command);
 
@@ -331,8 +324,7 @@ public abstract class ActionInvocationFacetForDomainEventAbstract
             final Object target = ObjectAdapter.Util.unwrap(targetAdapter);
             final List<Object> arguments = ObjectAdapter.Util.unwrap(Arrays.asList(argumentAdapters));
 
-
-            final Interaction.ActionArgs actionArgs = new Interaction.ActionArgs(command, target, arguments);
+            final Interaction.ActionArgs actionArgs = new Interaction.ActionArgs(actionId, target, arguments);
             final Interaction.MemberCallable callable = new Interaction.MemberCallable<Interaction.ActionArgs>() {
                 @Override
                 public Object call(final Interaction.ActionArgs actionArgs) {
@@ -355,7 +347,7 @@ public abstract class ActionInvocationFacetForDomainEventAbstract
             };
 
 
-            interaction.execute(callable, actionArgs, getClockService());
+            interaction.execute(callable, actionArgs, getClockService(), command);
 
             final Interaction.Execution priorExecution = interaction.getPriorExecution();
 
@@ -374,7 +366,10 @@ public abstract class ActionInvocationFacetForDomainEventAbstract
                 final List<ObjectAdapter> parameterAdapters = Arrays.asList(argumentAdapters);
 
                 getPublishingServiceInternal().publishAction(
-                        owningAction, identifiedHolder, targetAdapter, parameterAdapters, resultAdapter);
+                        priorExecution,
+                        owningAction, identifiedHolder,
+                        targetAdapter, parameterAdapters,
+                        resultAdapter);
             }
 
         }

http://git-wip-us.apache.org/repos/asf/isis/blob/07342da5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/CommandUtil.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/CommandUtil.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/CommandUtil.java
index 967f3c3..92843ae 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/CommandUtil.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/CommandUtil.java
@@ -36,7 +36,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.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
-
+import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
 
 /**
  * Factoring out the commonality between <tt>ActionInvocationFacetViaMethod</tt> and <tt>BackgroundServiceDefault</tt>.
@@ -45,19 +45,26 @@ public class CommandUtil {
 
     private CommandUtil(){}
 
-    public static String targetActionNameFor(ObjectAction owningAction) {
-        return owningAction.getName();
+    public static String targetActionNameFor(final ObjectMember objectMember) {
+        return objectMember.getName();
     }
 
-    public static String targetClassNameFor(ObjectAdapter targetAdapter) {
+    public static String targetClassNameFor(final ObjectAdapter targetAdapter) {
         return StringExtensions.asNaturalName2(targetAdapter.getSpecification().getSingularName());
     }
 
-    public static String actionIdentifierFor(ObjectAction owningAction) {
-        return owningAction.getIdentifier().toClassAndNameIdentityString();
+    public static String actionIdentifierFor(final ObjectMember objectMember) {
+        return objectMember.getIdentifier().toClassAndNameIdentityString();
     }
 
-    public static String argDescriptionFor(ObjectAction owningAction, ObjectAdapter[] arguments) {
+    public static String argDescriptionFor(final ObjectAdapter valueAdapter) {
+        final StringBuilder buf = new StringBuilder();
+        appendArg(buf, "new value", valueAdapter);
+        return buf.toString();
+    }
+    public static String argDescriptionFor(
+            final ObjectAction owningAction,
+            final ObjectAdapter[] arguments) {
         final StringBuilder argsBuf = new StringBuilder();
         List<ObjectActionParameter> parameters = owningAction.getParameters();
         if(parameters.size() == arguments.length) {
@@ -80,12 +87,27 @@ public class CommandUtil {
         return rootOid.asBookmark();
     }
 
-    static void appendParamArg(final StringBuilder buf, ObjectActionParameter param, ObjectAdapter objectAdapter) {
+    static void appendParamArg(
+            final StringBuilder buf,
+            final ObjectActionParameter param,
+            final ObjectAdapter objectAdapter) {
+        final String name = param.getName();
+        appendArg(buf, name, objectAdapter);
+    }
+
+    private static void appendArg(
+            final StringBuilder buf,
+            final String name,
+            final ObjectAdapter objectAdapter) {
         String titleOf = objectAdapter != null? objectAdapter.titleString(null): "null";
-        buf.append(param.getName()).append(": ").append(titleOf).append("\n");
+        buf.append(name).append(": ").append(titleOf).append("\n");
     }
 
-    public static void buildMementoArgLists(MementoService mementoService, BookmarkService bookmarkService, final Method method, final Object[] args, final List<Class<?>> argTypes, final List<Object> argObjs) {
+    public static void buildMementoArgLists(
+            final MementoService mementoService,
+            final BookmarkService bookmarkService,
+            final Method method,
+            final Object[] args, final List<Class<?>> argTypes, final List<Object> argObjs) {
         for (int i = 0; i < args.length; i++) {
             Object input = args[i];
             if (mementoService.canSet(input)) {

http://git-wip-us.apache.org/repos/asf/isis/blob/07342da5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventAbstract.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventAbstract.java
index c19740e..4773c7d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterFacetForDomainEventAbstract.java
@@ -31,6 +31,7 @@ import org.apache.isis.core.metamodel.facets.SingleValueFacetAbstract;
 import org.apache.isis.core.metamodel.facets.propcoll.accessor.PropertyOrCollectionAccessorFacet;
 import org.apache.isis.core.metamodel.facets.properties.update.modify.PropertySetterFacet;
 import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
 
 public abstract class PropertySetterFacetForDomainEventAbstract
         extends SingleValueFacetAbstract<Class<? extends PropertyDomainEvent<?,?>>>
@@ -62,6 +63,7 @@ public abstract class PropertySetterFacetForDomainEventAbstract
 
     @Override
     public void setProperty(
+            final OneToOneAssociation owningAssociation,
             final ObjectAdapter targetAdapter,
             final ObjectAdapter newValueAdapter,
             final InteractionInitiatedBy interactionInitiatedBy) {
@@ -69,7 +71,7 @@ public abstract class PropertySetterFacetForDomainEventAbstract
             return;
         }
         if(!domainEventHelper.hasEventBusService()) {
-            setterFacet.setProperty(targetAdapter, newValueAdapter, interactionInitiatedBy);
+            setterFacet.setProperty(owningAssociation, targetAdapter, newValueAdapter, interactionInitiatedBy);
             return;
         }
 
@@ -86,7 +88,7 @@ public abstract class PropertySetterFacetForDomainEventAbstract
                         oldValue, newValue);
 
         // ... perform the property modification
-        setterFacet.setProperty(targetAdapter, newValueAdapter, interactionInitiatedBy);
+        setterFacet.setProperty(owningAssociation, targetAdapter, newValueAdapter, interactionInitiatedBy);
 
         // reading the actual value from the target object, playing it safe...
         final Object actualNewValue = getterFacet.getProperty(targetAdapter, interactionInitiatedBy);

http://git-wip-us.apache.org/repos/asf/isis/blob/07342da5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/update/modify/PropertySetterFacet.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/update/modify/PropertySetterFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/update/modify/PropertySetterFacet.java
index ad5efa7..d76fe2a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/update/modify/PropertySetterFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/update/modify/PropertySetterFacet.java
@@ -23,6 +23,7 @@ import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facets.propcoll.accessor.PropertyOrCollectionAccessorFacet;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
 
 /**
  * The mechanism by which the value of the property can be set.
@@ -41,7 +42,8 @@ public interface PropertySetterFacet extends Facet {
      * Sets the value of this property.
      */
     public void setProperty(
-            ObjectAdapter inObject,
-            ObjectAdapter value,
+            final OneToOneAssociation owningAssociation,
+            final ObjectAdapter inObject,
+            final ObjectAdapter value,
             final InteractionInitiatedBy interactionInitiatedBy);
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/07342da5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/update/modify/PropertySetterFacetViaModifyMethod.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/update/modify/PropertySetterFacetViaModifyMethod.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/update/modify/PropertySetterFacetViaModifyMethod.java
index d5b7ec9..137a63c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/update/modify/PropertySetterFacetViaModifyMethod.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/update/modify/PropertySetterFacetViaModifyMethod.java
@@ -32,8 +32,8 @@ import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.ImperativeFacet;
-import org.apache.isis.core.metamodel.facets.actions.action.invocation.CommandUtil;
 import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
 
 public class PropertySetterFacetViaModifyMethod extends PropertySetterFacetAbstract implements ImperativeFacet {
 
@@ -62,41 +62,45 @@ public class PropertySetterFacetViaModifyMethod extends PropertySetterFacetAbstr
 
     @Override
     public void setProperty(
-            final ObjectAdapter targetAdapter,
+            final OneToOneAssociation owningAssociation, final ObjectAdapter targetAdapter,
             final ObjectAdapter valueAdapter,
             final InteractionInitiatedBy interactionInitiatedBy) {
 
-        final CommandContext commandContext = getCommandContext();
-        final Command command = commandContext.getCommand();
+        owningAssociation.setupCommand(targetAdapter, valueAdapter);
 
-        final InteractionContext interactionContext = getInteractionContext();
-        final Interaction interaction = interactionContext.getInteraction();
+        invokeThruCommand(owningAssociation, targetAdapter, valueAdapter);
 
-        // cf similar code in ActionInvocationFacetForDomainEventFacet
-        command.setExecutor(Command.Executor.USER);
+    }
 
-        command.setTarget(CommandUtil.bookmarkFor(targetAdapter));
-        command.setTargetClass(CommandUtil.targetClassNameFor(targetAdapter));
-        command.setTargetAction(Command.ACTION_IDENTIFIER_FOR_EDIT);
-        command.setMemberIdentifier(Command.ACTION_IDENTIFIER_FOR_EDIT);
+    private void invokeThruCommand(
+            final OneToOneAssociation owningAssociation,
+            final ObjectAdapter targetAdapter,
+            final ObjectAdapter valueAdapter) {
 
-        command.setExecuteIn(org.apache.isis.applib.annotation.Command.ExecuteIn.FOREGROUND);
-        command.setPersistence(org.apache.isis.applib.annotation.Command.Persistence.IF_HINTED);
+        // TODO: refactor to be the same as ActionInvocationFacetFDEA
 
         final Object target = ObjectAdapter.Util.unwrap(targetAdapter);
         final Object argValue = ObjectAdapter.Util.unwrap(valueAdapter);
 
+        final String propertyId = owningAssociation.getIdentifier().toClassAndNameIdentityString();
+
         final Interaction.PropertyArgs propertyArgs =
-                new Interaction.PropertyArgs(command, target, argValue);
+                new Interaction.PropertyArgs(propertyId, target, argValue);
+
+        final CommandContext commandContext = getCommandContext();
+        final Command command = commandContext.getCommand();
+
+        final InteractionContext interactionContext = getInteractionContext();
+        final Interaction interaction = interactionContext.getInteraction();
 
         final Interaction.MemberCallable<?> callable =
                 new Interaction.MemberCallable<Interaction.PropertyArgs>() {
-                    @Override public Object call(final Interaction.PropertyArgs propertyArgs) {
+                    @Override public Object call(final Interaction.PropertyArgs propertyArgs11) {
                         return ObjectAdapter.InvokeUtils.invoke(method, targetAdapter, valueAdapter);
                     }
                 };
 
-        interaction.execute(callable, propertyArgs, getClockService());
+        interaction.execute(callable, propertyArgs, getClockService(), command);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/isis/blob/07342da5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/update/modify/PropertySetterFacetViaSetterMethod.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/update/modify/PropertySetterFacetViaSetterMethod.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/update/modify/PropertySetterFacetViaSetterMethod.java
index f4881b9..d0bd8e9 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/update/modify/PropertySetterFacetViaSetterMethod.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/update/modify/PropertySetterFacetViaSetterMethod.java
@@ -27,6 +27,7 @@ import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.ImperativeFacet;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
 
 public class PropertySetterFacetViaSetterMethod extends PropertySetterFacetAbstract implements ImperativeFacet {
 
@@ -53,7 +54,7 @@ public class PropertySetterFacetViaSetterMethod extends PropertySetterFacetAbstr
 
     @Override
     public void setProperty(
-            final ObjectAdapter adapter,
+            final OneToOneAssociation owningAssociation, final ObjectAdapter adapter,
             final ObjectAdapter valueAdapter,
             final InteractionInitiatedBy interactionInitiatedBy) {
         ObjectAdapter.InvokeUtils.invoke(method, adapter, valueAdapter);

http://git-wip-us.apache.org/repos/asf/isis/blob/07342da5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/command/CommandMementoService.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/command/CommandMementoService.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/command/CommandMementoService.java
index 713d2de..156ecb9 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/command/CommandMementoService.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/command/CommandMementoService.java
@@ -23,6 +23,8 @@ import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.services.background.ActionInvocationMemento;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+import org.apache.isis.schema.cmd.v1.ActionDto;
 import org.apache.isis.schema.cmd.v1.CommandMementoDto;
 
 /**
@@ -41,8 +43,9 @@ public interface CommandMementoService {
     ActionInvocationMemento asActionInvocationMemento(Method m, Object domainObject, Object[] args);
 
     /**
-     * Returns a JAXB DTO (hence convertible to XML) that represents the intention to invoke an action on an action
-     * (or possible many, for bulk actions).  The action can be a mixin action or a contributed action.
+     * Returns a JAXB DTO (hence convertible to XML) that represents the intention to invoke an action on a
+     * target object (or possible many targets, for bulk actions).  The action can be a mixin action or a
+     * contributed action.
      */
     @Programmatic
     CommandMementoDto asCommandMemento(
@@ -50,4 +53,20 @@ public interface CommandMementoService {
             final ObjectAction objectAction,
             final ObjectAdapter[] argAdapters);
 
-}
+    /**
+     * Returns a JAXB DTO (hence convertible to XML) that represents the intention to edit a property on
+     * a target.  The property can be a mixin or contributed.
+     */
+    @Programmatic
+    CommandMementoDto asCommandMemento(
+            final ObjectAdapter targetAdapter,
+            final OneToOneAssociation association,
+            final ObjectAdapter valueAdapter);
+
+    @Programmatic
+    void addActionArgs(
+            final ObjectAction objectAction,
+            final ActionDto actionDto,
+            final ObjectAdapter[] argAdapters);
+
+    }

http://git-wip-us.apache.org/repos/asf/isis/blob/07342da5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/publishing/PublishingServiceInternal.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/publishing/PublishingServiceInternal.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/publishing/PublishingServiceInternal.java
index 93f5e64..e2f5237 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/publishing/PublishingServiceInternal.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/publishing/PublishingServiceInternal.java
@@ -21,6 +21,7 @@ package org.apache.isis.core.metamodel.services.publishing;
 import java.util.List;
 
 import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.facetapi.IdentifiedHolder;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
@@ -32,6 +33,7 @@ public interface PublishingServiceInternal {
 
     @Programmatic
     void publishAction(
+            final Interaction.Execution execution,
             final ObjectAction objectAction,
             final IdentifiedHolder identifiedHolder,
             final ObjectAdapter targetAdapter,

http://git-wip-us.apache.org/repos/asf/isis/blob/07342da5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
----------------------------------------------------------------------
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 aec5a1c..a94f647 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
@@ -204,7 +204,7 @@ public interface ObjectAction extends ObjectMember {
      */
     void setupCommand(
             final ObjectAdapter targetAdapter,
-            final ObjectAdapter[] arguments);
+            final ObjectAdapter[] argumentAdapters);
 
     // //////////////////////////////////////////////////////
     // Utils

http://git-wip-us.apache.org/repos/asf/isis/blob/07342da5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/OneToOneAssociation.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/OneToOneAssociation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/OneToOneAssociation.java
index 3e8e3ea..78062b1 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/OneToOneAssociation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/OneToOneAssociation.java
@@ -79,6 +79,11 @@ public interface OneToOneAssociation extends ObjectAssociation, OneToOneFeature,
     @Deprecated
     void clearAssociation(ObjectAdapter inObject, final InteractionInitiatedBy interactionInitiatedBy);
 
+    /**
+     * Internal API
+     */
+    void setupCommand(final ObjectAdapter targetAdapter, final ObjectAdapter valueAdapter);
+
     
     // //////////////////////////////////////////////////////
     // Functions

http://git-wip-us.apache.org/repos/asf/isis/blob/07342da5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionDefault.java
----------------------------------------------------------------------
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 7551844..56cc26d 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
@@ -23,8 +23,6 @@ import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Callable;
 
-import javax.ws.rs.HEAD;
-
 import com.google.common.base.Objects;
 import com.google.common.collect.Lists;
 
@@ -38,9 +36,6 @@ import org.apache.isis.applib.annotation.Bulk;
 import org.apache.isis.applib.annotation.InvokedOn;
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.applib.filter.Filter;
-import org.apache.isis.applib.services.bookmark.Bookmark;
-import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.applib.services.command.CommandContext;
 import org.apache.isis.core.commons.debug.DebugString;
 import org.apache.isis.core.commons.exceptions.UnknownTypeException;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
@@ -56,7 +51,6 @@ import org.apache.isis.core.metamodel.facets.TypedHolder;
 import org.apache.isis.core.metamodel.facets.actions.action.invocation.ActionInvocationFacet;
 import org.apache.isis.core.metamodel.facets.actions.action.invocation.CommandUtil;
 import org.apache.isis.core.metamodel.facets.actions.bulk.BulkFacet;
-import org.apache.isis.core.metamodel.facets.actions.command.CommandFacet;
 import org.apache.isis.core.metamodel.facets.actions.debug.DebugFacet;
 import org.apache.isis.core.metamodel.facets.actions.defaults.ActionDefaultsFacet;
 import org.apache.isis.core.metamodel.facets.actions.exploration.ExplorationFacet;
@@ -80,7 +74,6 @@ import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
 import org.apache.isis.core.metamodel.spec.feature.ObjectMemberDependencies;
 import org.apache.isis.schema.cmd.v1.CommandMementoDto;
-import org.apache.isis.schema.utils.CommandMementoDtoUtils;
 
 public class ObjectActionDefault extends ObjectMemberAbstract implements ObjectAction {
 
@@ -379,6 +372,7 @@ public class ObjectActionDefault extends ObjectMemberAbstract implements ObjectA
         return execute(target, mixedInAdapter, arguments, interactionInitiatedBy);
     }
 
+
     @Override
     public ObjectAdapter execute(
             final ObjectAdapter targetAdapter,
@@ -451,6 +445,27 @@ public class ObjectActionDefault extends ObjectMemberAbstract implements ObjectA
         return pojo == null ? null : getPersistenceSessionService().adapterFor(pojo);
     }
 
+    private static ThreadLocal<List<ObjectAdapter>> commandTargetAdaptersHolder = new ThreadLocal<>();
+
+    /**
+     * A horrible hack to be able to persist a number of adapters in the command object.
+     *
+     * <p>
+     *     What is really needed is to be able to invoke an action on a number of adapters all together.
+     * </p>
+     */
+    public static <T> T withTargetAdapters(final List<ObjectAdapter> adapters, final Callable<T> callable) {
+        commandTargetAdaptersHolder.set(adapters);
+        try {
+            return callable.call();
+        } catch (Exception e) {
+            throw new ApplicationException(e);
+        } finally {
+            commandTargetAdaptersHolder.set(null);
+        }
+    }
+
+
     //endregion
 
     //region > choices
@@ -527,7 +542,7 @@ public class ObjectActionDefault extends ObjectMemberAbstract implements ObjectA
     @Override
     public void setupActionInvocationContext(final ObjectAdapter targetAdapter) {
 
-        final Object targetPojo = unwrap(targetAdapter);
+        final Object targetPojo = ObjectAdapter.Util.unwrap(targetAdapter);
 
         final BulkFacet bulkFacet = getFacetHolder().getFacet(BulkFacet.class);
         if (bulkFacet != null) {
@@ -554,132 +569,40 @@ public class ObjectActionDefault extends ObjectMemberAbstract implements ObjectA
     @Override
     public void setupCommand(
             final ObjectAdapter targetAdapter,
-            final ObjectAdapter[] arguments) {
+            final ObjectAdapter[] argumentAdapters) {
 
-        setupCommandTarget(targetAdapter, arguments);
+        setupCommandTarget(targetAdapter, argumentAdapters);
         setupCommandMemberIdentifier();
-        setupCommandMementoAndExecutionContext(targetAdapter, arguments);
+        setupCommandMementoAndExecutionContext(targetAdapter, argumentAdapters);
     }
 
-
     protected void setupCommandTarget(
             final ObjectAdapter targetAdapter,
-            final ObjectAdapter[] arguments) {
-
-        final CommandContext commandContext = getCommandContext();
-        final Command command = commandContext.getCommand();
-
-        if (command.getExecutor() != Command.Executor.USER) {
-            return;
-        }
-
-        if(command.getTarget() != null) {
-            // already set up by a ObjectActionContributee or edit form;
-            // don't overwrite
-            return;
-        }
-
-        command.setTargetClass(CommandUtil.targetClassNameFor(targetAdapter));
-        command.setTargetAction(CommandUtil.targetActionNameFor(this));
-        command.setArguments(CommandUtil.argDescriptionFor(this, arguments));
-
-        final Bookmark targetBookmark = CommandUtil.bookmarkFor(targetAdapter);
-        command.setTarget(targetBookmark);
-    }
-
-    protected void setupCommandMemberIdentifier() {
-
-        final CommandContext commandContext = getCommandContext();
-        final Command command = commandContext.getCommand();
-
-        if (command.getExecutor() != Command.Executor.USER) {
-            return;
-        }
-
-        if(Command.ACTION_IDENTIFIER_FOR_EDIT.equals(command.getMemberIdentifier())) {
-            // special case for edit properties, don't overwrite
-            return;
-        }
-
-        if (command.getMemberIdentifier() != null) {
-            // any contributed/mixin actions will fire after the main action
-            // the guard here prevents them from trashing the command's memberIdentifier
-            return;
-        }
-
-        command.setMemberIdentifier(CommandUtil.actionIdentifierFor(this));
-    }
+            final ObjectAdapter[] argumentAdapters) {
 
-    private static ThreadLocal<List<ObjectAdapter>> commandTargetAdaptersHolder = new ThreadLocal<>();
+        final String arguments = CommandUtil.argDescriptionFor(this, argumentAdapters);
 
-    /**
-     * A horrible hack to be able to persist a number of adapters in the command object.
-     *
-     * <p>
-     *     What is really needed is to be able to invoke an action on a number of adapters all together.
-     * </p>
-     */
-    public static <T> T withTargetAdapters(final List<ObjectAdapter> adapters, final Callable<T> callable) {
-        commandTargetAdaptersHolder.set(adapters);
-        try {
-            return callable.call();
-        } catch (Exception e) {
-            throw new ApplicationException(e);
-        } finally {
-            commandTargetAdaptersHolder.set(null);
-        }
+        setupCommandTarget(targetAdapter, arguments);
     }
 
     protected void setupCommandMementoAndExecutionContext(
             final ObjectAdapter targetAdapter,
-            final ObjectAdapter[] arguments) {
-
-        final CommandContext commandContext = getCommandContext();
-        final Command command = commandContext.getCommand();
-
+            final ObjectAdapter[] argumentAdapters) {
 
-        if (command.getExecutor() != Command.Executor.USER) {
-            return;
-        }
-
-        if(Command.ACTION_IDENTIFIER_FOR_EDIT.equals(command.getMemberIdentifier())) {
-            // special case for edit properties, don't overwrite
-            return;
-        }
-
-        if (command.getMemento() != null) {
-            // guard here to prevent subsequent contributed/mixin actions from
-            // trampling over the command's memento and execution context
-            return;
-        }
-
-        // memento
         final CommandMementoService commandMementoService = getCommandMementoService();
-
-        List<ObjectAdapter> commandTargetAdapters =
+        final List<ObjectAdapter> commandTargetAdapters =
                 commandTargetAdaptersHolder.get() != null
                         ? commandTargetAdaptersHolder.get()
                         : Collections.singletonList(targetAdapter);
 
         final CommandMementoDto dto = commandMementoService.asCommandMemento(
-                commandTargetAdapters, this, arguments);
+                commandTargetAdapters, this, argumentAdapters);
 
-        final String mementoXml = CommandMementoDtoUtils.toXml(dto);
-        command.setMemento(mementoXml);
-
-        // copy over the command execution 'context' (if available)
-        final CommandFacet commandFacet = getFacetHolder().getFacet(CommandFacet.class);
-        if(commandFacet != null && !commandFacet.isDisabled()) {
-            command.setExecuteIn(commandFacet.executeIn());
-            command.setPersistence(commandFacet.persistence());
-        } else {
-            // if no facet, assume do want to execute right now, but only persist (eventually) if hinted.
-            command.setExecuteIn(org.apache.isis.applib.annotation.Command.ExecuteIn.FOREGROUND);
-            command.setPersistence(org.apache.isis.applib.annotation.Command.Persistence.IF_HINTED);
-        }
+        setupCommandMementoAndExecutionContext(dto);
 
     }
 
+
     //endregion
 
     //region > debug, toString
@@ -713,26 +636,8 @@ public class ObjectActionDefault extends ObjectMemberAbstract implements ObjectA
 
     //endregion
 
+    //region > services (lookup)
 
-    private static Object unwrap(final ObjectAdapter adapter) {
-        return adapter == null ? null : adapter.getObject();
-    }
-
-    private <T> T lookupService(final Class<T> serviceClass) {
-        return getServicesInjector().lookupService(serviceClass);
-    }
-
-    protected CommandContext getCommandContext() {
-        CommandContext commandContext = lookupService(CommandContext.class);
-        if (commandContext == null) {
-            throw new IllegalStateException("The CommandContext service is not registered!");
-        }
-        return commandContext;
-    }
-
-    protected CommandMementoService getCommandMementoService() {
-        return lookupService(CommandMementoService.class);
-    }
 
     protected Bulk.InteractionContext getBulkInteractionContext() {
         return lookupService(Bulk.InteractionContext.class);
@@ -742,5 +647,7 @@ public class ObjectActionDefault extends ObjectMemberAbstract implements ObjectA
         return lookupService(org.apache.isis.applib.services.actinvoc.ActionInvocationContext.class);
     }
 
+    //endregion
+
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/07342da5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java
----------------------------------------------------------------------
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 4467827..5fc4333 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
@@ -27,6 +27,9 @@ import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.annotation.When;
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.applib.filter.Filter;
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.applib.services.command.Command;
+import org.apache.isis.applib.services.command.CommandContext;
 import org.apache.isis.core.commons.lang.StringExtensions;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.consent.Consent;
@@ -37,6 +40,8 @@ import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.MultiTypedFacet;
 import org.apache.isis.core.metamodel.facets.FacetedMethod;
+import org.apache.isis.core.metamodel.facets.actions.action.invocation.CommandUtil;
+import org.apache.isis.core.metamodel.facets.actions.command.CommandFacet;
 import org.apache.isis.core.metamodel.facets.all.describedas.DescribedAsFacet;
 import org.apache.isis.core.metamodel.facets.all.help.HelpFacet;
 import org.apache.isis.core.metamodel.facets.all.hide.HiddenFacet;
@@ -51,11 +56,14 @@ import org.apache.isis.core.metamodel.interactions.UsabilityContext;
 import org.apache.isis.core.metamodel.interactions.VisibilityContext;
 import org.apache.isis.core.metamodel.runtimecontext.PersistenceSessionService;
 import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
+import org.apache.isis.core.metamodel.services.command.CommandMementoService;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.SpecificationLoader;
 import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
 import org.apache.isis.core.metamodel.spec.feature.ObjectMemberDependencies;
 import org.apache.isis.core.metamodel.specloader.collectiontyperegistry.CollectionTypeRegistry;
+import org.apache.isis.schema.cmd.v1.CommandMementoDto;
+import org.apache.isis.schema.utils.CommandMementoDtoUtils;
 
 public abstract class ObjectMemberAbstract implements ObjectMember {
 
@@ -384,6 +392,102 @@ public abstract class ObjectMemberAbstract implements ObjectMember {
         return collectionTypeRegistry;
     }
 
+    protected <T> T lookupService(final Class<T> serviceClass) {
+        return getServicesInjector().lookupService(serviceClass);
+    }
+
+    protected CommandContext getCommandContext() {
+        CommandContext commandContext = lookupService(CommandContext.class);
+        if (commandContext == null) {
+            throw new IllegalStateException("The CommandContext service is not registered!");
+        }
+        return commandContext;
+    }
+
+    protected CommandMementoService getCommandMementoService() {
+        return lookupService(CommandMementoService.class);
+    }
+
+    //endregion
+
+    //region > command (setup)
+
+
+    protected void setupCommandTarget(final ObjectAdapter targetAdapter, final String arguments) {
+        final CommandContext commandContext = getCommandContext();
+        final Command command = commandContext.getCommand();
+
+        if (command.getExecutor() != Command.Executor.USER) {
+            return;
+        }
+
+        if(command.getTarget() != null) {
+            // already set up by a ObjectActionContributee or edit form; don't overwrite
+            return;
+        }
+
+        command.setTargetClass(CommandUtil.targetClassNameFor(targetAdapter));
+        command.setTargetAction(CommandUtil.targetActionNameFor(this));
+        command.setArguments(arguments);
+
+        final Bookmark targetBookmark = CommandUtil.bookmarkFor(targetAdapter);
+        command.setTarget(targetBookmark);
+    }
+
+    protected void setupCommandMemberIdentifier() {
+
+        final CommandContext commandContext = getCommandContext();
+        final Command command = commandContext.getCommand();
+
+        if (command.getExecutor() != Command.Executor.USER) {
+            return;
+        }
+
+        if (command.getMemberIdentifier() != null) {
+            // any contributed/mixin actions will fire after the main action
+            // the guard here prevents them from trashing the command's memberIdentifier
+            return;
+        }
+
+        command.setMemberIdentifier(CommandUtil.actionIdentifierFor(this));
+    }
+
+    protected void setupCommandMementoAndExecutionContext(final CommandMementoDto dto) {
+        final CommandContext commandContext = getCommandContext();
+        final Command command = commandContext.getCommand();
+
+        if (command.getExecutor() != Command.Executor.USER) {
+            return;
+        }
+
+        if(Command.ACTION_IDENTIFIER_FOR_EDIT.equals(command.getMemberIdentifier())) {
+            // special case for edit properties, don't overwrite
+            return;
+        }
+
+        if (command.getMemento() != null) {
+            // guard here to prevent subsequent contributed/mixin actions from
+            // trampling over the command's memento and execution context
+            return;
+        }
+
+        // memento
+
+        final String mementoXml = CommandMementoDtoUtils.toXml(dto);
+        command.setMemento(mementoXml);
+
+        // copy over the command execution 'context' (if available)
+        final CommandFacet commandFacet = getFacetHolder().getFacet(CommandFacet.class);
+        if(commandFacet != null && !commandFacet.isDisabled()) {
+            command.setExecuteIn(commandFacet.executeIn());
+            command.setPersistence(commandFacet.persistence());
+        } else {
+            // if no facet, assume do want to execute right now, but only persist (eventually) if hinted.
+            command.setExecuteIn(org.apache.isis.applib.annotation.Command.ExecuteIn.FOREGROUND);
+            command.setPersistence(org.apache.isis.applib.annotation.Command.Persistence.IF_HINTED);
+        }
+    }
+
     //endregion
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/07342da5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationDefault.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationDefault.java
index 8089ca4..ef6acbd 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationDefault.java
@@ -33,6 +33,7 @@ import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.consent.InteractionResult;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facets.FacetedMethod;
+import org.apache.isis.core.metamodel.facets.actions.action.invocation.CommandUtil;
 import org.apache.isis.core.metamodel.facets.objectvalue.mandatory.MandatoryFacet;
 import org.apache.isis.core.metamodel.facets.param.autocomplete.MinLengthUtil;
 import org.apache.isis.core.metamodel.facets.propcoll.accessor.PropertyOrCollectionAccessorFacet;
@@ -50,10 +51,12 @@ import org.apache.isis.core.metamodel.interactions.PropertyVisibilityContext;
 import org.apache.isis.core.metamodel.interactions.UsabilityContext;
 import org.apache.isis.core.metamodel.interactions.ValidityContext;
 import org.apache.isis.core.metamodel.interactions.VisibilityContext;
+import org.apache.isis.core.metamodel.services.command.CommandMementoService;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.MutableCurrentHolder;
 import org.apache.isis.core.metamodel.spec.feature.ObjectMemberDependencies;
 import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+import org.apache.isis.schema.cmd.v1.CommandMementoDto;
 
 public class OneToOneAssociationDefault extends ObjectAssociationAbstract implements OneToOneAssociation {
 
@@ -209,7 +212,7 @@ public class OneToOneAssociationDefault extends ObjectAssociationAbstract implem
             // TODO: move to facet ?
             throw new IsisException("can't set a reference to a transient object from a persistent one: " + newReferencedAdapter.titleString(null) + " (transient)");
         }
-        setterFacet.setProperty(ownerAdapter, newReferencedAdapter, interactionInitiatedBy);
+        setterFacet.setProperty(this, ownerAdapter, newReferencedAdapter, interactionInitiatedBy);
     }
 
     /**
@@ -223,6 +226,7 @@ public class OneToOneAssociationDefault extends ObjectAssociationAbstract implem
         clearValue(ownerAdapter, interactionInitiatedBy);
     }
 
+
     private void clearValue(
             final ObjectAdapter ownerAdapter,
             final InteractionInitiatedBy interactionInitiatedBy) {
@@ -320,6 +324,41 @@ public class OneToOneAssociationDefault extends ObjectAssociationAbstract implem
 
     //endregion
 
+    /**
+     * Internal API
+     */
+    @Override
+    public void setupCommand(
+            final ObjectAdapter targetAdapter,
+            final ObjectAdapter valueAdapter) {
+
+        setupCommandTarget(targetAdapter, valueAdapter);
+        setupCommandMemberIdentifier();
+        setupCommandMementoAndExecutionContext(targetAdapter, valueAdapter);
+    }
+
+    protected void setupCommandTarget(
+            final ObjectAdapter targetAdapter,
+            final ObjectAdapter valueAdapter) {
+
+        final String arguments = CommandUtil.argDescriptionFor(valueAdapter);
+
+        setupCommandTarget(targetAdapter, arguments);
+    }
+
+    protected void setupCommandMementoAndExecutionContext(
+            final ObjectAdapter targetAdapter,
+            final ObjectAdapter valueAdapter) {
+
+        final CommandMementoService commandMementoService = getCommandMementoService();
+        final CommandMementoDto dto = commandMementoService.asCommandMemento(targetAdapter, this, valueAdapter);
+
+        setupCommandMementoAndExecutionContext(dto);
+
+    }
+
+
+
     //region > debug, toString
     @Override
     public String debugData() {

http://git-wip-us.apache.org/repos/asf/isis/blob/07342da5/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactoryTest.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactoryTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactoryTest.java
index a0024d1..d644a0a 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactoryTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactoryTest.java
@@ -78,6 +78,7 @@ import org.apache.isis.core.metamodel.facets.objectvalue.mandatory.MandatoryFace
 import org.apache.isis.core.metamodel.facets.objectvalue.maxlen.MaxLengthFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.mustsatisfyspec.MustSatisfySpecificationFacet;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
 
 import static org.apache.isis.core.commons.matchers.IsisMatchers.classEqualTo;
 import static org.hamcrest.CoreMatchers.is;
@@ -144,7 +145,7 @@ public class PropertyAnnotationFacetFactoryTest extends AbstractFacetFactoryJUni
             FacetUtil.addFacet(new PropertySetterFacetAbstract(holder) {
                 @Override
                 public void setProperty(
-                        final ObjectAdapter inObject,
+                        final OneToOneAssociation owningAssociation, final ObjectAdapter inObject,
                         final ObjectAdapter value,
                         final InteractionInitiatedBy interactionInitiatedBy) {
                 }

http://git-wip-us.apache.org/repos/asf/isis/blob/07342da5/core/runtime/src/main/java/org/apache/isis/core/runtime/services/command/CommandMementoServiceDefault.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/command/CommandMementoServiceDefault.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/command/CommandMementoServiceDefault.java
index 3b3be55..8db796c 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/command/CommandMementoServiceDefault.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/command/CommandMementoServiceDefault.java
@@ -42,12 +42,13 @@ import org.apache.isis.core.metamodel.spec.SpecificationLoaderSpi;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
 import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
-import org.apache.isis.core.metamodel.specloader.specimpl.ObjectActionMixedIn;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
 import org.apache.isis.core.metamodel.specloader.specimpl.dflt.ObjectSpecificationDefault;
 import org.apache.isis.core.runtime.services.memento.MementoServiceDefault;
 import org.apache.isis.core.runtime.system.context.IsisContext;
 import org.apache.isis.schema.cmd.v1.ActionDto;
 import org.apache.isis.schema.cmd.v1.CommandMementoDto;
+import org.apache.isis.schema.cmd.v1.ParamDto;
 import org.apache.isis.schema.utils.CommandMementoDtoUtils;
 
 /**
@@ -158,6 +159,28 @@ public class CommandMementoServiceDefault implements CommandMementoService {
         final ActionDto actionDto = new ActionDto();
         dto.setAction(actionDto);
 
+        addActionArgs(objectAction, actionDto, argAdapters);
+
+        dto.setTransactionId(UUID.randomUUID().toString());
+        return dto;
+    }
+
+    @Override
+    public CommandMementoDto asCommandMemento(
+            final ObjectAdapter targetAdapter,
+            final OneToOneAssociation association,
+            final ObjectAdapter valueAdapter) {
+
+        // TODO.  introduce a choice for aim vs pmm, in the cmd.xsd
+
+        throw new RuntimeException("not yet implemented");
+    }
+
+    @Override
+    public void addActionArgs(
+            final ObjectAction objectAction,
+            final ActionDto actionDto,
+            final ObjectAdapter[] argAdapters) {
         final String actionIdentifier = CommandUtil.actionIdentifierFor(objectAction);
         actionDto.setActionIdentifier(actionIdentifier);
 
@@ -166,16 +189,14 @@ public class CommandMementoServiceDefault implements CommandMementoService {
             final ObjectActionParameter actionParameter = actionParameters.get(paramNum);
             final String parameterName = actionParameter.getName();
             final Class<?> paramType = actionParameter.getSpecification().getCorrespondingClass();
-            ObjectAdapter argAdapter = argAdapters[paramNum];
+            final ObjectAdapter argAdapter = argAdapters[paramNum];
             final Object arg = argAdapter != null? argAdapter.getObject(): null;
-            CommandMementoDtoUtils.addParamArg(actionDto.getParameters(), parameterName, paramType, arg, bookmarkService);
+            final List<ParamDto> parameters = actionDto.getParameters();
+            CommandMementoDtoUtils.addParamArg(
+                    parameters, parameterName, paramType, arg, bookmarkService);
         }
-
-        dto.setTransactionId(UUID.randomUUID().toString());
-        return dto;
     }
 
-
     // //////////////////////////////////////
 
 

http://git-wip-us.apache.org/repos/asf/isis/blob/07342da5/core/runtime/src/main/java/org/apache/isis/core/runtime/services/publishing/PublishingServiceInternalDefault.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/publishing/PublishingServiceInternalDefault.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/publishing/PublishingServiceInternalDefault.java
index c19c494..cb8125a 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/publishing/PublishingServiceInternalDefault.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/publishing/PublishingServiceInternalDefault.java
@@ -39,6 +39,7 @@ import org.apache.isis.applib.annotation.PublishedAction;
 import org.apache.isis.applib.annotation.PublishedObject;
 import org.apache.isis.applib.annotation.PublishedObject.ChangeKind;
 import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.applib.services.bookmark.BookmarkService;
 import org.apache.isis.applib.services.clock.ClockService;
 import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.applib.services.command.CommandContext;
@@ -62,13 +63,17 @@ import org.apache.isis.core.metamodel.facets.actions.action.invocation.CommandUt
 import org.apache.isis.core.metamodel.facets.actions.publish.PublishedActionFacet;
 import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
 import org.apache.isis.core.metamodel.facets.object.publishedobject.PublishedObjectFacet;
+import org.apache.isis.core.metamodel.services.command.CommandMementoService;
 import org.apache.isis.core.metamodel.services.publishing.PublishingServiceInternal;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.runtime.services.enlist.EnlistedObjectsServiceInternal;
 import org.apache.isis.core.runtime.system.context.IsisContext;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
 import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
 import org.apache.isis.schema.aim.v2.ActionInvocationMementoDto;
+import org.apache.isis.schema.aim.v2.ReturnDto;
+import org.apache.isis.schema.cmd.v1.ActionDto;
 import org.apache.isis.schema.utils.ActionInvocationMementoDtoUtils;
 
 /**
@@ -169,6 +174,7 @@ public class PublishingServiceInternalDefault implements PublishingServiceIntern
 
     @Programmatic
     public void publishAction(
+            final Interaction.Execution execution,
             final ObjectAction objectAction,
             final IdentifiedHolder identifiedHolder,
             final ObjectAdapter targetAdapter,
@@ -176,10 +182,12 @@ public class PublishingServiceInternalDefault implements PublishingServiceIntern
             final ObjectAdapter resultAdapter) {
 
         publishActionToPublishingService(
-                objectAction, identifiedHolder, targetAdapter, parameterAdapters, resultAdapter);
+                objectAction, identifiedHolder, targetAdapter, parameterAdapters, resultAdapter
+        );
 
         publishActionToPublisherServices(
-                objectAction, identifiedHolder, targetAdapter, parameterAdapters, resultAdapter);
+                objectAction, identifiedHolder, targetAdapter, parameterAdapters, resultAdapter,
+                execution);
 
     }
 
@@ -187,7 +195,8 @@ public class PublishingServiceInternalDefault implements PublishingServiceIntern
             final ObjectAction objectAction,
             final IdentifiedHolder identifiedHolder,
             final ObjectAdapter targetAdapter,
-            final List<ObjectAdapter> parameterAdapters, final ObjectAdapter resultAdapter) {
+            final List<ObjectAdapter> parameterAdapters,
+            final ObjectAdapter resultAdapter) {
         if(publishingServiceIfAny == null) {
             return;
         }
@@ -315,10 +324,8 @@ public class PublishingServiceInternalDefault implements PublishingServiceIntern
             final IdentifiedHolder identifiedHolder,
             final ObjectAdapter targetAdapter,
             final List<ObjectAdapter> parameterAdapters,
-            final ObjectAdapter resultAdapter) {
-
-        final Interaction interaction = interactionContext.getInteraction();
-        final Interaction.Execution execution = interaction.getPriorExecution();
+            final ObjectAdapter resultAdapter,
+            final Interaction.Execution execution) {
 
         if(publisherServices == null || publisherServices.isEmpty()) {
             return;
@@ -330,29 +337,45 @@ public class PublishingServiceInternalDefault implements PublishingServiceIntern
         final int nextEventSequence = command.next(sequenceName.abbr());
         final UUID transactionId = command.getTransactionId();
 
-        final String actionMemberIdentifier = CommandUtil.actionIdentifierFor(objectAction);
-        final Bookmark actionTarget = CommandUtil.bookmarkFor(targetAdapter);
+        final Object targetPojo = execution.getMemberArgs().getTarget();
+        final Bookmark targetBookmark = bookmarkService.bookmarkFor(targetPojo);
 
-        final RootOid adapterOid = (RootOid) targetAdapter.getOid();
-        final String oidStr = getOidMarshaller().marshal(adapterOid);
-        final Identifier actionIdentifier = objectAction.getIdentifier();
+        final String actionClassNameId = execution.getMemberArgs().getMemberId();
+        final String actionId = actionClassNameId.substring(actionClassNameId.indexOf('#')+1);
 
-        final String title = oidStr + ": " + actionIdentifier.toNameParmsIdentityString();
+        final String title = targetBookmark.toString() + ": " + actionId;
 
         final String currentUser = userService.getUser().getName();
-        final Timestamp timestamp = clockService.nowAsJavaSqlTimestamp();
+        final Timestamp startedAt = execution.getStartedAt();
+        final Timestamp completedAt = execution.getCompletedAt();
+
+        final ActionDto actionDto = new ActionDto();
+        commandMementoService.addActionArgs(
+                objectAction, actionDto, parameterAdapters.toArray(new ObjectAdapter[]{}));
+
+        final ObjectSpecification returnSpec = objectAction.getReturnType();
+
+
+        final Class<?> returnType = returnSpec.getCorrespondingClass();
+        final ObjectAdapter argAdapter = resultAdapter;
+        final Object resultPojo = argAdapter != null? argAdapter.getObject(): null;
+
+        final ReturnDto returnDto = new ReturnDto();
+        ActionInvocationMementoDtoUtils.setValue(returnDto, returnType, resultPojo);
 
         for (PublisherService publisherService : publisherServices) {
             final ActionInvocationMementoDto aimDto =
                 ActionInvocationMementoDtoUtils.newDto(
                         transactionId,
                         nextEventSequence,
-                        actionMemberIdentifier,
-                        actionTarget,
-                        title,
+                        targetBookmark,
+                        actionDto, title,
                         currentUser,
-                        timestamp
-                );
+                        startedAt, completedAt,
+                        returnDto);
+
+            ActionInvocationMementoDtoUtils.addReturn(aimDto, returnType, resultPojo, bookmarkService);
+
             publisherService.publish(aimDto);
         }
     }
@@ -370,6 +393,12 @@ public class PublishingServiceInternalDefault implements PublishingServiceIntern
     private PublishingService publishingServiceIfAny;
 
     @Inject
+    CommandMementoService commandMementoService;
+
+    @Inject
+    private BookmarkService bookmarkService;
+
+    @Inject
     private EnlistedObjectsServiceInternal enlistedObjectsServiceInternal;
 
     @Inject