You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2021/10/03 15:20:25 UTC

[isis] branch value.types created (now 5798980)

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a change to branch value.types
in repository https://gitbox.apache.org/repos/asf/isis.git.


      at 5798980  ISIS-2871: evaluate action parameter defaults honoring multiselect providers (if any)

This branch includes the following new commits:

     new 5798980  ISIS-2871: evaluate action parameter defaults honoring multiselect providers (if any)

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[isis] 01/01: ISIS-2871: evaluate action parameter defaults honoring multiselect providers (if any)

Posted by ah...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch value.types
in repository https://gitbox.apache.org/repos/asf/isis.git

commit 579898050b15abccf9e5c44a77f0456dae2cb48d
Author: andi-huber <ah...@apache.org>
AuthorDate: Sun Oct 3 17:20:11 2021 +0200

    ISIS-2871: evaluate action parameter defaults honoring multiselect
    providers (if any)
---
 .../interactions/managed/ActionInteraction.java    | 11 ++++-
 .../managed/ActionInteractionHead.java             | 50 +++++++++++++--------
 .../interactions/managed/ManagedAction.java        | 20 +++++++--
 .../interactions/managed/MultiselectChoices.java   | 29 ++++++++++++
 .../managed/ParameterNegotiationModel.java         | 18 ++++++--
 .../managed/nonscalar/DataTableModel.java          | 16 ++++---
 ...meterDefaultsFacetFromAssociatedCollection.java |  6 +--
 .../core/metamodel/spec/feature/ObjectAction.java  | 11 ++---
 .../spec/feature/ObjectActionParameter.java        |  9 ----
 .../specloader/specimpl/ObjectActionDefault.java   | 14 +-----
 .../specloader/specimpl/ObjectActionMixedIn.java   |  6 ---
 .../testdomain/interact/ActionInteractionTest.java | 18 ++++----
 .../interact/CollectionInteractionTest.java        |  7 ++-
 .../testdomain/interact/NewParameterModelTest.java | 10 ++---
 .../interaction/DomainObjectTesterFactory.java     | 40 ++++++++++++++---
 .../util/interaction/InteractionTestAbstract.java  | 31 +++++--------
 .../domainobjects/ObjectActionReprRenderer.java    | 52 ++++++++++------------
 17 files changed, 202 insertions(+), 146 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ActionInteraction.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ActionInteraction.java
