Skip to content

Commit

Permalink
Ignore mappings with non-matching LC state
Browse files Browse the repository at this point in the history
Mappings LC state other than "active" or "deprecated" are not visible
in the production-configuration mode now. (Preliminary implementation.)
  • Loading branch information
mederly committed Dec 13, 2022
1 parent 57c1b01 commit 9a57609
Show file tree
Hide file tree
Showing 14 changed files with 134 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.evolveum.midpoint.schema.processor.ResourceObjectDefinition;
import com.evolveum.midpoint.schema.processor.ResourceObjectTypeDefinition;
import com.evolveum.midpoint.util.annotation.Experimental;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AbstractMappingType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType;

Expand Down Expand Up @@ -76,4 +77,9 @@ public static boolean isInProduction(@NotNull ResourceType resource, @Nullable R
public static boolean isVisible(ObjectType object, TaskExecutionMode taskExecutionMode) {
return isInProduction(object) || !taskExecutionMode.isProductionConfiguration();
}

// TEMPORARY IMPLEMENTATION
public static boolean isVisible(AbstractMappingType mapping, TaskExecutionMode taskExecutionMode) {
return isInProduction(mapping.getLifecycleState()) || !taskExecutionMode.isProductionConfiguration();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.namespace.QName;

import com.evolveum.midpoint.schema.TaskExecutionMode;
import com.evolveum.midpoint.schema.processor.ResourceObjectDefinition;

import com.evolveum.midpoint.schema.util.SimulationUtil;

import org.jetbrains.annotations.Nullable;

import com.evolveum.midpoint.model.common.ModelCommonBeans;
Expand Down Expand Up @@ -341,6 +344,10 @@ public boolean isApplicableToChannel(String channel) {
return MappingImpl.isApplicableToChannel(mappingBean, channel);
}

public boolean isApplicableToExecutionMode(TaskExecutionMode executionMode) {
return SimulationUtil.isVisible(mappingBean, executionMode);
}

public RT additionalSource(Source<?, ?> source) {
additionalSources.add(source);
return typedThis();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ private void processCustomMappings()
throws CommunicationException, ObjectNotFoundException, SchemaException, SecurityViolationException,
ConfigurationException, ExpressionEvaluationException {
for (MetadataMappingType mappingBean : processingSpec.getMappings()) {
if (!env.task.canSee(mappingBean)) {
LOGGER.trace("Mapping {} is not visible for the current task, ignoring", mappingBean);
continue;
}
MetadataMappingImpl<?, ?> mapping = createMapping(mappingBean);
mapping.evaluate(env.task, result);
appendValues(mapping.getOutputPath(), mapping.getOutputTriple());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,41 +43,47 @@ public class MappingDiagEvaluator {
@Autowired private PrismContext prismContext;
@Autowired private Clock clock;

public MappingEvaluationResponseType evaluateMapping(@NotNull MappingEvaluationRequestType request, @NotNull Task task,
@NotNull OperationResult result)
throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, SecurityViolationException, ConfigurationException, CommunicationException {
public MappingEvaluationResponseType evaluateMapping(
@NotNull MappingEvaluationRequestType request, @NotNull Task task, @NotNull OperationResult result)
throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, SecurityViolationException,
ConfigurationException, CommunicationException {

MappingBuilder<?,?> builder = mappingFactory.createMappingBuilder();

ObjectDeltaObject<?> sourceContext = createSourceContext(request, task, result);

builder
.mappingBean(request.getMapping())
.mappingKind(MappingKindType.OTHER)
.contextDescription("mapping diagnostic execution")
.sourceContext(sourceContext)
.targetContext(createTargetContext(request, sourceContext))
.profiling(true)
.now(clock.currentTimeXMLGregorianCalendar());

MappingImpl<?,?> mapping = builder.build();

ExpressionEnvironmentThreadLocalHolder.pushExpressionEnvironment(new ExpressionEnvironment(task, result));
try {
mapping.evaluate(task, result);
} finally {
ExpressionEnvironmentThreadLocalHolder.popExpressionEnvironment();
}

StringBuilder sb = new StringBuilder();
sb.append("Output triple: ");
dumpOutputTriple(sb, mapping.getOutputTriple());
sb.append("Condition output triple: ");
dumpOutputTriple(sb, mapping.getConditionOutputTriple());
sb.append("Time constraint valid: ").append(mapping.isTimeConstraintValid()).append("\n");
sb.append("Next recompute time: ").append(mapping.getNextRecomputeTime()).append("\n");
sb.append("\n");
sb.append("Evaluation time: ").append(mapping.getEtime()).append(" ms\n");
MappingType mappingBean = request.getMapping();
if (task.canSee(mappingBean)) {
builder
.mappingBean(mappingBean)
.mappingKind(MappingKindType.OTHER)
.contextDescription("mapping diagnostic execution")
.sourceContext(sourceContext)
.targetContext(createTargetContext(request, sourceContext))
.profiling(true)
.now(clock.currentTimeXMLGregorianCalendar());

MappingImpl<?, ?> mapping = builder.build();

ExpressionEnvironmentThreadLocalHolder.pushExpressionEnvironment(new ExpressionEnvironment(task, result));
try {
mapping.evaluate(task, result);
} finally {
ExpressionEnvironmentThreadLocalHolder.popExpressionEnvironment();
}

sb.append("Output triple: ");
dumpOutputTriple(sb, mapping.getOutputTriple());
sb.append("Condition output triple: ");
dumpOutputTriple(sb, mapping.getConditionOutputTriple());
sb.append("Time constraint valid: ").append(mapping.isTimeConstraintValid()).append("\n");
sb.append("Next recompute time: ").append(mapping.getNextRecomputeTime()).append("\n");
sb.append("\n");
sb.append("Evaluation time: ").append(mapping.getEtime()).append(" ms\n");
} else {
sb.append("Mapping is not visible for the current task");
}

MappingEvaluationResponseType response = new MappingEvaluationResponseType();
response.setResponse(sb.toString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,32 +38,37 @@ class ConditionEvaluator {
this.ctx = evaluationContext;
}

ConditionState computeConditionState(MappingType condition, ObjectType source, String description, Object loggingDesc,
OperationResult result)
ConditionState computeConditionState(
MappingType condition, ObjectType source, String description, Object loggingDesc, OperationResult result)
throws SchemaException, CommunicationException, ObjectNotFoundException, ConfigurationException,
SecurityViolationException, ExpressionEvaluationException {
if (condition != null) {
if (condition == null) {
return ConditionState.allTrue();
} else if (!ctx.task.canSee(condition)) {
LOGGER.trace("Condition is not visible for the current task");
return ConditionState.allTrue();
} else {
AssignmentPathVariables assignmentPathVariables = LensUtil.computeAssignmentPathVariables(ctx.assignmentPath);
PrismValueDeltaSetTriple<PrismPropertyValue<Boolean>> conditionTripleAbsolute = evaluateConditionAbsolute(condition,
source, assignmentPathVariables,
description, ctx, result);
PrismValueDeltaSetTriple<PrismPropertyValue<Boolean>> conditionTripleRelative = evaluateConditionRelative(condition,
source, assignmentPathVariables,
description, ctx, result);
PrismValueDeltaSetTriple<PrismPropertyValue<Boolean>> conditionTripleAbsolute =
evaluateConditionAbsolute(condition, source, assignmentPathVariables, description, result);
PrismValueDeltaSetTriple<PrismPropertyValue<Boolean>> conditionTripleRelative =
evaluateConditionRelative(condition, source, assignmentPathVariables, description, result);
// TODO eliminate repeated "new" computation
boolean condOld = ExpressionUtil.computeConditionResult(conditionTripleAbsolute.getNonPositiveValues());
boolean condCurrent = ExpressionUtil.computeConditionResult(conditionTripleRelative.getNonPositiveValues());
boolean condNew = ExpressionUtil.computeConditionResult(conditionTripleAbsolute.getNonNegativeValues());
return ConditionState.from(condOld, condCurrent, condNew);
} else {
return ConditionState.allTrue();
}
}

private PrismValueDeltaSetTriple<PrismPropertyValue<Boolean>> evaluateConditionAbsolute(MappingType condition,
ObjectType source, AssignmentPathVariables assignmentPathVariables, String contextDescription, EvaluationContext<?> ctx,
OperationResult result) throws ExpressionEvaluationException,
ObjectNotFoundException, SchemaException, SecurityViolationException, ConfigurationException, CommunicationException {
private PrismValueDeltaSetTriple<PrismPropertyValue<Boolean>> evaluateConditionAbsolute(
MappingType condition,
ObjectType source,
AssignmentPathVariables assignmentPathVariables,
String contextDescription,
OperationResult result)
throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, SecurityViolationException,
ConfigurationException, CommunicationException {
MappingBuilder<PrismPropertyValue<Boolean>, PrismPropertyDefinition<Boolean>> builder =
ctx.ae.mappingFactory.createMappingBuilder();
builder = builder.mappingBean(condition)
Expand Down Expand Up @@ -91,8 +96,11 @@ private PrismValueDeltaSetTriple<PrismPropertyValue<Boolean>> evaluateConditionA
}

// TODO deduplicate, optimize
private PrismValueDeltaSetTriple<PrismPropertyValue<Boolean>> evaluateConditionRelative(MappingType condition,
ObjectType source, AssignmentPathVariables assignmentPathVariables, String contextDescription, EvaluationContext<?> ctx,
private PrismValueDeltaSetTriple<PrismPropertyValue<Boolean>> evaluateConditionRelative(
MappingType condition,
ObjectType source,
AssignmentPathVariables assignmentPathVariables,
String contextDescription,
OperationResult result) throws ExpressionEvaluationException,
ObjectNotFoundException, SchemaException, SecurityViolationException, ConfigurationException, CommunicationException {
MappingBuilder<PrismPropertyValue<Boolean>, PrismPropertyDefinition<Boolean>> builder =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,13 +154,14 @@ protected void checkNotYetEvaluated() {
return mappingBean;
}

public boolean hasEvaluatedMapping() {
boolean hasEvaluatedMapping() {
return evaluatedMapping != null && evaluatedMapping.isEnabled();
}

// TODO: unify with MappingEvaluator.evaluateOutboundMapping(...)
private MappingImpl<V, D> evaluateMapping()
throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException {
throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, CommunicationException,
ConfigurationException, SecurityViolationException {

MappingBuilder<V, D> mappingBuilder = construction.getMappingFactory().createMappingBuilder(mappingBean, getShortDesc());

Expand All @@ -169,8 +170,11 @@ private MappingImpl<V, D> evaluateMapping()

LensContext<AH> context = construction.lensContext;

if (construction.initializeMappingBuilder(mappingBuilder, itemPath, itemName, itemPrismDefinition,
getAssociationTargetObjectClassDefinition()) == null) {
mappingBuilder = construction.initializeMappingBuilder(
mappingBuilder, itemPath, itemName, itemPrismDefinition,
getAssociationTargetObjectClassDefinition(), constructionEvaluation.task);

if (mappingBuilder == null) {
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ private PrismValueDeltaSetTriple<PrismPropertyValue<String>> evaluateTagTriple(T
MappingBuilder<PrismPropertyValue<String>, PrismPropertyDefinition<String>> builder =
getMappingFactory().createMappingBuilder(tagMappingBean, "for outbound tag mapping in " + getSource());

builder = initializeMappingBuilder(builder, ShadowType.F_TAG, ShadowType.F_TAG, createTagDefinition(), null);
builder = initializeMappingBuilder(
builder, ShadowType.F_TAG, ShadowType.F_TAG, createTagDefinition(), null, task);
if (builder == null) {
return null;
}
Expand Down Expand Up @@ -243,13 +244,21 @@ private NextRecompute evaluateConstructions(Task task, OperationResult result)
* @return null if mapping is not applicable
*/
<V extends PrismValue, D extends ItemDefinition<?>> MappingBuilder<V, D> initializeMappingBuilder(
MappingBuilder<V, D> builder, ItemPath implicitTargetPath, QName mappingQName, D outputDefinition,
ResourceObjectTypeDefinition assocTargetObjectClassDefinition) throws SchemaException {
MappingBuilder<V, D> builder,
ItemPath implicitTargetPath,
QName mappingQName,
D outputDefinition,
ResourceObjectTypeDefinition assocTargetObjectClassDefinition,
Task task) throws SchemaException {

if (!builder.isApplicableToChannel(lensContext.getChannel())) {
LOGGER.trace("Skipping outbound mapping for {} because the channel does not match", implicitTargetPath);
return null;
}
if (!builder.isApplicableToExecutionMode(task.getExecutionMode())) {
LOGGER.trace("Skipping outbound mapping for {} because the execution mode does not match", implicitTargetPath);
return null;
}

ObjectDeltaObject<AH> focusOdoAbsolute = getFocusOdoAbsolute();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,12 @@ MappingImpl<V, D> createFocusMapping(
AssignmentPathVariables assignmentPathVariables = request.getAssignmentPathVariables();

if (!MappingImpl.isApplicableToChannel(mappingBean, context.getChannel())) {
LOGGER.trace("Mapping {} not applicable to channel {}, skipping.", mappingBean, context.getChannel());
LOGGER.trace("Mapping {} is not applicable to channel {}, skipping", mappingBean, context.getChannel());
return null;
}

if (!task.canSee(mappingBean)) {
LOGGER.trace("Mapping {} is not visible in the current task, skipping", mappingBean);
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,13 @@ Map<UniformItemPath, MappingOutputStruct<V>> evaluateMappingsToTriples(
LOGGER.trace("Mapping {} not applicable to channel, skipping {}", mappingName, params.getContext().getChannel());
continue;
}
if (!task.canSee(mappingBean)) {
LOGGER.trace("Mapping {} not applicable to the execution mode, skipping", mappingName);
continue;
}

mappingBuilder.now(params.getNow());
if (defaultTargetItemPath != null && targetObjectDefinition != null) {
if (defaultTargetItemPath != null) {
mappingBuilder.defaultTargetDefinition(
targetObjectDefinition.findItemDefinition(defaultTargetItemPath));
} else {
Expand Down Expand Up @@ -307,7 +311,7 @@ Map<UniformItemPath, MappingOutputStruct<V>> evaluateMappingsToTriples(
continue;
}

ItemDefinition targetItemDefinition;
D targetItemDefinition;
if (mappingOutputPath != null) {
targetItemDefinition = targetObjectDefinition.findItemDefinition(mappingOutputPath);
if (targetItemDefinition == null) {
Expand All @@ -317,7 +321,7 @@ Map<UniformItemPath, MappingOutputStruct<V>> evaluateMappingsToTriples(
targetItemDefinition = params.getTargetItemDefinition();
}
//noinspection unchecked
ItemDelta<V, D> targetItemDelta = targetItemDefinition.createEmptyDelta(mappingOutputPath);
ItemDelta<V, D> targetItemDelta = (ItemDelta<V, D>) targetItemDefinition.createEmptyDelta(mappingOutputPath);

Item<V, D> aPrioriTargetItem;
if (aPrioriTargetObject != null) {
Expand Down Expand Up @@ -377,12 +381,12 @@ Map<UniformItemPath, MappingOutputStruct<V>> evaluateMappingsToTriples(
}
targetItemDelta.setValuesToReplace(PrismValueCollectionsUtil.cloneCollection(valuesToReplace));

applyEstematedOldValueInReplaceCase(targetItemDelta, outputTriple);
applyEstimatedOldValueInReplaceCase(targetItemDelta, outputTriple);

} else if (outputTriple.hasMinusSet()) {
LOGGER.trace("{} resulted in null or empty value for {} and there is a minus set, resetting it (replace with empty)", mappingDesc, targetContext);
targetItemDelta.setValueToReplace();
applyEstematedOldValueInReplaceCase(targetItemDelta, outputTriple);
applyEstimatedOldValueInReplaceCase(targetItemDelta, outputTriple);

} else {
LOGGER.trace("{} resulted in null or empty value for {}, skipping", mappingDesc, targetContext);
Expand Down Expand Up @@ -422,8 +426,8 @@ Map<UniformItemPath, MappingOutputStruct<V>> evaluateMappingsToTriples(
}


private <V extends PrismValue, D extends ItemDefinition> void applyEstematedOldValueInReplaceCase(ItemDelta<V, D> targetItemDelta,
PrismValueDeltaSetTriple<V> outputTriple) {
private <V extends PrismValue, D extends ItemDefinition<?>> void applyEstimatedOldValueInReplaceCase(
ItemDelta<V, D> targetItemDelta, PrismValueDeltaSetTriple<V> outputTriple) {
Collection<V> nonPositiveValues = outputTriple.getNonPositiveValues();
if (nonPositiveValues.isEmpty()) {
return;
Expand All @@ -445,6 +449,7 @@ private <V extends PrismValue> boolean isMeaningful(PrismValueDeltaSetTriple<V>
// This may be used e.g. to remove existing password.
return true;
}
//noinspection RedundantIfStatement
if (hasNoOrHashedValuesOnly(mappingOutputTriple.getMinusSet()) && hasNoOrHashedValuesOnly(mappingOutputTriple.getZeroSet()) && hasNoOrHashedValuesOnly(mappingOutputTriple.getPlusSet())) {
// Used to skip application of mapping that produces only hashed protected values.
// Those values are useless, e.g. to set new password. If we would consider them as
Expand Down Expand Up @@ -474,7 +479,7 @@ private <V extends PrismValue> boolean hasNoOrHashedValuesOnly(Collection<V> set
return true;
}

private boolean hasNoValue(Item aPrioriTargetItem) {
private boolean hasNoValue(Item<?, ?> aPrioriTargetItem) {
return aPrioriTargetItem == null
|| (aPrioriTargetItem.isEmpty() && !aPrioriTargetItem.isIncomplete());
}
Expand Down

0 comments on commit 9a57609

Please sign in to comment.