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/01 10:17:08 UTC

[31/35] isis git commit: ISIS-1343: ActionDomainEvent now has a getMixedIn(), populated for mixin actions. Corresponding changes to the rest of the metamodel.

ISIS-1343: ActionDomainEvent now has a getMixedIn(),populated for mixin actions.  Corresponding changes to the rest of the metamodel.

Merging remote-tracking branch 'origin/ISIS-1343' into ISIS-1291

# Conflicts:
# core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionContributee.java
# core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionDefault.java
# core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
# core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java
# core/runtime/src/main/java/org/apache/isis/core/runtime/transaction/facets/ActionInvocationFacetWrapTransaction.java


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

Branch: refs/heads/ISIS-1291
Commit: 02dd0ee5936b8d1b0cedbd52ab4e9e63ffc3bd73
Parents: 497e762 0689936
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Sun May 1 07:31:23 2016 +0100
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Sun May 1 07:31:23 2016 +0100

----------------------------------------------------------------------
 .../services/eventbus/ActionDomainEvent.java    | 18 ++++++
 .../metamodel/facets/DomainEventHelper.java     | 11 +++-
 .../ActionDomainEventFacetAbstract.java         | 22 ++++++--
 .../invocation/ActionInvocationFacet.java       |  1 +
 ...onInvocationFacetForDomainEventAbstract.java |  7 ++-
 .../autocomplete/AutoCompleteFacetAbstract.java |  2 +-
 .../interactions/ActionArgumentContext.java     | 11 +++-
 .../interactions/ActionInteractionContext.java  | 31 +++++++++++
 .../interactions/ActionInvocationContext.java   | 11 +++-
 .../interactions/ActionUsabilityContext.java    | 12 +++-
 .../interactions/ActionVisibilityContext.java   | 12 +++-
 .../interactions/InteractionContext.java        | 12 ++++
 .../metamodel/spec/feature/ObjectAction.java    |  8 ++-
 .../specimpl/ObjectActionContributee.java       |  9 +--
 .../specimpl/ObjectActionDefault.java           | 58 ++++++++++++--------
 .../specimpl/ObjectActionMixedIn.java           | 39 +++++++++----
 .../specimpl/ObjectActionParameterAbstract.java |  3 +-
 .../OneToManyAssociationContributee.java        |  2 +-
 .../specimpl/OneToManyAssociationMixedIn.java   |  6 +-
 .../OneToOneActionParameterMixedIn.java         | 14 +++++
 .../OneToOneAssociationContributee.java         |  2 +-
 .../specimpl/OneToOneAssociationMixedIn.java    |  6 +-
 .../background/BackgroundCommandExecution.java  | 17 +++++-
 .../HomePageProviderServiceDefault.java         |  6 +-
 .../server/resources/DomainResourceHelper.java  | 11 ++--
 .../viewer/wicket/model/models/ActionModel.java |  4 +-
 .../collection/bulk/BulkActionsLinkFactory.java |  6 +-
 .../handlers/DomainObjectInvocationHandler.java |  9 ++-
 .../app/services/homepage/HomePageService.java  | 11 ++++
 29 files changed, 285 insertions(+), 76 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/02dd0ee5/core/applib/src/main/java/org/apache/isis/applib/services/eventbus/ActionDomainEvent.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/isis/blob/02dd0ee5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacet.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/isis/blob/02dd0ee5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/isis/blob/02dd0ee5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
----------------------------------------------------------------------
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
index cf50c4b,a532d28..aec5a1c
--- 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
@@@ -107,9 -109,12 +110,12 @@@ public interface ObjectAction extends O
      /**
       * Invokes the action's method on the target object given the specified set
       * of parameters.
+      *
+      * @param mixedInAdapter - will be null for regular actions, and for mixin actions.  When a mixin action invokes its underlying mixedIn action, then will be populated (so that the ActionDomainEvent can correctly provide the underlying mixin)
       */
      ObjectAdapter execute(
--            ObjectAdapter target,
++            ObjectAdapter targetAdapter,
+             ObjectAdapter mixedInAdapter,
              ObjectAdapter[] parameters,
              final InteractionInitiatedBy interactionInitiatedBy);
  

