This is an automated email from the ASF dual-hosted git repository. ahuber pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/isis.git
The following commit(s) were added to refs/heads/master by this push: new 0cf68bb ISIS-2340: refactor defaults negotiation logic into the PPM class 0cf68bb is described below commit 0cf68bbc40047eb72f96296d173c452e9140daec Author: Andi Huber <ahu...@apache.org> AuthorDate: Fri May 1 13:01:54 2020 +0200 ISIS-2340: refactor defaults negotiation logic into the PPM class --- .../defaults/ActionParameterDefaultsFacet.java | 11 ++- .../ActionParameterDefaultsFacetViaMethod.java | 90 ++++++++++++---------- ...meterDefaultsFacetFromAssociatedCollection.java | 10 +-- .../spec/feature/ObjectActionParameter.java | 6 +- .../specloader/specimpl/ObjectActionDefault.java | 57 ++++++-------- .../specimpl/ObjectActionParameterAbstract.java | 13 +--- .../specloader/specimpl/PendingParameterModel.java | 63 ++++++++++++++- .../viewer/wicket/model/models/ScalarModel.java | 38 +++++---- .../components/scalars/ScalarPanelAbstract2.java | 2 +- 9 files changed, 166 insertions(+), 124 deletions(-) diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/defaults/ActionParameterDefaultsFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/defaults/ActionParameterDefaultsFacet.java index 8c3d078..7222e24 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/defaults/ActionParameterDefaultsFacet.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/defaults/ActionParameterDefaultsFacet.java @@ -19,9 +19,10 @@ package org.apache.isis.core.metamodel.facets.param.defaults; -import org.apache.isis.core.commons.collections.Can; import org.apache.isis.core.metamodel.facetapi.Facet; -import org.apache.isis.core.metamodel.spec.ManagedObject; +import org.apache.isis.core.metamodel.specloader.specimpl.PendingParameterModel; + +import lombok.NonNull; /** * Obtain defaults for each of the parameters of the action. @@ -33,8 +34,6 @@ import org.apache.isis.core.metamodel.spec.ManagedObject; */ public interface ActionParameterDefaultsFacet extends Facet { - public abstract Object getDefault( - ManagedObject target, - Can<ManagedObject> parameters, - Integer paramNumUpdated); + /** default parameter value, depending on other pending parameters */ + Object getDefault(@NonNull PendingParameterModel pendingArgs); } diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/defaults/methodnum/ActionParameterDefaultsFacetViaMethod.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/defaults/methodnum/ActionParameterDefaultsFacetViaMethod.java index 0016a71..5c71240 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/defaults/methodnum/ActionParameterDefaultsFacetViaMethod.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/defaults/methodnum/ActionParameterDefaultsFacetViaMethod.java @@ -26,14 +26,13 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import org.apache.isis.core.commons.collections.Can; -import org.apache.isis.core.commons.internal.base._NullSafe; import org.apache.isis.core.metamodel.facetapi.FacetHolder; import org.apache.isis.core.metamodel.facets.ImperativeFacet; import org.apache.isis.core.metamodel.facets.param.defaults.ActionParameterDefaultsFacetAbstract; import org.apache.isis.core.metamodel.spec.ManagedObject; +import org.apache.isis.core.metamodel.specloader.specimpl.PendingParameterModel; -import lombok.val; +import lombok.NonNull; public class ActionParameterDefaultsFacetViaMethod extends ActionParameterDefaultsFacetAbstract implements ImperativeFacet { @@ -75,51 +74,58 @@ public class ActionParameterDefaultsFacetViaMethod extends ActionParameterDefaul } @Override - public Object getDefault( - final ManagedObject target, - final Can<ManagedObject> pendingArgs, - final Integer paramNumUpdated) { + public Object getDefault(@NonNull PendingParameterModel pendingArgs) { - if(ppmFactory.isPresent()) { + if(pendingArgs.isPopulated()) { - if(_NullSafe.isEmpty(pendingArgs)) { - return pendingArgs.get(paramNum) - .map(ManagedObject::getPojo) - .orElse(null) ; + // call with args: defaultNAct(X x, Y y, ...) + + if(ppmFactory.isPresent()) { + // PPM programming model + return ManagedObject.InvokeUtil + .invokeWithPPM(ppmFactory.get(), method, + pendingArgs.getActionTarget(), pendingArgs.getParamValues()); } - return ManagedObject.InvokeUtil.invokeWithPPM(ppmFactory.get(), method, target, pendingArgs); + // else legacy programming model + return ManagedObject.InvokeUtil + .invokeAutofit(method, + pendingArgs.getActionTarget(), pendingArgs.getParamValues()); } - // this isn't a dependent defaults situation, so just evaluate the default. - if (_NullSafe.isEmpty(pendingArgs) || paramNumUpdated == null) { - return ManagedObject.InvokeUtil.invokeAutofit(method, target, pendingArgs); - } - - // this could be a dependent defaults situation, but has a previous parameter been updated - // that this parameter is dependent upon? - final int numParams = method.getParameterCount(); - if (paramNumUpdated < numParams) { - // in this case the parameter that was updated is previous - // - // eg, suppose the method is default2Foo(int, int), and the second param is updated... we want to re-evaluate - // so numParams == 2, and paramNumUpdated == 1, and (paramNumUpdated < numParams) is TRUE - // - // conversely, if method default2Foo(int), and the second param is updated... we don't want to re-evaluate - // so numParams == 1, and paramNumUpdated == 1, and (paramNumUpdated < numParams) is FALSE - // - return ManagedObject.InvokeUtil.invokeAutofit(method, target, pendingArgs); - } - - // otherwise, just return the arguments that are already known; we don't want to recompute the default - // because if we did then this would trample over any pending changes already made by the end-user. - val argPojo = pendingArgs.stream() - .skip(paramNum) - .findFirst() - .map(ManagedObject::getPojo) - .orElse(null) ; - - return argPojo; + // call no-arg defaultNAct() instead + return ManagedObject.InvokeUtil.invoke(method, pendingArgs.getActionTarget()); + +// legacy of +// // this isn't a dependent defaults situation, so just evaluate the default. +// if (_NullSafe.isEmpty(pendingArgs) || paramNumUpdated == null) { +// return ManagedObject.InvokeUtil.invokeAutofit(method, target, pendingArgs); +// } +// +// // this could be a dependent defaults situation, but has a previous parameter been updated +// // that this parameter is dependent upon? +// final int numParams = method.getParameterCount(); +// if (paramNumUpdated < numParams) { +// // in this case the parameter that was updated is previous +// // +// // eg, suppose the method is default2Foo(int, int), and the second param is updated... we want to re-evaluate +// // so numParams == 2, and paramNumUpdated == 1, and (paramNumUpdated < numParams) is TRUE +// // +// // conversely, if method default2Foo(int), and the second param is updated... we don't want to re-evaluate +// // so numParams == 1, and paramNumUpdated == 1, and (paramNumUpdated < numParams) is FALSE +// // +// return ManagedObject.InvokeUtil.invokeAutofit(method, target, pendingArgs); +// } +// +// // otherwise, just return the arguments that are already known; we don't want to recompute the default +// // because if we did then this would trample over any pending changes already made by the end-user. +// val argPojo = pendingArgs.stream() +// .skip(paramNum) +// .findFirst() +// .map(ManagedObject::getPojo) +// .orElse(null) ; +// +// return argPojo; } @Override diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/param/ActionParameterDefaultsFacetFromAssociatedCollection.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/param/ActionParameterDefaultsFacetFromAssociatedCollection.java index dd5333c..40dc3d4 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/param/ActionParameterDefaultsFacetFromAssociatedCollection.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/param/ActionParameterDefaultsFacetFromAssociatedCollection.java @@ -25,7 +25,9 @@ import org.apache.isis.applib.ApplicationException; import org.apache.isis.core.commons.collections.Can; import org.apache.isis.core.metamodel.facetapi.FacetHolder; import org.apache.isis.core.metamodel.facets.param.defaults.ActionParameterDefaultsFacetAbstract; -import org.apache.isis.core.metamodel.spec.ManagedObject; +import org.apache.isis.core.metamodel.specloader.specimpl.PendingParameterModel; + +import lombok.NonNull; public class ActionParameterDefaultsFacetFromAssociatedCollection extends ActionParameterDefaultsFacetAbstract { @@ -51,13 +53,9 @@ public class ActionParameterDefaultsFacetFromAssociatedCollection extends Action } @Override - public Object getDefault( - final ManagedObject target, - final Can<ManagedObject> pendingArgs, - final Integer paramNumUpdated) { + public Object getDefault(@NonNull PendingParameterModel pendingArgs) { return _selectedPojos.get(); } - } 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 db45efb..2c08556 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 @@ -114,12 +114,10 @@ public interface ObjectActionParameter extends ObjectFeature, CurrentHolder { InteractionInitiatedBy interactionInitiatedBy); - ManagedObject getDefault( - PendingParameterModel pendingArgs, - Integer paramNumUpdated); + ManagedObject getDefault(PendingParameterModel pendingArgs); default ManagedObject getDefault(ManagedObject actionOnwer) { - return getDefault(getAction().newPendingParameterModel(actionOnwer), null); + return getDefault(getAction().newPendingParameterModel(actionOnwer)); } 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 6f023c3..ffc38eb 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 @@ -52,7 +52,6 @@ import org.apache.isis.core.metamodel.facets.actions.prototype.PrototypeFacet; import org.apache.isis.core.metamodel.facets.actions.semantics.ActionSemanticsFacet; import org.apache.isis.core.metamodel.facets.param.choices.ActionChoicesFacet; import org.apache.isis.core.metamodel.facets.param.choices.ActionParameterChoicesFacet; -import org.apache.isis.core.metamodel.facets.param.defaults.ActionParameterDefaultsFacet; import org.apache.isis.core.metamodel.interactions.ActionUsabilityContext; import org.apache.isis.core.metamodel.interactions.ActionValidityContext; import org.apache.isis.core.metamodel.interactions.ActionVisibilityContext; @@ -444,17 +443,18 @@ public class ObjectActionDefault extends ObjectMemberAbstract implements ObjectA @Override public Can<ManagedObject> getDefaults(final ManagedObject target) { - final int parameterCount = getParameterCount(); - val parameters = getParameters(); - - final Object[] parameterDefaultPojos; - - final ActionDefaultsFacet facet = getFacet(ActionDefaultsFacet.class); - if (!facet.isFallback()) { + val actionDefaultsFacet = getFacet(ActionDefaultsFacet.class); + if (!actionDefaultsFacet.isFallback()) { + // use the old defaultXxx approach - parameterDefaultPojos = facet.getDefaults(target); + + final int parameterCount = getParameterCount(); + val parameters = getParameters(); + final Object[] parameterDefaultPojos; + + parameterDefaultPojos = actionDefaultsFacet.getDefaults(target); if (parameterDefaultPojos.length != parameterCount) { - throw new DomainModelException("Defaults array of incompatible size; expected " + parameterCount + " elements, but was " + parameterDefaultPojos.length + " for " + facet); + throw new DomainModelException("Defaults array of incompatible size; expected " + parameterCount + " elements, but was " + parameterDefaultPojos.length + " for " + actionDefaultsFacet); } for (int i = 0; i < parameterCount; i++) { if (parameterDefaultPojos[i] != null) { @@ -466,34 +466,27 @@ public class ObjectActionDefault extends ObjectMemberAbstract implements ObjectA } } } - } else { - // use the new defaultNXxx approach for each param in turn - // (the reflector will have made sure both aren't installed). - parameterDefaultPojos = new Object[parameterCount]; + + final ManagedObject[] parameterDefaultAdapters = new ManagedObject[parameterCount]; for (int i = 0; i < parameterCount; i++) { - final ActionParameterDefaultsFacet paramFacet = parameters.getElseFail(i) - .getFacet(ActionParameterDefaultsFacet.class); - if (paramFacet != null && !paramFacet.isFallback()) { - parameterDefaultPojos[i] = paramFacet - .getDefault( - target, - Can.empty(), - null); - } else { - parameterDefaultPojos[i] = null; - } + val paramSpec = parameters.getElseFail(i).getSpecification(); + parameterDefaultAdapters[i] = ManagedObject.of(paramSpec, parameterDefaultPojos[i]); } - } - final ManagedObject[] parameterDefaultAdapters = new ManagedObject[parameterCount]; - for (int i = 0; i < parameterCount; i++) { - val paramSpec = parameters.getElseFail(i).getSpecification(); - parameterDefaultAdapters[i] = ManagedObject.of(paramSpec, parameterDefaultPojos[i]); - } + return Can.ofArray(parameterDefaultAdapters); + + } + + // else use the new defaultNXxx approach for each param in turn + // (the reflector will have made sure both aren't installed). + return newPendingParameterModel(target, Can.empty()) + .defaultsFixedPointSearch() + .getParamValues(); - return Can.ofArray(parameterDefaultAdapters); } + + private static ThreadLocal<List<ManagedObject>> commandTargetAdaptersHolder = new ThreadLocal<>(); /** diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionParameterAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionParameterAbstract.java index 26ba3f9..d615d0d 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionParameterAbstract.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionParameterAbstract.java @@ -271,20 +271,11 @@ implements ObjectActionParameter, FacetHolder.Delegating { @Override public ManagedObject getDefault( - final PendingParameterModel pendingArgs, - final Integer paramNumUpdated) { - - return findDefault(pendingArgs, paramNumUpdated); - } - - private ManagedObject findDefault( - final PendingParameterModel pendingArgs, - final Integer paramNumUpdated) { + final PendingParameterModel pendingArgs) { val defaultsFacet = getFacet(ActionParameterDefaultsFacet.class); if (defaultsFacet != null) { - final Object defaultValue = defaultsFacet - .getDefault(pendingArgs.getActionTarget(), pendingArgs.getParamValues(), paramNumUpdated); + final Object defaultValue = defaultsFacet.getDefault(pendingArgs); if (defaultValue == null) { // it's possible that even though there is a default facet, when // invoked it is unable to return a default. diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/PendingParameterModel.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/PendingParameterModel.java index 44030b3..7c7bb20 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/PendingParameterModel.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/PendingParameterModel.java @@ -18,13 +18,18 @@ */ package org.apache.isis.core.metamodel.specloader.specimpl; +import java.util.function.Function; + import org.apache.isis.core.commons.collections.Can; +import org.apache.isis.core.metamodel.facets.param.defaults.ActionParameterDefaultsFacet; import org.apache.isis.core.metamodel.spec.ManagedObject; +import org.apache.isis.core.metamodel.spec.ObjectSpecification; import org.apache.isis.core.metamodel.spec.feature.ObjectAction; import lombok.Getter; import lombok.NonNull; import lombok.RequiredArgsConstructor; +import lombok.val; /** * Model used to negotiate the paramValues of an action by means of a UI dialog. @@ -37,10 +42,64 @@ public class PendingParameterModel { @NonNull private final ObjectAction action; @NonNull private final ManagedObject actionOwner; - /** typically equal to {@code actionOwner}, except for mixins, where {@code actionTarget} - * is the mixin instance */ + + /** + * typically equal to {@code actionOwner}, except for mixins, where {@code actionTarget} + * is the mixin instance + */ @NonNull private final ManagedObject actionTarget; + + /** + * Has special meaning when empty, that is, this instance is only used + * to initialize phase 1 in step 1 of 'Fill in defaults' see + * <a href="https://cwiki.apache.org/confluence/display/ISIS/ActionParameterNegotiation"> + * ActionParameterNegotiation (wiki) + * </a> + */ @NonNull private final Can<ManagedObject> paramValues; + public final boolean isPopulated() { + return !paramValues.isEmpty(); + } + + + public PendingParameterModel defaultsFixedPointSearch() { + + val paramDefaultProviders = getParameterDefaultProviders(); + + val initialDefaults = paramDefaultProviders + .map(paramDefaultProvider->paramDefaultProvider.getDefault(this)); + + //TODO do fixed point search + + return PendingParameterModel.of(action, actionOwner, actionTarget, initialDefaults); + } + + // -- HELPER + + @RequiredArgsConstructor(staticName = "of") + private static final class ParameterDefaultProvider { + + final ObjectSpecification paramSpec; + final Function<PendingParameterModel, Object> defaultPojoProvider; + + ManagedObject getDefault(PendingParameterModel ppm) { + return ManagedObject.of(paramSpec, defaultPojoProvider.apply(ppm)); + } + } + + private Can<ParameterDefaultProvider> getParameterDefaultProviders() { + return action.getParameters().stream() + .map(objectActionParameter->{ + val paramSpec = objectActionParameter.getSpecification(); + val paramDefaultFacet = objectActionParameter.getFacet(ActionParameterDefaultsFacet.class); + return (paramDefaultFacet != null && !paramDefaultFacet.isFallback()) + ? ParameterDefaultProvider.of(paramSpec, ppm->paramDefaultFacet.getDefault(ppm)) + : ParameterDefaultProvider.of(paramSpec, ppm->null); + }) + .collect(Can.toCan()); + } + + } diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java index 15d76e6..09af95f 100644 --- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java +++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java @@ -187,8 +187,7 @@ implements LinksProvider, FormExecutorContext, ActionArgumentModel { @Override public ManagedObject getDefault( final ScalarModel scalarModel, - final Can<ManagedObject> pendingArgs, - final int paramNumUpdated) { + final Can<ManagedObject> pendingArgs) { final PropertyMemento propertyMemento = scalarModel.getPropertyMemento(); final OneToOneAssociation property = propertyMemento @@ -420,13 +419,11 @@ implements LinksProvider, FormExecutorContext, ActionArgumentModel { @Override public ManagedObject getDefault( final ScalarModel scalarModel, - final Can<ManagedObject> pendingArgs, - final int paramNumUpdated) { + final Can<ManagedObject> pendingArgs) { return withPendingParamsDo(scalarModel, pendingArgs, (pendingParamsModel, actionParameter)-> actionParameter.getDefault( - pendingParamsModel, - paramNumUpdated)); + pendingParamsModel)); } @Override @@ -466,18 +463,7 @@ implements LinksProvider, FormExecutorContext, ActionArgumentModel { InteractionInitiatedBy.USER)); } - // pending args helper - private <T> T withPendingParamsDo( - final ScalarModel scalarModel, - final Can<ManagedObject> pendingArgs, - final BiFunction<PendingParameterModel, ObjectActionParameter, T> function) { - - val parameterMemento = scalarModel.getParameterMemento(); - val actionParameter = parameterMemento.getActionParameter(scalarModel.getSpecificationLoader()); - val actionOwner = scalarModel.getParentEntityModel().load(); - val pendingParamsModel = actionParameter.getAction().newPendingParameterModel(actionOwner, pendingArgs); - return function.apply(pendingParamsModel, actionParameter); - } + @Override public int getAutoCompleteOrChoicesMinLength(ScalarModel scalarModel) { @@ -618,8 +604,7 @@ implements LinksProvider, FormExecutorContext, ActionArgumentModel { public abstract ManagedObject getDefault( ScalarModel scalarModel, - Can<ManagedObject> pendingArgs, - int paramNumUpdated); + Can<ManagedObject> pendingArgs); public abstract boolean hasChoices(ScalarModel scalarModel); public abstract Can<ManagedObject> getChoices( @@ -868,6 +853,19 @@ implements LinksProvider, FormExecutorContext, ActionArgumentModel { } } + // pending args helper + private static <T> T withPendingParamsDo( + final ScalarModel scalarModel, + final Can<ManagedObject> pendingArgs, + final BiFunction<PendingParameterModel, ObjectActionParameter, T> function) { + + val parameterMemento = scalarModel.getParameterMemento(); + val actionParameter = parameterMemento.getActionParameter(scalarModel.getSpecificationLoader()); + val actionOwner = scalarModel.getParentEntityModel().load(); + val pendingParamsModel = actionParameter.getAction().newPendingParameterModel(actionOwner, pendingArgs); + return function.apply(pendingParamsModel, actionParameter); + } + public boolean whetherHidden() { final Where where = getRenderingHint().asWhere(); return kind.whetherHidden(this, where); diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract2.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract2.java index c873ef2..039cc1b 100644 --- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract2.java +++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract2.java @@ -168,7 +168,7 @@ implements ScalarModelSubscriber2 { // (else can hit complicated edge cases with stale data when next re-enable/make visible) final ScalarModel model = getModel(); val defaultIfAny = model.getKind() - .getDefault(scalarModel, pendingArguments, paramNumUpdated); + .getDefault(scalarModel, pendingArguments); val actionParameterMemento = new ActionParameterMemento(actionParameter); val actionArgumentModel = actionModel.getArgumentModel(actionParameterMemento);