From 5b0cf8fde1ea8a095a0201e6e554052cb6d2f352 Mon Sep 17 00:00:00 2001 From: Pavol Mederly Date: Mon, 24 Aug 2020 17:17:52 +0200 Subject: [PATCH] Support metadata computation in more evaluators Now we compute metadata not only in transformational evaluator (mostly - givenName @@ -91,11 +86,6 @@ ri:lastname strong - - - familyName @@ -105,11 +95,6 @@ ri:organization strong - - - organization diff --git a/model/model-intest/src/test/resources/metadata/provenance-metadata-recording/resource-hr.xml b/model/model-intest/src/test/resources/metadata/provenance-metadata-recording/resource-hr.xml index 4590450b32a..53fbd73248c 100644 --- a/model/model-intest/src/test/resources/metadata/provenance-metadata-recording/resource-hr.xml +++ b/model/model-intest/src/test/resources/metadata/provenance-metadata-recording/resource-hr.xml @@ -82,11 +82,6 @@ ri:firstname strong - - - givenName @@ -96,11 +91,6 @@ ri:lastname strong - - - familyName @@ -110,11 +100,6 @@ ri:organization strong - - - organization diff --git a/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/evaluator/AbstractExpressionEvaluator.java b/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/evaluator/AbstractExpressionEvaluator.java index 5fef696a57b..ace8f3fb2df 100644 --- a/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/evaluator/AbstractExpressionEvaluator.java +++ b/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/evaluator/AbstractExpressionEvaluator.java @@ -8,17 +8,24 @@ import javax.xml.namespace.QName; -import com.evolveum.midpoint.prism.ItemDefinition; -import com.evolveum.midpoint.prism.PrismContext; -import com.evolveum.midpoint.prism.PrismValue; +import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.crypto.Protector; +import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.xml.XsdTypeMapper; import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluationContext; import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluator; import com.evolveum.midpoint.repo.common.expression.ExpressionUtil; -import com.evolveum.midpoint.util.exception.SecurityViolationException; +import com.evolveum.midpoint.repo.common.expression.Source; +import com.evolveum.midpoint.schema.expression.TypedValue; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.util.exception.*; import org.jetbrains.annotations.NotNull; +import java.util.Collections; +import java.util.function.Function; + /** * @param evaluator bean (configuration) type * @author Radovan Semancik @@ -62,7 +69,7 @@ public AbstractExpressionEvaluator(@NotNull QName elementName, E expressionEvalu /** * Check expression profile. Throws security exception if the execution is not allowed by the profile. - * + *

* This implementation works only for simple evaluators that do not have any profile settings. * Complex evaluators should override this method. * @@ -75,4 +82,103 @@ protected void checkEvaluatorProfile(ExpressionEvaluationContext context) throws public @NotNull PrismContext getPrismContext() { return prismContext; } + + public D getOutputDefinition() { + return outputDefinition; + } + + public Protector getProtector() { + return protector; + } + + /** + * Converts intermediate expression result triple to the final output triple + * according to expected Java type and additional convertor. + * + * TODO why it is used only for some evaluators? + */ + public PrismValueDeltaSetTriple finishOutputTriple(PrismValueDeltaSetTriple resultTriple, + Function additionalConvertor, ItemPath residualPath) { + + if (resultTriple == null) { + return null; + } + + final Class resultTripleValueClass = resultTriple.getRealValueClass(); + if (resultTripleValueClass == null) { + // triple is empty. type does not matter. + return resultTriple; + } + Class expectedJavaType = getClassForType(outputDefinition.getTypeName()); + if (resultTripleValueClass == expectedJavaType) { + return resultTriple; + } + + resultTriple.accept(visitable -> { + if (visitable instanceof PrismPropertyValue) { + //noinspection unchecked + PrismPropertyValue pval = (PrismPropertyValue) visitable; + Object realVal = pval.getValue(); + if (realVal != null) { + if (Structured.class.isAssignableFrom(resultTripleValueClass)) { + if (residualPath != null && !residualPath.isEmpty()) { + realVal = ((Structured) realVal).resolve(residualPath); + } + } + if (expectedJavaType != null) { + Object convertedVal = ExpressionUtil.convertValue(expectedJavaType, additionalConvertor, realVal, protector, prismContext); + pval.setValue(convertedVal); + } + } + } + }); + return resultTriple; + } + + // TODO this should be a standard method + private Class getClassForType(@NotNull QName typeName) { + Class aClass = XsdTypeMapper.toJavaType(typeName); + if (aClass != null) { + return aClass; + } else { + return prismContext.getSchemaRegistry().getCompileTimeClass(typeName); + } + } + + public TypedValue findInSourcesAndVariables(ExpressionEvaluationContext context, String variableName) { + for (Source source : context.getSources()) { + if (variableName.equals(source.getName().getLocalPart())) { + return new TypedValue<>(source, source.getDefinition()); + } + } + + if (context.getVariables() != null) { + return context.getVariables().get(variableName); + } else { + return null; + } + } + + public void applyValueMetadata(PrismValueDeltaSetTriple triple, ExpressionEvaluationContext context, + OperationResult result) throws CommunicationException, ObjectNotFoundException, SchemaException, + SecurityViolationException, ConfigurationException, ExpressionEvaluationException { + if (triple != null && context.getValueMetadataComputer() != null) { + for (V value : triple.getPlusSet()) { + applyValueMetadata(value, context, result); + } + for (V value : triple.getZeroSet()) { + applyValueMetadata(value, context, result); + } + } + } + + private void applyValueMetadata(PrismValue value, ExpressionEvaluationContext context, OperationResult result) + throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException, + ConfigurationException, ExpressionEvaluationException { + if (value != null) { + value.setValueMetadata( + context.getValueMetadataComputer() + .compute(Collections.singletonList(value), result)); + } + } } diff --git a/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/evaluator/AsIsExpressionEvaluator.java b/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/evaluator/AsIsExpressionEvaluator.java index a593a9a4c58..d0e5a10c55f 100644 --- a/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/evaluator/AsIsExpressionEvaluator.java +++ b/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/evaluator/AsIsExpressionEvaluator.java @@ -17,10 +17,7 @@ import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluationContext; import com.evolveum.midpoint.repo.common.expression.Source; import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.util.exception.SecurityViolationException; +import com.evolveum.midpoint.util.exception.*; import com.evolveum.midpoint.xml.ns._public.common.common_3.AsIsExpressionEvaluatorType; /** @@ -37,7 +34,8 @@ public class AsIsExpressionEvaluator evaluate(ExpressionEvaluationContext context, OperationResult result) - throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, SecurityViolationException { + throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, SecurityViolationException, + CommunicationException, ConfigurationException { checkEvaluatorProfile(context); @@ -58,14 +56,11 @@ public PrismValueDeltaSetTriple evaluate(ExpressionEvaluationContext context, //noinspection unchecked source = (Source) context.getSources().iterator().next(); } - PrismValueDeltaSetTriple sourceTriple = ItemDeltaUtil.toDeltaSetTriple(source.getItemOld(), source.getDelta(), + PrismValueDeltaSetTriple outputTriple = ItemDeltaUtil.toDeltaSetTriple(source.getItemOld(), source.getDelta(), prismContext); - if (sourceTriple == null) { - return null; - } - return ExpressionEvaluatorUtil.toOutputTriple(sourceTriple, outputDefinition, context.getAdditionalConvertor(), - source.getResidualPath(), protector, prismContext); + applyValueMetadata(outputTriple, context, result); + return finishOutputTriple(outputTriple, context.getAdditionalConvertor(), source.getResidualPath()); } @Override diff --git a/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/evaluator/ExpressionEvaluatorUtil.java b/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/evaluator/ExpressionEvaluatorUtil.java deleted file mode 100644 index a8cd53e2395..00000000000 --- a/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/evaluator/ExpressionEvaluatorUtil.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2020 Evolveum and contributors - * - * This work is dual-licensed under the Apache License 2.0 - * and European Union Public License. See LICENSE file for details. - */ - -package com.evolveum.midpoint.repo.common.expression.evaluator; - -import com.evolveum.midpoint.prism.*; -import com.evolveum.midpoint.prism.crypto.Protector; -import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple; -import com.evolveum.midpoint.prism.path.ItemPath; -import com.evolveum.midpoint.prism.xml.XsdTypeMapper; -import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluationContext; -import com.evolveum.midpoint.repo.common.expression.ExpressionUtil; - -import com.evolveum.midpoint.repo.common.expression.Source; -import com.evolveum.midpoint.schema.expression.TypedValue; - -import org.jetbrains.annotations.NotNull; - -import javax.xml.namespace.QName; -import java.util.function.Function; - -/** - * Utilities that are used by expression evaluators only. - * (In contrast with ExpressionUtil that are used system-wide.) - */ -public class ExpressionEvaluatorUtil { - - /** - * Converts intermediate expression result triple to the final output triple. - */ - public static PrismValueDeltaSetTriple toOutputTriple( - PrismValueDeltaSetTriple resultTriple, ItemDefinition outputDefinition, - Function additionalConvertor, - ItemPath residualPath, Protector protector, PrismContext prismContext) { - - PrismValueDeltaSetTriple clonedTriple = resultTriple.clone(); - - final Class resultTripleValueClass = resultTriple.getRealValueClass(); - if (resultTripleValueClass == null) { - // triple is empty. type does not matter. - return clonedTriple; - } - Class expectedJavaType = getClassForType(outputDefinition.getTypeName(), prismContext); - if (resultTripleValueClass == expectedJavaType) { - return clonedTriple; - } - - clonedTriple.accept((Visitor) visitable -> { - if (visitable instanceof PrismPropertyValue) { - //noinspection unchecked - PrismPropertyValue pval = (PrismPropertyValue) visitable; - Object realVal = pval.getValue(); - if (realVal != null) { - if (Structured.class.isAssignableFrom(resultTripleValueClass)) { - if (residualPath != null && !residualPath.isEmpty()) { - realVal = ((Structured) realVal).resolve(residualPath); - } - } - if (expectedJavaType != null) { - Object convertedVal = ExpressionUtil.convertValue(expectedJavaType, additionalConvertor, realVal, protector, prismContext); - pval.setValue(convertedVal); - } - } - } - }); - return clonedTriple; - } - - // TODO this should be a standard method - private static Class getClassForType(@NotNull QName typeName, PrismContext prismContext) { - Class aClass = XsdTypeMapper.toJavaType(typeName); - if (aClass != null) { - return aClass; - } else { - return prismContext.getSchemaRegistry().getCompileTimeClass(typeName); - } - } - - public static TypedValue findInSourcesAndVariables(ExpressionEvaluationContext context, String variableName) { - for (Source source : context.getSources()) { - if (variableName.equals(source.getName().getLocalPart())) { - return new TypedValue<>(source, source.getDefinition()); - } - } - - if (context.getVariables() != null) { - return context.getVariables().get(variableName); - } else { - return null; - } - } -} diff --git a/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/evaluator/LiteralExpressionEvaluator.java b/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/evaluator/LiteralExpressionEvaluator.java index 72895ff4fb1..50867806095 100644 --- a/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/evaluator/LiteralExpressionEvaluator.java +++ b/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/evaluator/LiteralExpressionEvaluator.java @@ -6,49 +6,54 @@ */ package com.evolveum.midpoint.repo.common.expression.evaluator; +import java.util.Collection; +import javax.xml.bind.JAXBElement; import javax.xml.namespace.QName; +import com.evolveum.midpoint.common.StaticExpressionUtil; +import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.ItemDefinition; +import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismValue; +import com.evolveum.midpoint.prism.crypto.Protector; +import com.evolveum.midpoint.prism.delta.ItemDeltaUtil; import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple; import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluationContext; -import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluator; import com.evolveum.midpoint.repo.common.expression.ExpressionUtil; import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.util.exception.SecurityViolationException; +import com.evolveum.midpoint.util.exception.*; /** * Always returns zero set with literal value (values) specified in the evaluator. Plus and minus sets are empty. * - * @author Radovan Semancik + * Note: using evaluatorElements as "expressionEvaluatorBean" is a bit strange. It is because I am too lazy to find more + * appropriate name for the field. Moreover, for all other uses it really _is_ the expression evaluator bean. So leaving + * fixing this to the future. [pmed] */ -public class LiteralExpressionEvaluator implements ExpressionEvaluator { +public class LiteralExpressionEvaluator + extends AbstractExpressionEvaluator>> { - private final QName elementName; - private final PrismValueDeltaSetTriple outputTriple; - - LiteralExpressionEvaluator(QName elementName, PrismValueDeltaSetTriple outputTriple) { - this.elementName = elementName; - this.outputTriple = outputTriple; + LiteralExpressionEvaluator(QName elementName, Collection> evaluatorElements, + D outputDefinition, Protector protector, PrismContext prismContext) { + super(elementName, evaluatorElements, outputDefinition, protector, prismContext); } @Override public PrismValueDeltaSetTriple evaluate(ExpressionEvaluationContext context, OperationResult result) - throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, SecurityViolationException { + throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, SecurityViolationException, + CommunicationException, ConfigurationException { + ExpressionUtil.checkEvaluatorProfileSimple(this, context); - return outputTriple != null ? outputTriple.clone() : null; - } - @Override - public QName getElementName() { - return elementName; + Item output = StaticExpressionUtil.parseValueElements(expressionEvaluatorBean, outputDefinition, context.getContextDescription()); + + PrismValueDeltaSetTriple outputTriple = ItemDeltaUtil.toDeltaSetTriple(output, null, prismContext); + applyValueMetadata(outputTriple, context, result); + return outputTriple; } @Override public String shortDebugDump() { - return "literal: "+outputTriple; + return "literal: "+expressionEvaluatorBean; // TODO } } diff --git a/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/evaluator/LiteralExpressionEvaluatorFactory.java b/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/evaluator/LiteralExpressionEvaluatorFactory.java index d9329b32db1..ec26b6ee7b4 100644 --- a/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/evaluator/LiteralExpressionEvaluatorFactory.java +++ b/repo/repo-common/src/main/java/com/evolveum/midpoint/repo/common/expression/evaluator/LiteralExpressionEvaluatorFactory.java @@ -7,30 +7,25 @@ package com.evolveum.midpoint.repo.common.expression.evaluator; import java.util.Collection; - import javax.xml.bind.JAXBElement; import javax.xml.namespace.QName; -import com.evolveum.midpoint.prism.delta.ItemDeltaUtil; -import com.evolveum.midpoint.schema.SchemaConstantsGenerated; -import com.evolveum.midpoint.task.api.Task; - import com.google.common.annotations.VisibleForTesting; import org.apache.commons.lang.Validate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import com.evolveum.midpoint.common.StaticExpressionUtil; -import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.ItemDefinition; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismValue; -import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple; +import com.evolveum.midpoint.prism.crypto.Protector; import com.evolveum.midpoint.repo.common.expression.AbstractAutowiredExpressionEvaluatorFactory; import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluator; import com.evolveum.midpoint.repo.common.expression.ExpressionFactory; +import com.evolveum.midpoint.schema.SchemaConstantsGenerated; import com.evolveum.midpoint.schema.expression.ExpressionProfile; import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.exception.SchemaException; /** @@ -42,6 +37,7 @@ public class LiteralExpressionEvaluatorFactory extends AbstractAutowiredExpressi private static final QName ELEMENT_NAME = SchemaConstantsGenerated.C_VALUE; @Autowired private PrismContext prismContext; + @Autowired private Protector protector; @SuppressWarnings("unused") // Used by Spring public LiteralExpressionEvaluatorFactory() { @@ -64,10 +60,6 @@ public ExpressionEvaluator cr Validate.notNull(outputDefinition, "output definition must be specified for literal expression evaluator"); - Item output = StaticExpressionUtil.parseValueElements(evaluatorElements, outputDefinition, contextDescription); - - PrismValueDeltaSetTriple deltaSetTriple = ItemDeltaUtil.toDeltaSetTriple(output, null, prismContext); - - return new LiteralExpressionEvaluator<>(ELEMENT_NAME, deltaSetTriple); + return new LiteralExpressionEvaluator<>(ELEMENT_NAME, evaluatorElements, outputDefinition, protector, prismContext); } }