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/13 18:14:07 UTC

[25/50] [abbrv] isis git commit: ISIS-1389: removing differences between Dtos and Interaction: collapsing MemberArgs and Interaction.

ISIS-1389: removing differences between Dtos and Interaction: collapsing MemberArgs and Interaction.


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

Branch: refs/heads/master
Commit: 501fcb827a1b1f0a880cb30a7e5f152425b00d78
Parents: 2249764
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Wed May 4 00:17:07 2016 +0100
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Wed May 4 00:17:20 2016 +0100

----------------------------------------------------------------------
 .../isis/applib/services/iactn/Interaction.java | 296 +++++++++----------
 .../isis/schema/utils/InteractionDtoUtils.java  |   9 +-
 ...onInvocationFacetForDomainEventAbstract.java |  63 ++--
 ...etterOrClearFacetForDomainEventAbstract.java |  50 +++-
 .../ixn/InteractionDtoServiceInternal.java      |  12 +-
 .../background/BackgroundCommandExecution.java  |   4 +-
 .../InteractionDtoServiceInternalDefault.java   |  31 +-
 7 files changed, 256 insertions(+), 209 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/501fcb82/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 7cdd78d..3479eaf 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
@@ -35,10 +35,15 @@ import org.apache.isis.applib.services.HasTransactionId;
 import org.apache.isis.applib.services.clock.ClockService;
 import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.applib.services.eventbus.AbstractDomainEvent;
+import org.apache.isis.applib.services.eventbus.ActionDomainEvent;
 import org.apache.isis.applib.services.eventbus.EventBusService;
+import org.apache.isis.applib.services.eventbus.PropertyDomainEvent;
 import org.apache.isis.applib.services.wrapper.WrapperFactory;
+import org.apache.isis.schema.common.v1.InteractionType;
 import org.apache.isis.schema.common.v1.PeriodDto;
+import org.apache.isis.schema.ixn.v1.ActionInvocationDto;
 import org.apache.isis.schema.ixn.v1.InteractionExecutionDto;
+import org.apache.isis.schema.ixn.v1.PropertyModificationDto;
 import org.apache.isis.schema.utils.jaxbadapters.JavaSqlTimestampXmlGregorianCalendarAdapter;
 
 /**
@@ -100,104 +105,41 @@ public class Interaction implements HasTransactionId {
      * by which the framework actually performs the interaction.
      * @param <T>
      */
