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 2020/07/18 17:03:11 UTC
[isis] branch master updated: ISIS-2362: new prg.mod. for action
validation ... validate(P params)
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 dfccf5f ISIS-2362: new prg.mod. for action validation ... validate(P params)
dfccf5f is described below
commit dfccf5f453f4378b165cbdb67ac1deb3fcc6934b
Author: Andi Huber <ah...@apache.org>
AuthorDate: Sat Jul 18 19:02:52 2020 +0200
ISIS-2362: new prg.mod. for action validation ... validate(P params)
- in full support of
https://cwiki.apache.org/confluence/display/ISIS/ActionParameters?focusedCommentId=158867933#comment-158867933
---
.../isis/core/metamodel/facets/ActionSupport.java | 257 +++++++++++++++++++++
.../metamodel/facets/MethodLiteralConstants.java | 4 +-
.../method/ActionValidationFacetViaMethod.java | 18 +-
.../ActionValidationFacetViaMethodFactory.java | 74 ++++--
...ActionParameterHiddenFacetViaMethodFactory.java | 2 +-
.../InteractionNpmDemo_biArgDisabled.java | 33 ++-
6 files changed, 357 insertions(+), 31 deletions(-)
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/ActionSupport.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/ActionSupport.java
new file mode 100644
index 0000000..2cd5f3a
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/ActionSupport.java
@@ -0,0 +1,257 @@
+/*
+ * 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.facets;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nullable;
+
+import org.apache.isis.core.commons.collections.Can;
+import org.apache.isis.core.commons.internal._Constants;
+import org.apache.isis.core.commons.internal.base._NullSafe;
+import org.apache.isis.core.commons.internal.collections._Arrays;
+import org.apache.isis.core.metamodel.facets.MethodFinderUtils.MethodAndPpmConstructor;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+import lombok.Value;
+import lombok.val;
+import lombok.extern.log4j.Log4j2;
+
+@Log4j2
+public final class ActionSupport {
+
+ @Value @Builder
+ public static class ActionSupportingMethodSearchRequest {
+
+ public static enum ReturnType {
+ TEXT,
+ BOOLEAN,
+ }
+
+ @NonNull FacetFactory.ProcessMethodContext processMethodContext;
+ @NonNull Can<String> methodNames;
+ @NonNull EnumSet<SearchAlgorithm> searchAlgorithms;
+ @NonNull ReturnType returnType;
+
+ Class<?> additionalParamType;
+
+ @Getter(lazy = true)
+ Class<?>[] paramTypes = getProcessMethodContext().getMethod().getParameterTypes();
+
+ Can<String> getSupporingMethodNameCandidates() {
+ return methodNames;
+ }
+ }
+
+ @FunctionalInterface
+ public static interface SearchFunction {
+ ActionSupportingMethodSearchResult search(
+ ActionSupportingMethodSearchRequest searchRequest);
+ }
+
+ @RequiredArgsConstructor
+ public static enum SearchAlgorithm
+ implements SearchFunction {
+ PPM(ActionSupport::findActionSupportingMethodWithPPMArg),
+ ALL_PARAM_TYPES(ActionSupport::findActionSupportingMethodWithAllParamTypes),
+ ;
+ private final SearchFunction searchFunction;
+ public ActionSupportingMethodSearchResult search(
+ final ActionSupportingMethodSearchRequest searchRequest) {
+ return searchFunction.search(searchRequest);
+ }
+ }
+
+ @Value(staticConstructor = "of")
+ public static class ActionSupportingMethodSearchResult {
+ Method supportingMethod;
+ Class<?> returnType;
+ Optional<Constructor<?>> ppmFactory;
+ }
+
+ public static void findActionSupportingMethods(
+ final ActionSupportingMethodSearchRequest searchRequest,
+ final Consumer<ActionSupportingMethodSearchResult> onMethodFound) {
+
+ for (val searchAlgorithm : searchRequest.searchAlgorithms) {
+
+ val searchResult = searchAlgorithm.search(searchRequest);
+
+ if(log.isDebugEnabled()) {
+ log.debug("search algorithm={} {}",
+ searchAlgorithm.name(),
+ searchResult != null ? "FOUND " : "",
+ toString(searchRequest));
+ }
+
+ if (searchResult != null) {
+ onMethodFound.accept(searchResult);
+ }
+ }
+
+ }
+
+ // -- SEARCH ALGORITHMS
+
+ private final static ActionSupportingMethodSearchResult findActionSupportingMethodWithPPMArg(
+ final ActionSupportingMethodSearchRequest searchRequest) {
+
+ val processMethodContext = searchRequest.getProcessMethodContext();
+ val type = processMethodContext.getCls();
+ val paramTypes = searchRequest.getParamTypes();
+ val methodNames = searchRequest.getMethodNames();
+
+ val additionalParamTypes = Can.ofNullable(searchRequest.getAdditionalParamType());
+
+ final MethodAndPpmConstructor supportingMethodAndPpmConstructor;
+
+ switch(searchRequest.getReturnType()) {
+ case BOOLEAN:
+ supportingMethodAndPpmConstructor = MethodFinder2
+ .findMethodWithPPMArg_returningBoolean(type, methodNames, paramTypes, additionalParamTypes);
+ break;
+ case TEXT:
+ supportingMethodAndPpmConstructor = MethodFinder2
+ .findMethodWithPPMArg_returningText(type, methodNames, paramTypes, additionalParamTypes);
+ break;
+ default:
+ supportingMethodAndPpmConstructor = null;
+ }
+
+ if(log.isDebugEnabled()) {
+
+ log.debug(". signature (<any>, {}) {}",
+ toString(additionalParamTypes.toArray(_Constants.emptyClasses)),
+ supportingMethodAndPpmConstructor != null
+ ? "found -> " + supportingMethodAndPpmConstructor.getSupportingMethod()
+ : "");
+ }
+
+ if(supportingMethodAndPpmConstructor != null) {
+ val searchResult = ActionSupportingMethodSearchResult
+ .of(
+ supportingMethodAndPpmConstructor.getSupportingMethod(),
+ supportingMethodAndPpmConstructor.getSupportingMethod().getReturnType(),
+ Optional.of(supportingMethodAndPpmConstructor.getPpmFactory()));
+ return searchResult;
+ }
+
+ return null;
+ }
+
+ private final static ActionSupportingMethodSearchResult findActionSupportingMethodWithAllParamTypes(
+ final ActionSupportingMethodSearchRequest searchRequest) {
+
+ val processMethodContext = searchRequest.getProcessMethodContext();
+ val type = processMethodContext.getCls();
+ val paramTypes = searchRequest.getParamTypes();
+ val methodNames = searchRequest.getMethodNames();
+
+ val additionalParamType = searchRequest.getAdditionalParamType();
+ val additionalParamCount = additionalParamType!=null ? 1 : 0;
+
+ final int paramsConsideredCount = paramTypes.length + additionalParamCount;
+ if(paramsConsideredCount>=0) {
+
+ val paramTypesToLookFor = concat(paramTypes, paramsConsideredCount, additionalParamType);
+
+ final Method supportingMethod;
+
+ switch(searchRequest.getReturnType()) {
+ case BOOLEAN:
+ supportingMethod = MethodFinder2
+ .findMethod_returningBoolean(type, methodNames, paramTypesToLookFor);
+ break;
+ case TEXT:
+ supportingMethod = MethodFinder2
+ .findMethod_returningText(type, methodNames, paramTypesToLookFor);
+ break;
+ default:
+ supportingMethod = null;
+ }
+
+ if(log.isDebugEnabled()) {
+ log.debug(". signature ({}) {}",
+ toString(paramTypesToLookFor),
+ supportingMethod != null ? "found -> " + supportingMethod : "");
+ }
+
+ if(supportingMethod != null) {
+ val searchResult = ActionSupportingMethodSearchResult
+ .of(supportingMethod, supportingMethod.getReturnType(), Optional.empty());
+ return searchResult;
+ }
+ }
+
+ return null;
+ }
+
+ // -- PARAM UTIL
+
+ private static Class<?>[] concat(
+ final Class<?>[] paramTypes,
+ final int paramsConsidered,
+ @Nullable final Class<?> additionalParamType) {
+
+ if(paramsConsidered>paramTypes.length) {
+ val msg = String.format("paramsConsidered %d exceeds size of paramTypes %d",
+ paramsConsidered, paramTypes.length);
+ throw new IllegalArgumentException(msg);
+ }
+
+ val paramTypesConsidered = paramsConsidered<paramTypes.length
+ ? Arrays.copyOf(paramTypes, paramsConsidered)
+ : paramTypes;
+
+ val withAdditional = additionalParamType!=null
+ ? _Arrays.combine(paramTypesConsidered, additionalParamType)
+ : paramTypesConsidered;
+
+ return withAdditional;
+ }
+
+ // -- DEBUG LOGGING
+
+ private static String toString(
+ ActionSupportingMethodSearchRequest searchRequest) {
+
+ return String.format("%s.%s(%s) : %s",
+ searchRequest.getProcessMethodContext().getCls().getSimpleName(),
+ searchRequest.getSupporingMethodNameCandidates(),
+ toString(searchRequest.getParamTypes()),
+ searchRequest.getReturnType().name()
+ );
+ }
+
+ private static String toString(Class<?>[] types) {
+ return _NullSafe.stream(types)
+ .map(Class::getSimpleName)
+ .collect(Collectors.joining(","));
+ }
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/MethodLiteralConstants.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/MethodLiteralConstants.java
index 3b80695..3b3400c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/MethodLiteralConstants.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/MethodLiteralConstants.java
@@ -126,8 +126,8 @@ public final class MethodLiteralConstants {
}
@Override
protected String getMemberSupportingMethodName(Member member, String prefix) {
- // same as classic ???
- return PREFIX_PARAMNUM_ACTION.getMemberSupportingMethodName(member, prefix);
+ // prefix only
+ return prefix;
}
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/validate/method/ActionValidationFacetViaMethod.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/validate/method/ActionValidationFacetViaMethod.java
index e466a9a..92cd5dd 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/validate/method/ActionValidationFacetViaMethod.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/validate/method/ActionValidationFacetViaMethod.java
@@ -19,10 +19,12 @@
package org.apache.isis.core.metamodel.facets.actions.validate.method;
+import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import org.apache.isis.applib.services.i18n.TranslatableString;
import org.apache.isis.applib.services.i18n.TranslationService;
@@ -38,12 +40,20 @@ public class ActionValidationFacetViaMethod extends ActionValidationFacetAbstrac
private final Method method;
private final TranslationService translationService;
private final String translationContext;
+ private final Optional<Constructor<?>> ppmFactory;
- public ActionValidationFacetViaMethod(final Method method, final TranslationService translationService, final String translationContext, final FacetHolder holder) {
+ public ActionValidationFacetViaMethod(
+ final Method method,
+ final TranslationService translationService,
+ final String translationContext,
+ Optional<Constructor<?>> ppmFactory,
+ final FacetHolder holder) {
+
super(holder);
this.method = method;
this.translationService = translationService;
this.translationContext = translationContext;
+ this.ppmFactory = ppmFactory;
}
/**
@@ -62,7 +72,11 @@ public class ActionValidationFacetViaMethod extends ActionValidationFacetAbstrac
@Override
public String invalidReason(final ManagedObject owningAdapter, final Can<ManagedObject> proposedArgumentAdapters) {
- final Object returnValue = ManagedObjects.InvokeUtil.invoke(method, owningAdapter, proposedArgumentAdapters);
+
+ final Object returnValue = ppmFactory.isPresent()
+ ? ManagedObjects.InvokeUtil.invokeWithPPM(ppmFactory.get(), method, owningAdapter, proposedArgumentAdapters)
+ : ManagedObjects.InvokeUtil.invoke(method, owningAdapter, proposedArgumentAdapters);
+
if(returnValue instanceof String) {
return (String) returnValue;
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/validate/method/ActionValidationFacetViaMethodFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/validate/method/ActionValidationFacetViaMethodFactory.java
index 2483550..0ffef68 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/validate/method/ActionValidationFacetViaMethodFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/validate/method/ActionValidationFacetViaMethodFactory.java
@@ -19,15 +19,17 @@
package org.apache.isis.core.metamodel.facets.actions.validate.method;
-import java.lang.reflect.Method;
+import java.util.EnumSet;
-import org.apache.isis.applib.services.i18n.TranslationService;
import org.apache.isis.core.commons.collections.Can;
+import org.apache.isis.core.metamodel.exceptions.MetaModelException;
import org.apache.isis.core.metamodel.facetapi.FeatureType;
-import org.apache.isis.core.metamodel.facets.MethodFinder2;
+import org.apache.isis.core.metamodel.facets.ActionSupport;
+import org.apache.isis.core.metamodel.facets.ActionSupport.SearchAlgorithm;
import org.apache.isis.core.metamodel.facets.MethodLiteralConstants;
import org.apache.isis.core.metamodel.facets.MethodPrefixBasedFacetFactoryAbstract;
import org.apache.isis.core.metamodel.facets.actions.validate.ActionValidationFacet;
+import org.apache.isis.core.metamodel.facets.param.validate.method.ActionParameterValidationFacetViaMethod;
import lombok.val;
@@ -50,29 +52,61 @@ extends MethodPrefixBasedFacetFactoryAbstract {
private void handleValidateAllArgsMethod(final ProcessMethodContext processMethodContext) {
- val cls = processMethodContext.getCls();
+ //val cls = processMethodContext.getCls();
val actionMethod = processMethodContext.getMethod();
val facetHolder = processMethodContext.getFacetHolder();
- val paramTypes = actionMethod.getParameterTypes();
+ //val paramTypes = actionMethod.getParameterTypes();
val namingConvention = PREFIX_BASED_NAMING.map(naming->naming.providerForAction(actionMethod, PREFIX));
- final Method validateMethod = MethodFinder2.findMethod_returningText(
- cls,
- namingConvention.map(x->x.get()),
- paramTypes);
- if (validateMethod == null) {
- return;
- }
- processMethodContext.removeMethod(validateMethod);
-
- final TranslationService translationService = getTranslationService();
- // sadness: same as in TranslationFactory
- final String translationContext = facetHolder.getIdentifier().toClassAndNameIdentityString();
- final ActionValidationFacetViaMethod facet =
- new ActionValidationFacetViaMethod(validateMethod, translationService, translationContext, facetHolder);
- super.addFacet(facet);
+ val searchRequest = ActionSupport.ActionSupportingMethodSearchRequest.builder()
+ .processMethodContext(processMethodContext)
+ .returnType(ActionSupport.ActionSupportingMethodSearchRequest.ReturnType.TEXT)
+ .methodNames(namingConvention.map(x->x.get()))
+ .searchAlgorithms(EnumSet.of(SearchAlgorithm.PPM, SearchAlgorithm.ALL_PARAM_TYPES))
+ .build();
+
+ ActionSupport.findActionSupportingMethods(searchRequest, searchResult -> {
+ val validateMethod = searchResult.getSupportingMethod();
+
+ processMethodContext.removeMethod(validateMethod);
+
+ if (facetHolder.containsNonFallbackFacet(ActionValidationFacetViaMethod.class)) {
+ throw new MetaModelException( processMethodContext.getCls() + " uses both old and new 'validate' syntax - "
+ + "must use one or other");
+ }
+
+ val ppmFactory = searchResult.getPpmFactory();
+ val translationService = getTranslationService();
+ val translationContext = facetHolder.getIdentifier().toClassAndNameIdentityString();
+ super.addFacet(
+ new ActionValidationFacetViaMethod(
+ validateMethod, translationService, translationContext, ppmFactory, facetHolder));
+ });
+
+// final Method validateMethod = MethodFinder2.findMethod_returningText(
+// cls,
+// namingConvention.map(x->x.get()),
+// paramTypes);
+//
+// val validateMethodPpm = MethodFinder2.findMethodWithPPMArg_returningText(
+// cls,
+// namingConvention.map(x->x.get()),
+// paramTypes,
+// Can.empty());
+// if (validateMethod == null) {
+// return;
+// }
+// processMethodContext.removeMethod(validateMethod);
+//
+// final TranslationService translationService = getTranslationService();
+// final String translationContext = facetHolder.getIdentifier().toClassAndNameIdentityString();
+// final ActionValidationFacetViaMethod facet =
+// new ActionValidationFacetViaMethod(validateMethod, translationService, translationContext, facetHolder);
+// super.addFacet(facet);
+
+
}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/hide/method/ActionParameterHiddenFacetViaMethodFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/hide/method/ActionParameterHiddenFacetViaMethodFactory.java
index 07e6ec8..70b1d5d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/hide/method/ActionParameterHiddenFacetViaMethodFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/hide/method/ActionParameterHiddenFacetViaMethodFactory.java
@@ -64,7 +64,7 @@ public class ActionParameterHiddenFacetViaMethodFactory extends MethodPrefixBase
.returnType(ReturnType.BOOLEAN)
.paramIndexToMethodNameProviders(namingConvention)
.searchAlgorithms(EnumSet.of(SearchAlgorithm.PPM, SearchAlgorithm.SWEEP))
- .build();
+ .build();
ParameterSupport.findParamSupportingMethods(searchRequest, searchResult -> {
diff --git a/examples/smoketests/stable/src/main/java/org/apache/isis/testdomain/model/interaction/InteractionNpmDemo_biArgDisabled.java b/examples/smoketests/stable/src/main/java/org/apache/isis/testdomain/model/interaction/InteractionNpmDemo_biArgDisabled.java
index c88792e..9f21acb 100644
--- a/examples/smoketests/stable/src/main/java/org/apache/isis/testdomain/model/interaction/InteractionNpmDemo_biArgDisabled.java
+++ b/examples/smoketests/stable/src/main/java/org/apache/isis/testdomain/model/interaction/InteractionNpmDemo_biArgDisabled.java
@@ -43,16 +43,37 @@ public class InteractionNpmDemo_biArgDisabled {
return a + b;
}
- //TODO[ISIS-2362] supporting methods (no arg): rename -> disable()
@Model
- public String disableAct() {
+ public boolean hide() {
+ return false;
+ }
+
+ @Model
+ public String disable() {
return "Disabled for demonstration.";
}
- //TODO[ISIS-2362] supporting methods (no arg): rename -> validate()
- //TODO[ISIS-2362] supporting methods (all args): rename -> validate(params)
- //@Model //FIXME not recognized by method finders (metamodel)
- public String validateAct(Parameters params) {
+ @Model
+ public String validate(Parameters params) {
return "Never valid for demonstration.";
}
+
+ // -- PARAM SUPPORTING METHODS
+
+ // testing whether all of these get picked up by the meta-model
+
+ @Model public boolean hideA(Parameters params) { return false; }
+ @Model public String disableA(Parameters params) { return null; }
+ @Model public String validateA(Parameters params) { return null; }
+ @Model public int[] choicesA(Parameters params) { return null; }
+ @Model public int[] autoCompleteA(Parameters params, String search) { return null; }
+ @Model public int defaultA(Parameters params) { return 0; }
+
+ @Model public boolean hideB(Parameters params) { return false; }
+ @Model public String disableB(Parameters params) { return null; }
+ @Model public String validateB(Parameters params) { return null; }
+ @Model public int[] choicesB(Parameters params) { return null; }
+ @Model public int[] autoCompleteB(Parameters params, String search) { return null; }
+ @Model public int defaultB(Parameters params) { return 0; }
+
}