http://git-wip-us.apache.org/repos/asf/isis/blob/02dd0ee5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionContributee.java
----------------------------------------------------------------------
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionContributee.java
index 59a0048,e1a52e6..b41f21d
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionContributee.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionContributee.java
@@@ -185,14 -195,55 +185,15 @@@ public class ObjectActionContributee ex
  
      @Override
      public ObjectAdapter execute(
--            final ObjectAdapter contributee,
++            final ObjectAdapter targetAdapter,
+             final ObjectAdapter mixedInAdapter,
              final ObjectAdapter[] arguments,
              final InteractionInitiatedBy interactionInitiatedBy) {
          
-         setupActionInvocationContext(contributee);
-         setupCommandTarget(contributee, arguments);
 -        // this code also exists in ActionInvocationFacetViaMethod
 -        // we need to repeat it here because the target adapter should be the contributee, not the contributing service.
 -
 -        final BulkFacet bulkFacet = getFacet(BulkFacet.class);
 -        if (bulkFacet != null) {
 -
 -            final ActionInvocationContext actionInvocationContext = getServicesInjector().lookupService(ActionInvocationContext.class);
 -            if (actionInvocationContext != null &&
 -                    actionInvocationContext.getInvokedOn() == null) {
 -
 -                actionInvocationContext.setInvokedOn(InvokedOn.OBJECT);
 -                actionInvocationContext.setDomainObjects(Collections.singletonList(contributee.getObject()));
 -            }
 -
 -            final Bulk.InteractionContext bulkInteractionContext = getServicesInjector().lookupService(Bulk.InteractionContext.class);
 -            if (bulkInteractionContext != null &&
 -                    bulkInteractionContext.getInvokedAs() == null) {
 -
 -                bulkInteractionContext.setInvokedAs(Bulk.InteractionContext.InvokedAs.REGULAR);
 -                bulkInteractionContext.setDomainObjects(Collections.singletonList(contributee.getObject()));
 -            }
 -
++        setupActionInvocationContext(targetAdapter);
++        setupCommandTarget(targetAdapter, arguments);
  
-         return serviceAction.execute(getServiceAdapter(), argsPlusContributee(contributee, arguments),
 -        }
 -
 -        final CommandContext commandContext = getServicesInjector().lookupService(CommandContext.class);
 -        final Command command = commandContext != null ? commandContext.getCommand() : null;
 -
 -        if(command != null && command.getExecutor() == Executor.USER) {
 -
 -            if (command.getTarget() != null) {
 -                // already set up by a edit form
 -                // don't overwrite
 -            } else {
 -                command.setTargetClass(CommandUtil.targetClassNameFor(contributee));
 -                command.setTargetAction(CommandUtil.targetActionNameFor(this));
 -                command.setArguments(CommandUtil.argDescriptionFor(this, arguments));
 -
 -                final Bookmark targetBookmark = CommandUtil.bookmarkFor(contributee);
 -                command.setTarget(targetBookmark);
 -            }
 -        }
 -        
 -        return serviceAction.execute(getServiceAdapter(), mixedInAdapter, argsPlusContributee(contributee, arguments),
++        return serviceAction.execute(getServiceAdapter(), mixedInAdapter, argsPlusContributee(targetAdapter, arguments),
                  interactionInitiatedBy);
      }
  

http://git-wip-us.apache.org/repos/asf/isis/blob/02dd0ee5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionDefault.java
----------------------------------------------------------------------
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionDefault.java
index e198ab4,09a061f..7551844
--- 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
@@@ -19,10 -19,8 +19,12 @@@
  
  package org.apache.isis.core.metamodel.specloader.specimpl;
  
 +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;
  
@@@ -367,15 -365,16 +381,15 @@@ public class ObjectActionDefault extend
  
      @Override
      public ObjectAdapter execute(
 -            final ObjectAdapter target,
 +            final ObjectAdapter targetAdapter,
-             final ObjectAdapter[] arguments,
+             final ObjectAdapter mixedInAdapter,
 -            final ObjectAdapter[] arguments,
++            final ObjectAdapter[] argumentAdapters,
              final InteractionInitiatedBy interactionInitiatedBy) {
          if(LOG.isDebugEnabled()) {
 -            LOG.debug("execute action " + target + "." + getId());
 +            LOG.debug("execute action " + targetAdapter + "." + getId());
          }
          final ActionInvocationFacet facet = getFacet(ActionInvocationFacet.class);
- 
-         return facet.invoke(this, targetAdapter, arguments, interactionInitiatedBy);
 -        return facet.invoke(this, target, mixedInAdapter, arguments,
 -                interactionInitiatedBy);
++        return facet.invoke(this, targetAdapter, mixedInAdapter, argumentAdapters, interactionInitiatedBy);
      }
  
      protected ActionInvocationFacet getActionInvocationFacet() {

http://git-wip-us.apache.org/repos/asf/isis/blob/02dd0ee5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
----------------------------------------------------------------------
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
index f362952,40468f1..8c68f84
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
@@@ -34,9 -43,11 +35,10 @@@ import org.apache.isis.core.metamodel.f
  import org.apache.isis.core.metamodel.facets.all.named.NamedFacetInferred;
  import org.apache.isis.core.metamodel.interactions.InteractionUtils;
  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.spec.ObjectSpecification;
 +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;
  
@@@ -162,46 -169,94 +164,63 @@@ public class ObjectActionMixedIn extend
          return InteractionUtils.isUsableResult(this, ic).createConsent();
      }
  
+ 
      @Override
      public ObjectAdapter[] getDefaults(final ObjectAdapter mixedInAdapter) {
 -        return mixinAction.getDefaults(mixinAdapterFor(mixinType, mixedInAdapter));
 +        return mixinAction.getDefaults(mixinAdapterFor(mixedInAdapter));
      }
  
      @Override
      public ObjectAdapter[][] getChoices(
              final ObjectAdapter mixedInAdapter,
              final InteractionInitiatedBy interactionInitiatedBy) {
 -        return mixinAction.getChoices(mixinAdapterFor(mixinType, mixedInAdapter), interactionInitiatedBy);
 +        return mixinAction.getChoices(mixinAdapterFor(mixedInAdapter), interactionInitiatedBy);
 +    }
 +
 +    protected ObjectAdapter mixinAdapterFor(final ObjectAdapter mixedInAdapter) {
 +        return mixinAdapterFor(mixinType, mixedInAdapter);
      }
  
-     public Consent isProposedArgumentSetValid(
+     @Override
+     protected void validateArgumentSet(
              final ObjectAdapter mixedInAdapter,
              final ObjectAdapter[] proposedArguments,
-             final InteractionInitiatedBy interactionInitiatedBy) {
-         return mixinAction.isProposedArgumentSetValid(mixinAdapterFor(mixedInAdapter), proposedArguments, interactionInitiatedBy);
+             final InteractionInitiatedBy interactionInitiatedBy,
+             final InteractionResultSet resultSet) {
+ 
+         final ObjectAdapter targetObject = mixinAdapterFor(mixinType, mixedInAdapter);
+ 
+         final ValidityContext<?> ic =  mixinAction.createActionInvocationInteractionContext(
+                 targetObject, proposedArguments, interactionInitiatedBy);
+         ic.setMixedIn(mixedInAdapter);
+ 
+         InteractionUtils.isValidResultSet(this, ic, resultSet);
      }
  
+ 
+ 
      @Override
      public ObjectAdapter execute(
-             final ObjectAdapter mixedInAdapter,
+             final ObjectAdapter target,         // will be the mixedInAdapter
+             final ObjectAdapter mixedInAdapter, // will be passed in as null
              final ObjectAdapter[] arguments,
              final InteractionInitiatedBy interactionInitiatedBy) {
  
          // this code also exists in ActionInvocationFacetViaMethod
          // we need to repeat it here because the target adapter should be the mixedInAdapter, not the mixin
  
 -        final BulkFacet bulkFacet = getFacet(BulkFacet.class);
 -        if (bulkFacet != null) {
 -
 -            final ActionInvocationContext actionInvocationContext =
 -                    getServicesInjector().lookupService(ActionInvocationContext.class);
 -            if (actionInvocationContext != null &&
 -                    actionInvocationContext.getInvokedOn() == null) {
 -
 -                actionInvocationContext.setInvokedOn(InvokedOn.OBJECT);
 -                actionInvocationContext.setDomainObjects(Collections.singletonList(target.getObject()));
 -            }
 -
 -            final Bulk.InteractionContext bulkInteractionContext = getServicesInjector().lookupService(Bulk.InteractionContext.class);
 -            if (bulkInteractionContext != null &&
 -                    bulkInteractionContext.getInvokedAs() == null) {
 -
 -                bulkInteractionContext.setInvokedAs(Bulk.InteractionContext.InvokedAs.REGULAR);
 -                actionInvocationContext.setDomainObjects(Collections.singletonList(target.getObject()));
 -            }
 -        }
 -
 -        final CommandContext commandContext = getServicesInjector().lookupService(CommandContext.class);
 -        final Command command = commandContext != null ? commandContext.getCommand() : null;
 -
 -        if(command != null && command.getExecutor() == Executor.USER) {
 -
 -            if (command.getTarget() != null) {
 -                // already set up by a edit form
 -                // don't overwrite
 -            } else {
 -                command.setTargetClass(CommandUtil.targetClassNameFor(target));
 -                command.setTargetAction(CommandUtil.targetActionNameFor(this));
 -                command.setArguments(CommandUtil.argDescriptionFor(this, arguments));
 +        setupActionInvocationContext(mixedInAdapter);
  
 -                final Bookmark targetBookmark = CommandUtil.bookmarkFor(target);
 -                command.setTarget(targetBookmark);
 -            }
 -        }
 +        setupCommandTarget(mixedInAdapter, arguments);
 +        setupCommandMementoAndExecutionContext(mixedInAdapter, arguments);
  
-         return mixinAction.execute(mixinAdapterFor(mixedInAdapter), arguments, interactionInitiatedBy);
+         final ObjectAdapter targetAdapter = mixinAdapterFor(mixinType, target);
+         final ObjectAdapter actualMixedInAdapter = target;
+         return mixinAction.execute(
+                 targetAdapter, actualMixedInAdapter, arguments,
+                 interactionInitiatedBy);
      }
  
 -
      //region > facetHolder
      @Override
      protected FacetHolder getFacetHolder() {

http://git-wip-us.apache.org/repos/asf/isis/blob/02dd0ee5/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java
----------------------------------------------------------------------
diff --cc core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java
index 8b66f1c,8cf11dd..55c0ea6
--- 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
@@@ -95,110 -85,52 +95,123 @@@ public abstract class BackgroundCommand
      // //////////////////////////////////////
  
      
 -    private void execute(final IsisTransactionManager transactionManager, final Command command) {
 -        transactionManager.executeWithinTransaction(new TransactionalClosure() {
 +    private void execute(final IsisTransactionManager transactionManager, final Command backgroundCommand) {
 +        transactionManager.executeWithinTransaction(
 +                backgroundCommand,
 +                new TransactionalClosure() {
              @Override
              public void execute() {
 -                commandContext.setCommand(command);
 +
 +                // setup for us by IsisTransactionManager; will have the transactionId of the backgroundCommand
 +                final Interaction backgroundInteraction = interactionContext.getInteraction();
 +
 +                final String memento = backgroundCommand.getMemento();
 +
                  try {
 +                    backgroundCommand.setExecutor(Executor.BACKGROUND);
  
 -                    command.setStartedAt(Clock.getTimeAsJavaSqlTimestamp());
 -                    command.setExecutor(Executor.BACKGROUND);
 +                    final boolean legacy = memento.startsWith("<memento");
 +                    if(legacy) {
  
 -                    final String memento = command.getMemento();
 -                    final ActionInvocationMemento aim = new ActionInvocationMemento(mementoService, memento);
 +                        final ActionInvocationMemento aim = new ActionInvocationMemento(mementoService, memento);
  
 -                    final String actionId = aim.getActionId();
 +                        final String actionId = aim.getActionId();
  
 -                    final Bookmark targetBookmark = aim.getTarget();
 -                    final Object targetObject = bookmarkService.lookup(targetBookmark);
 +                        final Bookmark targetBookmark = aim.getTarget();
 +                        final Object targetObject = bookmarkService.lookup(targetBookmark);
  
 -                    final ObjectAdapter targetAdapter = adapterFor(targetObject);
 -                    final ObjectSpecification specification = targetAdapter.getSpecification();
 +                        final ObjectAdapter targetAdapter = adapterFor(targetObject);
 +                        final ObjectSpecification specification = targetAdapter.getSpecification();
  
 -                    final ObjectAction objectAction = findAction(specification, actionId);
 -                    if(objectAction == null) {
 -                        throw new Exception("Unknown action '" + actionId + "'");
 -                    }
 +                        final ObjectAction objectAction = findAction(specification, actionId);
 +                        if(objectAction == null) {
 +                            throw new RuntimeException(String.format("Unknown action '%s'", actionId));
 +                        }
 +
++                        // TODO: background commands won't work for mixin actions...
++                        // ... we obtain the target from the bookmark service (above), which will
++                        // simply fail for a mixin.  Instead we would need to serialize out the mixedInAdapter
++                        // and also capture the mixinType within the aim memento.
++                        final ObjectAdapter mixedInAdapter = null;
++
 +                        final ObjectAdapter[] argAdapters = argAdaptersFor(aim);
 +                        final ObjectAdapter resultAdapter = objectAction.execute(
-                                 targetAdapter, argAdapters, InteractionInitiatedBy.FRAMEWORK);
++                                targetAdapter, mixedInAdapter, argAdapters, InteractionInitiatedBy.FRAMEWORK);
++
 +                        if(resultAdapter != null) {
 +                            Bookmark resultBookmark = CommandUtil.bookmarkFor(resultAdapter);
 +                            backgroundCommand.setResult(resultBookmark);
 +                            backgroundInteraction.getCurrentExecution().setResult(resultAdapter.getObject());
 +                        }
 +
 +                    } else {
 +
 +                        final CommandMementoDto dto = jaxbService.fromXml(CommandMementoDto.class, memento);
 +                        final ActionDto actionDto = dto.getAction();
 +                        final String actionId = actionDto.getActionIdentifier();
 +
 +                        final List<OidDto> targetOidDtos = dto.getTargets();
 +                        for (OidDto targetOidDto : targetOidDtos) {
  
 -                    final ObjectAdapter[] argAdapters = argAdaptersFor(aim);
 +                            final Bookmark bookmark = Bookmark.from(targetOidDto);
 +                            final Object targetObject = bookmarkService.lookup(bookmark);
  
 -                    // TODO: background commands won't work for mixin actions...
 -                    // ... we obtain the target from the bookmark service (above), which will
 -                    // simply fail for a mixin.  Instead we would need to serialize out the mixedInAdapter
 -                    // and also capture the mixinType within the aim memento.
 -                    final ObjectAdapter mixedInAdapter = null;
 +                            final ObjectAdapter targetAdapter = adapterFor(targetObject);
  
 -                    final ObjectAdapter resultAdapter = objectAction.execute(
 -                            targetAdapter, mixedInAdapter, argAdapters, InteractionInitiatedBy.FRAMEWORK);
 -                    if(resultAdapter != null) {
 -                        Bookmark resultBookmark = CommandUtil.bookmarkFor(resultAdapter);
 -                        command.setResult(resultBookmark);
 +                            final ObjectAction objectAction =
 +                                    findObjectAction(targetAdapter, actionId);
 +
++                            // TODO: background commands won't work for mixin actions...
++                            // ... we obtain the target from the bookmark service (above), which will
++                            // simply fail for a mixin.  Instead we would need to serialize out the mixedInAdapter
++                            // and also capture the mixinType within the aim memento.
++                            final ObjectAdapter mixedInAdapter = null;
++
 +                            final ObjectAdapter[] argAdapters = argAdaptersFor(dto);
 +                            final ObjectAdapter resultAdapter = objectAction.execute(
-                                     targetAdapter, argAdapters, InteractionInitiatedBy.FRAMEWORK);
++                                    targetAdapter, mixedInAdapter, argAdapters, InteractionInitiatedBy.FRAMEWORK);
 +
 +                            // alternatively, could use...
 +                            Object unused = backgroundInteraction.getPriorExecution().getResult();
 +
 +                            // this doesn't really make sense if >1 action
 +                            // in any case, the capturing of the action interaction should be the
 +                            // responsibility of auditing/profiling
 +                            if(resultAdapter != null) {
 +                                Bookmark resultBookmark = CommandUtil.bookmarkFor(resultAdapter);
 +                                backgroundCommand.setResult(resultBookmark);
 +                            }
 +                        }
                      }
  
 -                } catch (Exception e) {
 -                    command.setException(Throwables.getStackTraceAsString(e));
 -                } finally {
 -                    command.setCompletedAt(Clock.getTimeAsJavaSqlTimestamp());
 +                } catch (RuntimeException e) {
 +                    // this doesn't really make sense if >1 action
 +                    // in any case, the capturing of the action interaction should be the
 +                    // responsibility of auditing/profiling
 +                    backgroundCommand.setException(Throwables.getStackTraceAsString(e));
 +
 +                    // alternatively, could use...
 +                    RuntimeException unused = backgroundInteraction.getPriorExecution().getException();
 +
 +                    backgroundInteraction.getCurrentExecution().setException(e);
 +                }
 +
 +                backgroundCommand.setCompletedAt(backgroundInteraction.getPriorExecution().getCompletedAt());
 +            }
 +
 +            private ObjectAction findObjectAction(
 +                    final ObjectAdapter targetAdapter,
 +                    final String actionId) throws RuntimeException {
 +
 +                final ObjectAction objectAction;
 +
 +                final ObjectSpecification specification = targetAdapter.getSpecification();
 +
 +                objectAction = findAction(specification, actionId);
 +                if(objectAction == null) {
 +                    throw new RuntimeException(String.format("Unknown action '%s'", actionId));
                  }
 +                return objectAction;
              }
          });
      }

http://git-wip-us.apache.org/repos/asf/isis/blob/02dd0ee5/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsLinkFactory.java
----------------------------------------------------------------------
diff --cc core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsLinkFactory.java
index 12682d5,08134fc..77ee33e
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsLinkFactory.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsLinkFactory.java
@@@ -133,12 -125,13 +133,16 @@@ public final class BulkActionsLinkFacto
                              bulkInteractionContext.setIndex(i++);
                          }
  
-                         lastReturnedAdapter = objectAction.executeWithRuleChecking(adapter, new ObjectAdapter[]{},
+                         final ObjectAdapter mixedInAdapter = null;
+                         final ObjectAdapter[] arguments = {};
+ 
+                         lastReturnedAdapter = objectAction.executeWithRuleChecking(
+                                 adapter, mixedInAdapter, arguments,
                                  InteractionInitiatedBy.USER, ActionModel.WHERE_FOR_ACTION_INVOCATION
                          );
 +                        TransactionService transactionService =
 +                                getServicesInjector().lookupService(TransactionService.class);
 +                        transactionService.nextTransaction();
                      }
  
  

http://git-wip-us.apache.org/repos/asf/isis/blob/02dd0ee5/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/DomainObjectInvocationHandler.java
----------------------------------------------------------------------
diff --cc core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/DomainObjectInvocationHandler.java
index d866e14,b7db730..c9f6bc9
--- a/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/DomainObjectInvocationHandler.java
+++ b/core/wrapper/src/main/java/org/apache/isis/core/wrapper/handlers/DomainObjectInvocationHandler.java
@@@ -623,13 -625,20 +623,16 @@@ public class DomainObjectInvocationHand
  
          if (getExecutionMode().shouldExecute()) {
              final InteractionInitiatedBy interactionInitiatedBy = getInteractionInitiatedBy();
-             final ObjectAdapter actionReturnNO =
-                     objectAction.execute(targetAdapter, argAdapters, interactionInitiatedBy);
+             final ObjectAdapter mixedInAdapter = null; // mixin action will automatically fill in.
+             final ObjectAdapter returnedAdapter =
+                     objectAction.execute(
+                             targetAdapter, mixedInAdapter, argAdapters,
+                             interactionInitiatedBy);
  
 -            final IsisTransaction transaction = IsisContext.getTransactionManager().getTransaction();
 -
 -            final String currentUser = IsisContext.getAuthenticationSession().getUserName();
 -            final Timestamp timestamp = Clock.getTimeAsJavaSqlTimestamp();
 -
 -            transaction.publishActionIfRequired(currentUser, timestamp);
 +            final PublishingServiceInternal publishingServiceInternal = getPublishingServiceInternal();
 +            publishingServiceInternal.publishAction();
  
-             return ObjectAdapter.Util.unwrap(actionReturnNO);
+             return ObjectAdapter.Util.unwrap(returnedAdapter);
          }
  
          return null;