-    public interface MemberCallable<T extends MemberArgs> {
-        Object call(final Execution currentExecution, final T args);
+    public interface MemberExecutor<T extends Execution> {
+        Object execute(final T currentExecution);
     }
 
-    public static abstract class MemberArgs {
 
-        private final String memberId;
-
-        enum Type {
-            PROPERTY,
-            ACTION
-        }
-
-        private final Object target;
-        private final Type type;
-
-        protected MemberArgs(
-                final Type type,
-                final String memberId,
-                final Object target) {
-            this.memberId = memberId;
-            this.target = target;
-            this.type = type;
-        }
-
-        public String getMemberId() {
-            return memberId;
-        }
-
-        public Object getTarget() {
-            return target;
-        }
-
-        public Type getType() {
-            return type;
-        }
-    }
-
-
-    public static class ActionArgs extends MemberArgs {
-        private final List<Object> args;
-
-        public ActionArgs(
-                final String actionId,
-                final Object target,
-                final List<Object> args) {
-            super(Type.ACTION, actionId, target);
-            this.args = args;
-        }
 
-        public List<Object> getArgs() {
-            return args;
-        }
-    }
-
-    public static class PropertyArgs extends MemberArgs {
-        private final Object argValue;
-
-        public PropertyArgs(
-                final String propertyId, final Object target,
-                final Object argValue) {
-            super(Type.PROPERTY, propertyId, target);
-            this.argValue = argValue;
-        }
-
-        public Object getArgValue() {
-            return argValue;
-        }
-    }
-
-    public <T> T execute(
-            final MemberCallable memberCallable,
-            final ActionArgs actionArgs,
+    public Object execute(
+            final MemberExecutor<ActionInvocation> memberExecutor,
+            final ActionInvocation actionInvocation,
             final ClockService clockService,
             final Command command) {
 
-        final Execution execution = push(actionArgs, clockService, command);
+        pushAndUpdateCommand(actionInvocation, clockService, command);
 
-        return execute(memberCallable, actionArgs, clockService, execution);
+        return execute(memberExecutor, actionInvocation, clockService);
     }
 
-    public <T> T execute(
-            final MemberCallable memberCallable,
-            final PropertyArgs propertyArgs,
+    public Object execute(
+            final MemberExecutor<PropertyModification> memberExecutor,
+            final PropertyModification propertyModification,
             final ClockService clockService,
             final Command command) {
 
-        final Execution execution = push(propertyArgs, clockService, command);
-        return execute(memberCallable, propertyArgs, clockService, execution);
+        pushAndUpdateCommand(propertyModification, clockService, command);
+        return execute(memberExecutor, propertyModification, clockService);
     }
 
 
-    private Execution push(
-            final MemberArgs memberArgs,
+    private Execution pushAndUpdateCommand(
+            final Execution execution,
             final ClockService clockService,
             final Command command) {
+
         final Timestamp startedAt = clockService.nowAsJavaSqlTimestamp();
-        final Execution execution = push(startedAt, memberArgs);
+        push(startedAt, execution);
 
         if(command.getStartedAt() == null) {
             command.setStartedAt(startedAt);
@@ -206,29 +148,27 @@ public class Interaction implements HasTransactionId {
     }
 
 
-    private <T> T execute(
-            final MemberCallable memberCallable,
-            final MemberArgs memberArgs,
-            final ClockService clockService,
-            final Execution currentExecution) {
+    private <T extends Execution> Object execute(
+            final MemberExecutor<T> memberExecutor,
+            final T execution,
+            final ClockService clockService) {
 
         // as a convenience, since in all cases we want the command to start when the first interaction executes,
         // we populate the command here.
 
         try {
             try {
-                Object result = memberCallable.call(currentExecution, memberArgs);
-                currentExecution.setReturned(result);
-                return (T)result;
-            } catch (Exception e) {
+                Object result = memberExecutor.execute(execution);
+                execution.setReturned(result);
+                return result;
+            } catch (Exception ex) {
 
                 // just because an exception has thrown, does not mean it is that significant; it could be that
                 // it is recognized by an ExceptionRecognizer and is not severe, eg unique index violation in the DB.
-                RuntimeException re = e instanceof RuntimeException? (RuntimeException) e : new RuntimeException(e);
-                currentExecution.setThrew(re);
+                currentExecution.setThrew(ex);
 
                 // propagate (as in previous design); caller will need to trap and decide
-                throw re;
+                throw ex;
             }
         } finally {
             final Timestamp completedAt = clockService.nowAsJavaSqlTimestamp();
@@ -261,23 +201,23 @@ public class Interaction implements HasTransactionId {
      * </p>
      */
     @Programmatic
-    Execution push(final Timestamp startedAt, final MemberArgs memberArgs) {
+    private Execution push(final Timestamp startedAt, final Execution execution) {
 
-        final Execution newExecution;
         if(currentExecution == null) {
             // new top-level execution
-            newExecution = new Execution(memberArgs, startedAt);
-            executionGraphs.add(newExecution);
+            executionGraphs.add(execution);
 
         } else {
             // adds to graph of parent
-            newExecution = new Execution(memberArgs, startedAt, currentExecution);
+            execution.setParent(currentExecution);
         }
 
-        // set
-        moveCurrentTo(newExecution);
+        execution.setStartedAt(startedAt);
 
-        return currentExecution;
+        // update this.currentExecution and this.previousExecution
+        moveCurrentTo(execution);
+
+        return execution;
     }
 
     /**
@@ -290,9 +230,9 @@ public class Interaction implements HasTransactionId {
      * @param completedAt
      */
     @Programmatic
-    Execution pop(final Timestamp completedAt) {
+    private Execution pop(final Timestamp completedAt) {
         if(currentExecution == null) {
-            throw new IllegalStateException("No current execution graph to pop");
+            throw new IllegalStateException("No current execution to pop");
         }
         final Execution popped = currentExecution;
         popped.setCompletedAt(completedAt);
@@ -307,8 +247,7 @@ public class Interaction implements HasTransactionId {
     }
 
     /**
-     * Returns a (list of) graph(es) indicating the domain events in the order that they were
-     * {@link #push(Timestamp, MemberArgs pushed}.
+     * Returns a (list of) graph(es) indicating the domain events in the order that they were pushed.
      *
      * <p>
      *     Each {@link Execution} represents a call stack of domain events (action invocations or property edits),
@@ -325,7 +264,7 @@ public class Interaction implements HasTransactionId {
     /**
      * <b>NOT API</b>: intended to be called only by the framework.
      *
-     * Clears the set of {@link AbstractDomainEvent}s that have been {@link #push(Timestamp, MemberArgs push)}ed.
+     * Clears the set of {@link Execution}s that may have been {@link #push(Timestamp, Execution)}ed.
      */
     @Programmatic
     public void clear() {
@@ -376,40 +315,59 @@ public class Interaction implements HasTransactionId {
      * Represents an action invocation/property edit as a node in a call-stack execution graph, with sub-interactions
      * being made by way of the {@link WrapperFactory}).
      */
-    public static class Execution {
+    public static class Execution<T extends InteractionExecutionDto, E extends AbstractDomainEvent<?>> {
 
         //region > fields, constructor
-        private final Timestamp startedAt;
-        private final MemberArgs memberArgs;
-        private final Execution parent;
-        private final List<Execution> children = Lists.newArrayList();
+
+        private final String memberId;
+        private final Object target;
+        private final InteractionType interactionType;
 
         public Execution(
-                final MemberArgs memberArgs, final Timestamp startedAt) {
-            this.startedAt = startedAt;
-            this.memberArgs = memberArgs;
-            this.parent = null;
+                final InteractionType interactionType,
+                final String memberId,
+                final Object target) {
+            this.interactionType = interactionType;
+            this.memberId = memberId;
+            this.target = target;
         }
+        //endregion
 
-        public Execution(
-                final MemberArgs memberArgs, final Timestamp startedAt, final Execution parent) {
-            this.startedAt = startedAt;
-            this.parent = parent;
-            this.memberArgs = memberArgs;
-            parent.children.add(this);
+        //region > via constructor: interactionType, memberId, target
+
+        public InteractionType getInteractionType() {
+            return interactionType;
+        }
+
+        public String getMemberId() {
+            return memberId;
         }
+
+        public Object getTarget() {
+            return target;
+        }
+
         //endregion
 
-        //region > parent
+        //region > parent, children
+
+        private final List<Execution> children = Lists.newArrayList();
+        private Execution parent;
+
         /**
          * The action/property that invoked this action/property edit (if any).
          */
         public Execution getParent() {
             return parent;
         }
-        //endregion
 
-        //region > children
+        public void setParent(final Execution parent) {
+            this.parent = parent;
+            if(parent != null) {
+                parent.children.add(this);
+            }
+        }
+
         /**
          * The actions/property edits made in turn via the {@link WrapperFactory}.
          */
@@ -418,33 +376,36 @@ public class Interaction implements HasTransactionId {
         }
         //endregion
 
-        //region > memberArgs
-        public MemberArgs getMemberArgs() {
-            return memberArgs;
-        }
-        //endregion
 
         //region > event
 
-        private AbstractDomainEvent<?> event;
+        private E event;
         /**
          * The domain event fired on the {@link EventBusService event bus} representing the execution of
          * this action invocation/property edit.
+         *
+         * <p>
+         *     This event field is called by the framework before the action invocation/property edit itself;
+         *     if read by the executing action/property edit method it will be in the
+         *     {@link AbstractDomainEvent.Phase#EXECUTING executing} phase.
+         * </p>
          */
-        public AbstractDomainEvent<?> getEvent() {
+        public E getEvent() {
             return event;
         }
 
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          */
-        public void setEvent(final AbstractDomainEvent<?> event) {
+        public void setEvent(final E event) {
             this.event = event;
         }
         //endregion
 
-        //region > startedAt
+        //region > startedAt, completedAt
 
+        private Timestamp startedAt;
+        private Timestamp completedAt;
 
         /**
          * The date/time at which this execution started.
@@ -453,12 +414,11 @@ public class Interaction implements HasTransactionId {
             return startedAt;
         }
 
+        public void setStartedAt(final Timestamp startedAt) {
+            this.startedAt = startedAt;
+            syncMetrics();
+        }
 
-        //endregion
-
-        //region > completedAt
-
-        private Timestamp completedAt;
 
         /**
          * The date/time at which this execution completed.
@@ -470,14 +430,14 @@ public class Interaction implements HasTransactionId {
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          */
-        void setCompletedAt(Timestamp completedAt) {
+        void setCompletedAt(final Timestamp completedAt) {
             this.completedAt = completedAt;
             syncMetrics();
         }
 
         //endregion
 
-        //region > returned (property)
+        //region > returned, threw (properties)
 
         private Object returned;
         /**
@@ -502,20 +462,16 @@ public class Interaction implements HasTransactionId {
             this.returned = returned;
         }
 
-        //endregion
-
-        //region > threw (property)
-
-        private RuntimeException threw;
+        private Exception threw;
         @Programmatic
-        public RuntimeException getThrew() {
+        public Exception getThrew() {
             return threw;
         }
 
         /**
          * <b>NOT API</b>: intended to be called only by the framework.
          */
-        public void setThrew(RuntimeException threw) {
+        public void setThrew(Exception threw) {
             this.threw = threw;
         }
 
@@ -524,16 +480,25 @@ public class Interaction implements HasTransactionId {
 
         //region > dto (property)
 
-        private InteractionExecutionDto dto;
+        private T dto;
 
-        public InteractionExecutionDto getDto() {
+        /**
+         * A serializable representation of this action invocation/property edit.
+         *
+         * <p>
+         *     This <i>will</i> be populated (by the framework) during the method call itself (representing the
+         *     action invocation/property edit), though some fields ({@link Execution#getCompletedAt()},
+         *     {@link Execution#getReturned()}) will (obviously) still be null.
+         * </p>
+         */
+        public T getDto() {
             return dto;
         }
 
         /**
-         * Set by framework (implementation of {@link MemberCallable})
+         * Set by framework (implementation of {@link MemberExecutor})
          */
-        public void setDto(final InteractionExecutionDto executionDto) {
+        public void setDto(final T executionDto) {
             this.dto = executionDto;
             syncMetrics();
         }
@@ -561,4 +526,37 @@ public class Interaction implements HasTransactionId {
 
     }
 
+    public static class ActionInvocation extends Execution<ActionInvocationDto, ActionDomainEvent<?>> {
+
+        private final List<Object> args;
+
+        public ActionInvocation(
+                final String memberId,
+                final Object target,
+                final List<Object> args) {
+            super(InteractionType.ACTION_INVOCATION, memberId, target);
+            this.args = args;
+        }
+
+        public List<Object> getArgs() {
+            return args;
+        }
+    }
+
+    public static class PropertyModification extends Execution<PropertyModificationDto, PropertyDomainEvent<?,?>> {
+
+        private final Object newValue;
+
+        public PropertyModification(
+                final String memberId,
+                final Object target,
+                final Object newValue) {
+            super(InteractionType.PROPERTY_MODIFICATION, memberId, target);
+            this.newValue = newValue;
+        }
+
+        public Object getNewValue() {
+            return newValue;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/501fcb82/core/applib/src/main/java/org/apache/isis/schema/utils/InteractionDtoUtils.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/schema/utils/InteractionDtoUtils.java b/core/applib/src/main/java/org/apache/isis/schema/utils/InteractionDtoUtils.java
index 278467c..7572384 100644
--- a/core/applib/src/main/java/org/apache/isis/schema/utils/InteractionDtoUtils.java
+++ b/core/applib/src/main/java/org/apache/isis/schema/utils/InteractionDtoUtils.java
@@ -141,7 +141,7 @@ public final class InteractionDtoUtils {
 
         final InteractionExecutionDto executionDto = newActionInvocation(
                 sequence, targetBookmark, targetTitle,
-                actionIdentifier, parameterDtos, returnDto,
+                actionIdentifier, parameterDtos,
                 user, transactionId);
 
         addExecution(interactionDto, executionDto);
@@ -181,14 +181,13 @@ public final class InteractionDtoUtils {
             final String targetTitle,
             final String actionIdentifier,
             final List<ParamDto> parameterDtos,
-            final ValueWithTypeDto returnDto,
             final String user,
             final String transactionId) {
 
         return (ActionInvocationDto) newInteractionExecutionDto(
                 InteractionType.ACTION_INVOCATION, transactionId, sequence,
                 targetBookmark, targetTitle, actionIdentifier,
-                parameterDtos, returnDto, null,
+                parameterDtos, null,
                 user);
     }
 
@@ -203,7 +202,7 @@ public final class InteractionDtoUtils {
         return (PropertyModificationDto) newInteractionExecutionDto(
                 InteractionType.PROPERTY_MODIFICATION, transactionId, sequence,
                 targetBookmark, targetTitle, propertyIdentifier,
-                null, null, newValueDto,
+                null, newValueDto,
                 user);
     }
 
@@ -215,7 +214,6 @@ public final class InteractionDtoUtils {
             final String targetTitle,
             final String memberIdentifier,
             final List<ParamDto> parameterDtos,
-            final ValueWithTypeDto returnDto,
             final ValueWithTypeDto newValueDto,
             final String user) {
 
@@ -226,7 +224,6 @@ public final class InteractionDtoUtils {
 
             final ActionInvocationDto.Parameters parameters = invocation.getParameters();
             parameters.getParameter().addAll(parameterDtos);
-            invocation.setReturned(returnDto);
 
             executionDto = invocation;
         } else {

http://git-wip-us.apache.org/repos/asf/isis/blob/501fcb82/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 cc72d27..d89c8bc 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
@@ -173,7 +173,7 @@ public abstract class ActionInvocationFacetForDomainEventAbstract
 
         final String actionId = owningAction.getIdentifier().toClassAndNameIdentityString();
 
-        final ObjectAdapter resultAdapter;
+        final ObjectAdapter returnedAdapter;
         if( command.getExecutor() == Command.Executor.USER &&
             command.getExecuteIn() == org.apache.isis.applib.annotation.Command.ExecuteIn.BACKGROUND) {
 
@@ -186,7 +186,7 @@ public abstract class ActionInvocationFacetForDomainEventAbstract
                         "Unable to persist command for action '%s'; CommandService does not support persistent commands ",
                         actionId));
             }
-            resultAdapter = getAdapterManager().adapterFor(command);
+            returnedAdapter = getAdapterManager().adapterFor(command);
 
         } else {
 
@@ -194,17 +194,25 @@ public abstract class ActionInvocationFacetForDomainEventAbstract
             owningAction.setupActionInvocationContext(targetAdapter);
 
             final Object targetPojo = ObjectAdapter.Util.unwrap(targetAdapter);
-            final List<Object> argumentPojos = ObjectAdapter.Util.unwrap(Arrays.asList(argumentAdapters));
+            final List<ObjectAdapter> argumentAdapterList = Arrays.asList(argumentAdapters);
+            final List<Object> argumentPojos = ObjectAdapter.Util.unwrap(argumentAdapterList);
 
-            final Interaction.ActionArgs actionArgs = new Interaction.ActionArgs(actionId, targetPojo, argumentPojos);
-            final Interaction.MemberCallable callable = new Interaction.MemberCallable<Interaction.ActionArgs>() {
+            final Interaction.ActionInvocation execution =
+                    new Interaction.ActionInvocation(actionId, targetPojo, argumentPojos);
+            final Interaction.MemberExecutor<Interaction.ActionInvocation> callable =
+                    new Interaction.MemberExecutor<Interaction.ActionInvocation>() {
 
                 @Override
-                public Object call(
-                        final Interaction.Execution currentExecution,
-                        final Interaction.ActionArgs actionArgs) {
+                public Object execute(final Interaction.ActionInvocation currentExecution) {
 
                     try {
+
+                        // update the current execution with the DTO (memento)
+                        final ActionInvocationDto invocationDto =
+                                getInteractionDtoServiceInternal().asActionInvocationDto(
+                                        owningAction, targetAdapter, argumentAdapterList);
+                        currentExecution.setDto(invocationDto);
+
                         // ... post the executing event
                         final ActionDomainEvent<?> event =
                                 domainEventHelper.postEventForAction(
@@ -215,18 +223,14 @@ public abstract class ActionInvocationFacetForDomainEventAbstract
                                         command,
                                         null);
 
+                        // set event onto the execution
+                        currentExecution.setEvent(event);
 
+                        // invoke method
                         final Object resultPojo = invokeMethodElseFromCache(targetAdapter, argumentAdapters);
 
                         final ObjectAdapter resultAdapterPossiblyCloned = cloneIfViewModelCloneable(resultPojo, targetAdapter);
 
-                        // update the current execution with the DTO (memento)
-                        final List<ObjectAdapter> parameterAdapters = Arrays.asList(argumentAdapters);
-                        final ActionInvocationDto invocationDto =
-                                getInteractionDtoServiceInternal().asActionInvocationDto(
-                                        owningAction, targetAdapter, parameterAdapters, resultAdapterPossiblyCloned);
-
-                        currentExecution.setDto(invocationDto);
 
                         // ... post the executed event
                         domainEventHelper.postEventForAction(
@@ -271,19 +275,32 @@ public abstract class ActionInvocationFacetForDomainEventAbstract
                 }
             };
 
-            interaction.execute(callable, actionArgs, getClockService(), command);
-            final Interaction.Execution priorExecution = interaction.getPriorExecution();
+            // sets up startedAt and completedAt on the execution, also manages the execution call graph
+            interaction.execute(callable, execution, getClockService(), command);
+
+            // handle any exceptions
+            final Interaction.Execution<ActionInvocationDto, ?> priorExecution = interaction.getPriorExecution();
+
+            final Exception executionExceptionIfAny = priorExecution.getThrew();
+
+            // TODO: should also sync DTO's threw here...
 
-            final RuntimeException executionExceptionIfAny = priorExecution.getThrew();
             if(executionExceptionIfAny != null) {
-                throw executionExceptionIfAny;
+                throw executionExceptionIfAny instanceof RuntimeException
+                        ? ((RuntimeException)executionExceptionIfAny)
+                        : new RuntimeException(executionExceptionIfAny);
             }
 
-            resultAdapter = getAdapterManager().adapterFor(priorExecution.getReturned());
+
+            final Object returnedPojo = priorExecution.getReturned();
+            returnedAdapter = adapterManager.adapterFor(returnedPojo);
+
+            // sync DTO with result
+            getInteractionDtoServiceInternal().updateResult(priorExecution.getDto(), owningAction, returnedPojo);
 
 
             // update Command (if required)
-            setCommandResultIfEntity(command, resultAdapter);
+            setCommandResultIfEntity(command, returnedAdapter);
 
             final PublishedActionFacet publishedActionFacet = getIdentified().getFacet(PublishedActionFacet.class);
             if (publishedActionFacet != null) {
@@ -295,12 +312,12 @@ public abstract class ActionInvocationFacetForDomainEventAbstract
                         priorExecution,
                         owningAction, identifiedHolder,
                         targetAdapter, parameterAdapters,
-                        resultAdapter);
+                        returnedAdapter);
             }
         }
 
 
-        return filteredIfRequired(resultAdapter, interactionInitiatedBy);
+        return filteredIfRequired(returnedAdapter, interactionInitiatedBy);
     }
 
     private static String trim(String message, final int maxLen) {

http://git-wip-us.apache.org/repos/asf/isis/blob/501fcb82/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterOrClearFacetForDomainEventAbstract.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterOrClearFacetForDomainEventAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterOrClearFacetForDomainEventAbstract.java
index abe0ec8..83c8fbe 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterOrClearFacetForDomainEventAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/modify/PropertySetterOrClearFacetForDomainEventAbstract.java
@@ -40,7 +40,9 @@ import org.apache.isis.core.metamodel.facets.propcoll.accessor.PropertyOrCollect
 import org.apache.isis.core.metamodel.facets.properties.update.clear.PropertyClearFacet;
 import org.apache.isis.core.metamodel.facets.properties.update.modify.PropertySetterFacet;
 import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
+import org.apache.isis.core.metamodel.services.ixn.InteractionDtoServiceInternal;
 import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+import org.apache.isis.schema.ixn.v1.PropertyModificationDto;
 
 public abstract class PropertySetterOrClearFacetForDomainEventAbstract
         extends SingleValueFacetAbstract<Class<? extends PropertyDomainEvent<?,?>>> {
@@ -148,7 +150,7 @@ public abstract class PropertySetterOrClearFacetForDomainEventAbstract
 
     private void setOrClearProperty(
             final Style style,
-            final OneToOneAssociation owningAssociation,
+            final OneToOneAssociation owningProperty,
             final ObjectAdapter targetAdapter,
             final ObjectAdapter newValueAdapter,
             final InteractionInitiatedBy interactionInitiatedBy) {
@@ -162,13 +164,13 @@ public abstract class PropertySetterOrClearFacetForDomainEventAbstract
         final CommandContext commandContext = getCommandContext();
         final Command command = commandContext.getCommand();
 
-        owningAssociation.setupCommand(targetAdapter, newValueAdapter);
+        owningProperty.setupCommand(targetAdapter, newValueAdapter);
 
 
         final InteractionContext interactionContext = getInteractionContext();
         final Interaction interaction = interactionContext.getInteraction();
 
-        final String propertyId = owningAssociation.getIdentifier().toClassAndNameIdentityString();
+        final String propertyId = owningProperty.getIdentifier().toClassAndNameIdentityString();
 
         if( command.getExecutor() == Command.Executor.USER &&
                 command.getExecuteIn() == org.apache.isis.applib.annotation.Command.ExecuteIn.BACKGROUND) {
@@ -185,19 +187,25 @@ public abstract class PropertySetterOrClearFacetForDomainEventAbstract
 
         } else {
 
-            // otherwise, go ahead and execute action in the 'foreground'
-
             final Object target = ObjectAdapter.Util.unwrap(targetAdapter);
             final Object argValue = ObjectAdapter.Util.unwrap(newValueAdapter);
 
-            final Interaction.PropertyArgs propertyArgs = new Interaction.PropertyArgs(propertyId, target, argValue);
-            final Interaction.MemberCallable<?> callable = new Interaction.MemberCallable<Interaction.PropertyArgs>() {
-                        @Override public Object call(
-                                final Interaction.Execution currentExecution,
-                                final Interaction.PropertyArgs propertyArgs11) {
+            final Interaction.PropertyModification execution =
+                    new Interaction.PropertyModification(propertyId, target, argValue);
+            final Interaction.MemberExecutor<Interaction.PropertyModification> executor =
+                    new Interaction.MemberExecutor<Interaction.PropertyModification>() {
+                        @Override
+                        public Object execute(final Interaction.PropertyModification currentExecution) {
 
                             try {
 
+                                // update the current execution with the DTO (memento)
+                                final PropertyModificationDto invocationDto =
+                                        getInteractionDtoServiceInternal().asPropertyModificationDto(
+                                                owningProperty, targetAdapter, newValueAdapter);
+                                currentExecution.setDto(invocationDto);
+
+
                                 // ... post the executing event
                                 final Object oldValue = getterFacet.getProperty(targetAdapter, interactionInitiatedBy);
                                 final Object newValue = ObjectAdapter.Util.unwrap(newValueAdapter);
@@ -210,10 +218,15 @@ public abstract class PropertySetterOrClearFacetForDomainEventAbstract
                                                 oldValue, newValue);
 
 
-                                style.invoke(PropertySetterOrClearFacetForDomainEventAbstract.this, owningAssociation,
+                                // set event onto the execution
+                                currentExecution.setEvent(event);
+
+                                // invoke method
+                                style.invoke(PropertySetterOrClearFacetForDomainEventAbstract.this, owningProperty,
                                         targetAdapter, newValueAdapter, interactionInitiatedBy);
 
 
+
                                 // reading the actual value from the target object, playing it safe...
                                 final Object actualNewValue = getterFacet.getProperty(targetAdapter, interactionInitiatedBy);
                                 if (!Objects.equal(oldValue, actualNewValue)) {
@@ -239,13 +252,19 @@ public abstract class PropertySetterOrClearFacetForDomainEventAbstract
                         }
                     };
 
-            interaction.execute(callable, propertyArgs, getClockService(), command);
+            // sets up startedAt and completedAt on the execution, also manages the execution call graph
+            interaction.execute(executor, execution, getClockService(), command);
 
+            // handle any exceptions
             final Interaction.Execution priorExecution = interaction.getPriorExecution();
 
-            final RuntimeException executionExceptionIfAny = priorExecution.getThrew();
+            // TODO: should also sync DTO's threw here...
+
+            final Exception executionExceptionIfAny = priorExecution.getThrew();
             if(executionExceptionIfAny != null) {
-                throw executionExceptionIfAny;
+                throw executionExceptionIfAny instanceof RuntimeException
+                        ? ((RuntimeException)executionExceptionIfAny)
+                        : new RuntimeException(executionExceptionIfAny);
             }
 
             //
@@ -270,6 +289,9 @@ public abstract class PropertySetterOrClearFacetForDomainEventAbstract
     }
 
 
+    private InteractionDtoServiceInternal getInteractionDtoServiceInternal() {
+        return lookupService(InteractionDtoServiceInternal.class);
+    }
 
     private ServicesInjector getServicesInjector() {
         return servicesInjector;

http://git-wip-us.apache.org/repos/asf/isis/blob/501fcb82/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ixn/InteractionDtoServiceInternal.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ixn/InteractionDtoServiceInternal.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ixn/InteractionDtoServiceInternal.java
index 716ba9b..80f89ae 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ixn/InteractionDtoServiceInternal.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ixn/InteractionDtoServiceInternal.java
@@ -33,10 +33,16 @@ public interface InteractionDtoServiceInternal {
     ActionInvocationDto asActionInvocationDto(
             ObjectAction objectAction,
             ObjectAdapter targetAdapter,
-            List<ObjectAdapter> parameterAdapters,
-            ObjectAdapter resultAdapter);
+            List<ObjectAdapter> argumentAdapters);
 
-    @Programmatic PropertyModificationDto asPropertyModificationDto(
+    @Programmatic
+    ActionInvocationDto updateResult(
+            ActionInvocationDto actionInvocationDto,
+            ObjectAction objectAction,
+            Object resultPojo);
+
+    @Programmatic
+    PropertyModificationDto asPropertyModificationDto(
             OneToOneAssociation property,
             ObjectAdapter targetAdapter,
             ObjectAdapter newValueAdapterIfAny);

http://git-wip-us.apache.org/repos/asf/isis/blob/501fcb82/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java
index 4decd5b..923aac4 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java
@@ -227,8 +227,8 @@ public abstract class BackgroundCommandExecution extends AbstractIsisSessionTemp
                     // responsibility of auditing/profiling
                     backgroundCommand.setException(Throwables.getStackTraceAsString(e));
 
-                    // alternatively, could use...
-                    RuntimeException unused = backgroundInteraction.getPriorExecution().getThrew();
+                    // alternatively, could have used ...
+                    Exception unused = backgroundInteraction.getPriorExecution().getThrew();
 
                     backgroundInteraction.getCurrentExecution().setThrew(e);
                 }

http://git-wip-us.apache.org/repos/asf/isis/blob/501fcb82/core/runtime/src/main/java/org/apache/isis/core/runtime/services/ixn/InteractionDtoServiceInternalDefault.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/ixn/InteractionDtoServiceInternalDefault.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/ixn/InteractionDtoServiceInternalDefault.java
index 85b1830..733a252 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/ixn/InteractionDtoServiceInternalDefault.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/ixn/InteractionDtoServiceInternalDefault.java
@@ -54,8 +54,7 @@ public class InteractionDtoServiceInternalDefault implements InteractionDtoServi
     public ActionInvocationDto asActionInvocationDto(
             final ObjectAction objectAction,
             final ObjectAdapter targetAdapter,
-            final List<ObjectAdapter> parameterAdapters,
-            final ObjectAdapter resultAdapter) {
+            final List<ObjectAdapter> argumentAdapters) {
 
         final Command command = commandContext.getCommand();
         final UUID transactionId = command.getTransactionId();
@@ -74,15 +73,7 @@ public class InteractionDtoServiceInternalDefault implements InteractionDtoServi
 
         final ActionDto actionDto = new ActionDto();
         commandDtoServiceInternal.addActionArgs(
-                objectAction, actionDto, parameterAdapters.toArray(new ObjectAdapter[]{}));
-
-        final ObjectSpecification returnSpec = objectAction.getReturnType();
-
-        final Class<?> returnType = returnSpec.getCorrespondingClass();
-        final Object resultPojo = resultAdapter != null? resultAdapter.getObject(): null;
-
-        final ValueWithTypeDto returnDto = new ValueWithTypeDto();
-        InteractionDtoUtils.setValue(returnDto, returnType, resultPojo);
+                objectAction, actionDto, argumentAdapters.toArray(new ObjectAdapter[]{}));
 
         final String transactionIdStr = transactionId.toString();
 
@@ -90,11 +81,27 @@ public class InteractionDtoServiceInternalDefault implements InteractionDtoServi
         // InteractionDtoUtils.addReturn(invocationDto, returnType, resultPojo, bookmarkService);
         return InteractionDtoUtils.newActionInvocation(
                 nextEventSequence, targetBookmark, targetTitle,
-                actionDto.getMemberIdentifier(), actionDto.getParameters(), returnDto, currentUser,
+                actionDto.getMemberIdentifier(), actionDto.getParameters(), currentUser,
                 transactionIdStr);
     }
 
     @Override @Programmatic
+    public ActionInvocationDto updateResult(
+            final ActionInvocationDto actionInvocationDto,
+            final ObjectAction objectAction,
+            final Object resultPojo) {
+
+        final ObjectSpecification returnSpec = objectAction.getReturnType();
+
+        final Class<?> returnType = returnSpec.getCorrespondingClass();
+
+        final ValueWithTypeDto returnDto = new ValueWithTypeDto();
+        InteractionDtoUtils.setValue(returnDto, returnType, resultPojo);
+
+        return actionInvocationDto;
+    }
+
+    @Override @Programmatic
     public PropertyModificationDto asPropertyModificationDto(
             final OneToOneAssociation property,
             final ObjectAdapter targetAdapter,