index 4130ad6..5ac8f08 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ActionInteraction.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ActionInteraction.java
@@ -55,7 +55,16 @@ public final class ActionInteraction extends MemberInteraction<ManagedAction, Ac
             final @NonNull String memberId,
             final @NonNull Where where) {
 
-        val managedAction = ManagedAction.lookupAction(owner, memberId, where);
+        return startWithMultiselect(owner, memberId, where, Can::empty);
+    }
+
+    public static final ActionInteraction startWithMultiselect(
+            final @NonNull ManagedObject owner,
+            final @NonNull String memberId,
+            final @NonNull Where where,
+            final @NonNull MultiselectChoices multiselectChoices) {
+
+        val managedAction = ManagedAction.lookupActionWithMultiselect(owner, memberId, where, multiselectChoices);
 
         final _Either<ManagedAction, InteractionVeto> chain = managedAction.isPresent()
                 ? _Either.left(managedAction.get())
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ActionInteractionHead.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ActionInteractionHead.java
index 19b9c2f..d2d5915 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ActionInteractionHead.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ActionInteractionHead.java
@@ -43,20 +43,31 @@ implements HasMetaModel<ObjectAction> {
 
     @Getter(onMethod = @__(@Override))
     @NonNull private final ObjectAction metaModel;
+    @Getter private final MultiselectChoices multiselectChoices;
 
     public static ActionInteractionHead of(
-            @NonNull final ObjectAction objectAction,
-            @NonNull final ManagedObject owner,
-            @NonNull final ManagedObject target) {
-        return new ActionInteractionHead(objectAction, owner, target);
+            final @NonNull ObjectAction objectAction,
+            final @NonNull ManagedObject owner,
+            final @NonNull ManagedObject target) {
+        return new ActionInteractionHead(objectAction, owner, target, Can::empty);
+    }
+
+    public static ActionInteractionHead of(
+            final @NonNull ObjectAction objectAction,
+            final @NonNull ManagedObject owner,
+            final @NonNull ManagedObject target,
+            final @NonNull MultiselectChoices multiselectChoices) {
+        return new ActionInteractionHead(objectAction, owner, target, multiselectChoices);
     }
 
     protected ActionInteractionHead(
-            @NonNull final ObjectAction objectAction,
-            @NonNull final ManagedObject owner,
-            @NonNull final ManagedObject target) {
+            final @NonNull ObjectAction objectAction,
+            final @NonNull ManagedObject owner,
+            final @NonNull ManagedObject target,
+            final @NonNull MultiselectChoices multiselectChoices) {
         super(owner, target);
         this.metaModel = objectAction;
+        this.multiselectChoices = multiselectChoices;
     }
 
     /**
@@ -93,13 +104,8 @@ implements HasMetaModel<ObjectAction> {
             ManagedObject.of(objectActionParameter.getElementType(), argPojo));
     }
 
-    public ParameterNegotiationModel model(
-            @NonNull final Can<ManagedObject> paramValues) {
-        return ParameterNegotiationModel.of(this, paramValues);
-    }
-
-    public ParameterNegotiationModel emptyModel() {
-        return ParameterNegotiationModel.of(this, getEmptyParameterValues());
+    public ParameterNegotiationModel emptyModel(final ManagedAction managedAction) {
+        return ParameterNegotiationModel.of(managedAction, getEmptyParameterValues());
     }
 
     /**
@@ -108,7 +114,7 @@ implements HasMetaModel<ObjectAction> {
      * ActionParameterNegotiation (wiki)
      * </a>
      */
-    public ParameterNegotiationModel defaults() {
+    public ParameterNegotiationModel defaults(final ManagedAction managedAction) {
 
         // first pass ... empty values
         // second pass ... proposed default values
@@ -122,7 +128,7 @@ implements HasMetaModel<ObjectAction> {
                 // vector of packed values - where each is either scalar or non-scalar
                 paramVector->{
                     //lombok 1.18.20 issue with val - should be fixed in 1.18.22
-                    final var paramNegotiationModel = model(paramVector);
+                    final var paramNegotiationModel = modelForParamValues(managedAction, paramVector);
                     return params
                             .map(param->param.getDefault(paramNegotiationModel));
                 },
@@ -133,11 +139,19 @@ implements HasMetaModel<ObjectAction> {
                     + "parameter defaults on action %s.", getMetaModel());
         }
 
-        return model(fixedPoint.fold(
+        return modelForParamValues(managedAction,
+                fixedPoint.fold(
                 left->left,
                 right->right));
     }
 
+    // -- HELPER
+
+    private ParameterNegotiationModel modelForParamValues(
+            final ManagedAction managedAction,
+            @NonNull final Can<ManagedObject> paramValues) {
+        return ParameterNegotiationModel.of(managedAction, paramValues);
+    }
 
     /**
      * Returns either a fixed point or the last iteration.
@@ -159,6 +173,4 @@ implements HasMetaModel<ObjectAction> {
         return _Either.right(t0);
     }
 
-
-
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedAction.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedAction.java
index d6951f7..1d3f78d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedAction.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedAction.java
@@ -54,7 +54,7 @@ public final class ManagedAction extends ManagedMember {
             final @NonNull ManagedObject owner,
             final @NonNull ObjectAction action,
             final @NonNull Where where) {
-        return new ManagedAction(owner, action, where);
+        return new ManagedAction(owner, action, where, Can::empty);
     }
 
     public static final Optional<ManagedAction> lookupAction(
@@ -66,20 +66,32 @@ public final class ManagedAction extends ManagedMember {
         .map(objectAction -> of(owner, objectAction, where));
     }
 
+    public static final Optional<ManagedAction> lookupActionWithMultiselect(
+            final @NonNull ManagedObject owner,
+            final @NonNull String memberId,
+            final @NonNull Where where,
+            final @NonNull MultiselectChoices multiselectChoices) {
+
+        return ManagedMember.<ObjectAction>lookup(owner, MemberType.ACTION, memberId)
+                .map(objectAction -> new ManagedAction(owner, objectAction, where, multiselectChoices));
+    }
+
     // -- IMPLEMENTATION
 
     @Getter private final ObjectAction action;
-
     @Getter private final ActionInteractionHead interactionHead;
+    @Getter private final MultiselectChoices multiselectChoices;
 
     private ManagedAction(
             final @NonNull ManagedObject owner,
             final @NonNull ObjectAction action,
-            final @NonNull Where where) {
+            final @NonNull Where where,
+            final @NonNull MultiselectChoices multiselectChoices) {
 
         super(owner, where);
         this.action = action;
         this.interactionHead = action.interactionHead(owner);
+        this.multiselectChoices = multiselectChoices;
     }
 
     /**
@@ -87,7 +99,7 @@ public final class ManagedAction extends ManagedMember {
      * parameters if any are initialized with their defaults (taking into account any supporting methods)
      */
     public ParameterNegotiationModel startParameterNegotiation() {
-        return getInteractionHead().defaults();
+        return interactionHead.defaults(this);
     }
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/MultiselectChoices.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/MultiselectChoices.java
new file mode 100644
index 0000000..75dd3b1
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/MultiselectChoices.java
@@ -0,0 +1,29 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.core.metamodel.interactions.managed;
+
+import org.apache.isis.commons.collections.Can;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+
+@FunctionalInterface
+public interface MultiselectChoices {
+
+    Can<ManagedObject> getSelected();
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ParameterNegotiationModel.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ParameterNegotiationModel.java
index ecf8d56..4bf5461 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ParameterNegotiationModel.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ParameterNegotiationModel.java
@@ -54,21 +54,23 @@ import lombok.val;
 public class ParameterNegotiationModel {
 
     public static ParameterNegotiationModel of(
-            final @NonNull ActionInteractionHead head,
+            final @NonNull ManagedAction managedAction,
             final @NonNull Can<ManagedObject> initialParamValues) {
-        return new ParameterNegotiationModel(head, initialParamValues);
+        return new ParameterNegotiationModel(managedAction, initialParamValues);
 
     }
 
     @Getter private final ActionInteractionHead head;
+    private final @NonNull ManagedAction managedAction;
     private final Can<ParameterModel> paramModels;
     private final _BindableAbstract<Boolean> validationFeedbackActive;
     private final LazyObservable<String> observableActionValidation;
 
     private ParameterNegotiationModel(
-            final @NonNull ActionInteractionHead head,
+            final @NonNull ManagedAction managedAction,
             final @NonNull Can<ManagedObject> initialParamValues) {
-        this.head = head;
+        this.managedAction = managedAction;
+        this.head = managedAction.getInteractionHead(); //TODO  don't memoize
         this.validationFeedbackActive = _Bindables.forValue(false);
 
         val paramNrIterator = IntStream.range(0, initialParamValues.size()).iterator();
@@ -164,6 +166,12 @@ public class ParameterNegotiationModel {
                 .isUsable(head, pendingArgValues, InteractionInitiatedBy.USER);
     }
 
+    // -- MULTI SELECT
+
+    public MultiselectChoices getMultiselectChoices() {
+        return managedAction.getMultiselectChoices();
+    }
+
     // -- RATHER INTERNAL ...
 
     /** validates all, the action and each individual parameter */
@@ -345,4 +353,6 @@ public class ParameterNegotiationModel {
 
     }
 
+
+
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/nonscalar/DataTableModel.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/nonscalar/DataTableModel.java
index f07c4b7..6537d91 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/nonscalar/DataTableModel.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/nonscalar/DataTableModel.java
@@ -45,6 +45,7 @@ import org.apache.isis.core.metamodel.interactions.managed.ManagedAction;
 import org.apache.isis.core.metamodel.interactions.managed.ManagedAction.MementoForArgs;
 import org.apache.isis.core.metamodel.interactions.managed.ManagedCollection;
 import org.apache.isis.core.metamodel.interactions.managed.ManagedMember;
+import org.apache.isis.core.metamodel.interactions.managed.MultiselectChoices;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
@@ -55,7 +56,8 @@ import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
 import lombok.val;
 
-public class DataTableModel {
+public class DataTableModel
+implements MultiselectChoices {
 
     // -- FACTORIES
 
@@ -195,8 +197,14 @@ public class DataTableModel {
 
     // -- ASSOCIATED ACTION WITH MULTI SELECT
 
-    public ActionInteraction startAssociatedActionInteraction(final String actionId, final Where where) {
+    @Override
+    public Can<ManagedObject> getSelected() {
+        return getDataRowsSelected()
+                .getValue()
+                .map(DataRow::getRowElement);
+    }
 
+    public ActionInteraction startAssociatedActionInteraction(final String actionId, final Where where) {
         val featureId = managedMember.getIdentifier();
         if(featureId.getType().isAction()) {
             return ActionInteraction.empty(String.format("[no such associated action %s for collection %s "
@@ -204,9 +212,7 @@ public class DataTableModel {
                     actionId,
                     featureId));
         }
-
-        //FIXME[ISIS-2871] get initial defaults from this table
-        return ActionInteraction.start(managedMember.getOwner(), actionId, where);
+        return ActionInteraction.startWithMultiselect(managedMember.getOwner(), actionId, where, this);
     }
 
     // -- MEMENTO
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/collparam/ActionParameterDefaultsFacetFromAssociatedCollection.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/collparam/ActionParameterDefaultsFacetFromAssociatedCollection.java
index d605f41..df973ca 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/collparam/ActionParameterDefaultsFacetFromAssociatedCollection.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/collparam/ActionParameterDefaultsFacetFromAssociatedCollection.java
@@ -34,17 +34,13 @@ extends ActionParameterDefaultsFacetAbstract {
         return new ActionParameterDefaultsFacetFromAssociatedCollection(param);
     }
 
-    private int paramIndex;
-
     private ActionParameterDefaultsFacetFromAssociatedCollection(final ObjectActionParameter param) {
         super(param);
-        this.paramIndex = param.getNumber();
     }
 
     @Override
     public Can<ManagedObject> getDefault(@NonNull final ParameterNegotiationModel pendingArgs) {
-        //FIXME[ISIS-2871] rather then filling in all (as proof of concept), fill in only those selected
-        return pendingArgs.getObservableParamChoices(paramIndex).getValue();
+        return pendingArgs.getMultiselectChoices().getSelected();
     }
 
 
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 c6d3fcd..4aeae25 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
@@ -171,10 +171,10 @@ public interface ObjectAction extends ObjectMember {
             InteractionInitiatedBy interactionInitiatedBy);
 
 
-    // -- Model for Parameter Negotiation
+    // -- INTERACTION HEAD
 
-    ActionInteractionHead interactionHead(
-            @NonNull ManagedObject actionOwner);
+    @Deprecated// use ManagedAction instead
+    ActionInteractionHead interactionHead(@NonNull ManagedObject actionOwner);
 
     // -- Parameters (declarative)
 
@@ -234,11 +234,6 @@ public interface ObjectAction extends ObjectMember {
     // -- Parameters (per instance)
 
     /**
-     * Returns the defaults references/values to be used for the action.
-     */
-    Can<ManagedObject> getDefaults(ManagedObject target);
-
-    /**
      * Returns a list of possible references/values for each parameter, which
      * the user can choose from.
      */
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectActionParameter.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectActionParameter.java
index 553e77e..1edc930 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectActionParameter.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectActionParameter.java
@@ -140,15 +140,6 @@ extends ObjectFeature, CurrentHolder {
         return ManagedObject.of(getElementType(), null);
     }
 
-    /** default value as result of a initial param value fixed point search */
-    default ManagedObject getDefault(final ManagedObject actionOnwer) {
-        return getAction()
-                .interactionHead(actionOnwer).defaults()
-                .getParamValues()
-                .getElseFail(getNumber());
-    }
-
-
     /**
      * Whether this parameter is visible given the entered previous arguments
      * @param head
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 2062f01..dde552d 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
@@ -144,7 +144,8 @@ implements ObjectAction {
     }
 
     @Override
-    public ActionInteractionHead interactionHead(final @NonNull ManagedObject actionOwner) {
+    public ActionInteractionHead interactionHead(
+            final @NonNull ManagedObject actionOwner) {
         return ActionInteractionHead.of(this, actionOwner, actionOwner);
     }
 
@@ -402,17 +403,6 @@ implements ObjectAction {
         return getFacetedMethod().getFacet(ActionInvocationFacet.class);
     }
 
-    // -- defaults
-
-    @Override
-    public Can<ManagedObject> getDefaults(final ManagedObject target) {
-        // use the new defaultNXxx approach for each param in turn
-        // (the reflector will have made sure both aren't installed).
-        return interactionHead(target)
-                .defaults()
-                .getParamValues();
-    }
-
     // -- choices
 
     @Override
diff --git 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
index 3c7aa55..0151122 100644
--- 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
@@ -136,12 +136,6 @@ implements MixedInMember {
     }
 
     @Override
-    public Can<ManagedObject> getDefaults(final ManagedObject mixedInAdapter) {
-        final ManagedObject mixinAdapter = mixinAdapterFor(mixedInAdapter);
-        return mixinAction.getDefaults(mixinAdapter);
-    }
-
-    @Override
     public CanVector<ManagedObject> getChoices(
             final ManagedObject mixedInAdapter,
             final InteractionInitiatedBy interactionInitiatedBy) {
diff --git a/regressiontests/stable-interact/src/test/java/org/apache/isis/testdomain/interact/ActionInteractionTest.java b/regressiontests/stable-interact/src/test/java/org/apache/isis/testdomain/interact/ActionInteractionTest.java
index fbf70ff..ccbe728 100644
--- a/regressiontests/stable-interact/src/test/java/org/apache/isis/testdomain/interact/ActionInteractionTest.java
+++ b/regressiontests/stable-interact/src/test/java/org/apache/isis/testdomain/interact/ActionInteractionTest.java
@@ -25,11 +25,6 @@ import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.TestPropertySource;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.collections._Lists;
@@ -44,6 +39,11 @@ import org.apache.isis.testdomain.model.interaction.InteractionDemo_multiEnum;
 import org.apache.isis.testdomain.model.interaction.InteractionDemo_multiInt;
 import org.apache.isis.testdomain.util.interaction.InteractionTestAbstract;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
 import lombok.val;
 
 @SpringBootTest(
@@ -206,7 +206,7 @@ class ActionInteractionTest extends InteractionTestAbstract {
                 .checkUsability();
 
         val managedAction = actionInteraction.getManagedAction().get(); // should not throw
-        val pendingArgs = managedAction.getInteractionHead().defaults();
+        val pendingArgs = managedAction.startParameterNegotiation();
 
         val expectedDefaults = Can.of(
                 new InteractionDemo_biArgEnabled(null).defaultA(null),
@@ -225,7 +225,7 @@ class ActionInteractionTest extends InteractionTestAbstract {
                 .checkUsability();
 
         val managedAction = actionInteraction.getManagedAction().get(); // should not throw
-        val pendingArgs = managedAction.getInteractionHead().defaults();
+        val pendingArgs = managedAction.startParameterNegotiation();
 
         val mixin = new InteractionDemo_multiInt(null);
         val expectedDefaults = Can.<Integer>of(
@@ -261,7 +261,7 @@ class ActionInteractionTest extends InteractionTestAbstract {
                 .checkUsability();
 
         val managedAction = actionInteraction.getManagedAction().get(); // should not throw
-        val pendingArgs = managedAction.getInteractionHead().defaults();
+        val pendingArgs = managedAction.startParameterNegotiation();
 
         val mixin = new InteractionDemo_multiEnum(null);
         val expectedDefaults = Can.<DemoEnum>of(
@@ -296,7 +296,7 @@ class ActionInteractionTest extends InteractionTestAbstract {
                 .checkUsability();
 
         val managedAction = actionInteraction.getManagedAction().get(); // should not throw
-        val pendingArgs = managedAction.getInteractionHead().defaults();
+        val pendingArgs = managedAction.startParameterNegotiation();
 
         val mixin = new InteractionDemo_biListOfString(null);
         val expectedDefaults = Can.<List<String>>of(
diff --git a/regressiontests/stable-interact/src/test/java/org/apache/isis/testdomain/interact/CollectionInteractionTest.java b/regressiontests/stable-interact/src/test/java/org/apache/isis/testdomain/interact/CollectionInteractionTest.java
index e570b83..cd75256 100644
--- a/regressiontests/stable-interact/src/test/java/org/apache/isis/testdomain/interact/CollectionInteractionTest.java
+++ b/regressiontests/stable-interact/src/test/java/org/apache/isis/testdomain/interact/CollectionInteractionTest.java
@@ -21,13 +21,10 @@ package org.apache.isis.testdomain.interact;
 import java.util.List;
 import java.util.stream.Collectors;
 
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.TestPropertySource;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.core.config.presets.IsisPresets;
 import org.apache.isis.core.metamodel.spec.ManagedObjects;
@@ -36,6 +33,8 @@ import org.apache.isis.testdomain.model.interaction.Configuration_usingInteracti
 import org.apache.isis.testdomain.model.interaction.InteractionDemo;
 import org.apache.isis.testdomain.util.interaction.InteractionTestAbstract;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
 import lombok.val;
 
 @SpringBootTest(
@@ -106,7 +105,7 @@ class CollectionInteractionTest extends InteractionTestAbstract {
 
     }
 
-    @Test @Disabled("FIXME[ISIS-2871]")
+    @Test
     void choicesFromMultiselect() {
 
         val collTester =
diff --git a/regressiontests/stable-interact/src/test/java/org/apache/isis/testdomain/interact/NewParameterModelTest.java b/regressiontests/stable-interact/src/test/java/org/apache/isis/testdomain/interact/NewParameterModelTest.java
index 7acc394..ff27c92 100644
--- a/regressiontests/stable-interact/src/test/java/org/apache/isis/testdomain/interact/NewParameterModelTest.java
+++ b/regressiontests/stable-interact/src/test/java/org/apache/isis/testdomain/interact/NewParameterModelTest.java
@@ -24,10 +24,6 @@ import org.junit.jupiter.api.Test;
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.TestPropertySource;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.core.config.presets.IsisPresets;
@@ -41,6 +37,10 @@ import org.apache.isis.testdomain.model.interaction.InteractionNpmDemo;
 import org.apache.isis.testdomain.model.interaction.InteractionNpmDemo_biArgEnabled;
 import org.apache.isis.testdomain.util.interaction.InteractionTestAbstract;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
 import lombok.val;
 
 @SpringBootTest(
@@ -150,7 +150,7 @@ class NewParameterModelTest extends InteractionTestAbstract {
                 .checkUsability();
 
         val managedAction = actionInteraction.getManagedAction().get(); // should not throw
-        val pendingArgs = managedAction.getInteractionHead().defaults();
+        val pendingArgs = managedAction.startParameterNegotiation();
 
         val expectedDefaults = Can.of(
                 new InteractionDemo_biArgEnabled(null).defaultA(null),
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/util/interaction/DomainObjectTesterFactory.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/util/interaction/DomainObjectTesterFactory.java
index 96b2134..09ee8f4 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/util/interaction/DomainObjectTesterFactory.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/util/interaction/DomainObjectTesterFactory.java
@@ -18,6 +18,7 @@
  */
 package org.apache.isis.testdomain.util.interaction;
 
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.function.Consumer;
@@ -30,12 +31,6 @@ import org.junit.jupiter.api.function.ThrowingSupplier;
 import org.springframework.lang.Nullable;
 import org.springframework.stereotype.Service;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
-
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.applib.exceptions.unrecoverable.DomainModelException;
@@ -74,6 +69,12 @@ import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.testdomain.util.CollectionAssertions;
 import org.apache.isis.testing.integtestsupport.applib.validate.DomainModelValidator;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
 import lombok.Getter;
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
@@ -318,6 +319,32 @@ public class DomainObjectTesterFactory {
 
         }
 
+        public Object invokeWithPojos(final List<Object> pojoArgList) {
+
+            assertExists(true);
+
+            val pojoVector = Can.ofCollection(pojoArgList);
+
+            return interactionService.callAnonymous(()->{
+
+                val pendingArgs = startParameterNegotiation(true);
+
+                pendingArgs.getParamModels()
+                        .forEach(param->{
+                            pojoVector
+                                .get(param.getParamNr())
+                                .ifPresent(pojo->param.updatePojo(__->pojo));
+                        });
+
+                //pendingArgs.validateParameterSetForParameters();
+
+                val resultOrVeto = actionInteraction.invokeWith(pendingArgs);
+                assertTrue(resultOrVeto.isLeft()); // assert action did not throw
+
+                return resultOrVeto.leftIfAny().getPojo();
+            });
+        }
+
         /**
          * circumvents rule checking
          */
@@ -446,6 +473,7 @@ public class DomainObjectTesterFactory {
                                     .orElse("no such action")));
         }
 
+
     }
 
     // -- PROPERTY TESTER
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/util/interaction/InteractionTestAbstract.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/util/interaction/InteractionTestAbstract.java
index 2c395a2..2c1fef5 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/util/interaction/InteractionTestAbstract.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/util/interaction/InteractionTestAbstract.java
@@ -29,10 +29,6 @@ import javax.inject.Inject;
 
 import org.springframework.lang.Nullable;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.applib.services.iactnlayer.InteractionService;
 import org.apache.isis.applib.services.wrapper.WrapperFactory;
@@ -49,6 +45,9 @@ import org.apache.isis.testdomain.util.CollectionAssertions;
 import org.apache.isis.testdomain.util.kv.KVStoreForTesting;
 import org.apache.isis.testing.integtestsupport.applib.IsisIntegrationTestAbstract;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
 import lombok.val;
 
 public abstract class InteractionTestAbstract extends IsisIntegrationTestAbstract {
@@ -90,24 +89,14 @@ public abstract class InteractionTestAbstract extends IsisIntegrationTestAbstrac
 
     // -- SHORTCUTS
 
-    protected Object invokeAction(final Class<?> type, final String actionId, final @Nullable List<Object> pojoArgList) {
-        val managedAction = startActionInteractionOn(type, actionId, Where.OBJECT_FORMS)
-                .getManagedAction().get(); // should not throw
-
-        assertFalse(managedAction.checkVisibility().isPresent()); // is visible
-        assertFalse(managedAction.checkUsability().isPresent()); // can invoke
-
-        val args = managedAction.getInteractionHead()
-                .getPopulatedParameterValues(pojoArgList);
-
-        // spawns its own transactional boundary, or reuses an existing one if available
-        val either = managedAction.invoke(args);
-
-        assertTrue(either.isLeft()); // assert action did not throw
-
-        val actionResultAsPojo = either.leftIfAny().getPojo();
+    protected Object invokeAction(
+            final Class<?> type, final String actionId, final @Nullable List<Object> pojoArgList) {
 
-        return actionResultAsPojo;
+        val actTester = testerFactory.actionTester(type, actionId);
+        actTester.assertExists(true);
+        actTester.assertVisibilityIsNotVetoed();
+        actTester.assertUsabilityIsNotVetoed();
+        return actTester.invokeWithPojos(pojoArgList);
     }
 
     // -- ASSERTIONS
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java
index 4e5309d..c9af1c4 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java
@@ -27,11 +27,11 @@ import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.commons.internal.collections._Maps;
-import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.interactions.managed.ManagedAction;
+import org.apache.isis.core.metamodel.interactions.managed.ManagedParameter;
+import org.apache.isis.core.metamodel.interactions.managed.ParameterNegotiationModel;
 import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
-import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
@@ -129,26 +129,31 @@ extends AbstractObjectMemberReprRenderer<ObjectAction> {
 
     private ObjectActionReprRenderer addParameterDetails() {
         final Map<String,Object> parameters = _Maps.newLinkedHashMap();
-        for (int i = 0; i < objectMember.getParameterCount(); i++) {
-            final ObjectActionParameter param = objectMember.getParameters().getElseFail(i);
-            final Object paramDetails = paramDetails(param, getInteractionInitiatedBy());
-            parameters.put(param.getId(), paramDetails);
+        if(objectMember.getParameterCount()>0) {
+            val act = ManagedAction.of(objectAdapter, objectMember, Where.ANYWHERE);
+            val paramNeg = act.startParameterNegotiation();
+            for(val paramMod : paramNeg.getParamModels()) {
+                val paramMeta = paramMod.getMetaModel();
+                final Object paramDetails = paramDetails(paramMod, paramNeg);
+                parameters.put(paramMeta.getId(), paramDetails);
+            }
         }
         representation.mapPut("parameters", parameters);
         return this;
     }
 
-    private Object paramDetails(final ObjectActionParameter param, final InteractionInitiatedBy interactionInitiatedBy) {
+    private Object paramDetails(final ManagedParameter paramMod, final ParameterNegotiationModel paramNeg) {
+        val paramMeta = paramMod.getMetaModel();
         final JsonRepresentation paramRep = JsonRepresentation.newMap();
-        paramRep.mapPut("num", param.getNumber());
-        paramRep.mapPut("id", param.getId());
-        paramRep.mapPut("name", param.getFriendlyName(objectAdapter.asProvider()));
-        paramRep.mapPut("description", param.getDescription(objectAdapter.asProvider()));
-        final Object paramChoices = choicesFor(param, interactionInitiatedBy);
+        paramRep.mapPut("num", paramMeta.getNumber());
+        paramRep.mapPut("id", paramMeta.getId());
+        paramRep.mapPut("name", paramMeta.getFriendlyName(objectAdapter.asProvider()));
+        paramRep.mapPut("description", paramMeta.getDescription(objectAdapter.asProvider()));
+        final Object paramChoices = choicesFor(paramMod, paramNeg);
         if (paramChoices != null) {
             paramRep.mapPut("choices", paramChoices);
         }
-        final Object paramDefault = defaultFor(param);
+        final Object paramDefault = defaultFor(paramMod);
         if (paramDefault != null) {
             paramRep.mapPut("default", paramDefault);
         }
@@ -156,14 +161,10 @@ extends AbstractObjectMemberReprRenderer<ObjectAction> {
     }
 
     private Object choicesFor(
-            final ObjectActionParameter param,
-            final InteractionInitiatedBy interactionInitiatedBy) {
-
-        val pendingArgs = param.getAction()
-                .interactionHead(objectAdapter)
-                .emptyModel();
-
-        val choiceAdapters = param.getChoices(pendingArgs, interactionInitiatedBy);
+            final ManagedParameter paramMod,
+            final ParameterNegotiationModel paramNeg) {
+        val paramMeta = paramMod.getMetaModel();
+        val choiceAdapters = paramMeta.getChoices(paramNeg, getInteractionInitiatedBy());
         if (choiceAdapters == null || choiceAdapters.isEmpty()) {
             return null;
         }
@@ -176,13 +177,8 @@ extends AbstractObjectMemberReprRenderer<ObjectAction> {
         return list;
     }
 
-    private Object defaultFor(final ObjectActionParameter param) {
-
-        val emptyParamTuple = param.getAction()
-                .interactionHead(objectAdapter)
-                .emptyModel();
-
-        val defaultAdapter = param.getDefault(emptyParamTuple);
+    private Object defaultFor(final ManagedParameter paramMod) {
+        val defaultAdapter = paramMod.getValue().getValue();
         if (ManagedObjects.isNullOrUnspecifiedOrEmpty(defaultAdapter)) {
             return null;
         }