Skip to content

Commit

Permalink
Improve assigned mappings evaluation
Browse files Browse the repository at this point in the history
1) Implemented assigned mapping chaining (MID-5753)
2) Fixed mappings evaluation from invalid assignments (MID-4430)
3) Fixed mappings evaluation from disabled roles (MID-4449)
4) Fixed mappings evaluation when condition changes (MID-5783)
5) Fixed mappings eval. when assignments are being deleted (MID-4452)

Also improved mapping chaining in general, providing better logging
and partial chaining in cases when total ordering is not possible.
  • Loading branch information
mederly committed Sep 21, 2019
1 parent 4b6d649 commit 5caec04
Show file tree
Hide file tree
Showing 21 changed files with 631 additions and 229 deletions.
Expand Up @@ -96,8 +96,7 @@ public boolean hasAnyObject() {
public void update(ItemDelta<?, ?> itemDelta) throws SchemaException {
if (delta == null) {
delta = getAnyObject().getPrismContext().deltaFactory().object()
.createModifyDelta(getAnyObject().getOid(), itemDelta, getAnyObject().getCompileTimeClass()
);
.createModifyDelta(getAnyObject().getOid(), itemDelta, getAnyObject().getCompileTimeClass());
} else {
delta.swallow(itemDelta);
itemDelta.applyTo(newObject);
Expand Down
Expand Up @@ -98,6 +98,7 @@ public void setValue(PrismContainerValue<C> value) throws SchemaException {
realContainer.setValue(value);
}

@NotNull
public PrismContainerValue<C> getValue() {
return realContainer.getValue();
}
Expand Down
Expand Up @@ -503,16 +503,15 @@ private <O extends ObjectType> boolean evaluateSegmentContent(AssignmentPathSegm
collectPersonaConstruction(segment, relativeMode, reallyValid, ctx);
}
if (assignmentType.getFocusMappings() != null) {
// Here we ignore "reallyValid". It is OK, because reallyValid can be false here only when
// evaluating direct assignments; and invalid ones are marked as such via EvaluatedAssignment.isValid.
// (This is currently ignored by downstream processing, but that's another story. Will be fixed soon.)
if (isNonNegative(relativeMode)) {
evaluateFocusMappings(segment, ctx, result);
if (reallyValid && relativeMode != null) { // null relative mode means both PLUS and MINUS
collectFocusMappings(segment, relativeMode, ctx);
}
}
}
if (assignmentType.getPolicyRule() != null && !loginMode) {
// We can ignore "reallyValid" for the same reason as for focus mappings.
// Here we ignore "reallyValid". It is OK, because reallyValid can be false here only when
// evaluating direct assignments; and invalid ones are marked as such via EvaluatedAssignment.isValid.
// TODO is it ok?
if (isNonNegative(relativeMode)) {
if (segment.isMatchingOrder()) {
collectPolicyRule(true, segment, ctx);
Expand Down Expand Up @@ -671,8 +670,8 @@ private void collectPersonaConstruction(AssignmentPathSegmentImpl segment, PlusM
ctx.evalAssignment.addPersonaConstruction(construction, mode);
}

private void evaluateFocusMappings(AssignmentPathSegmentImpl segment, EvaluationContext ctx, OperationResult result)
throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, SecurityViolationException, ConfigurationException, CommunicationException {
private void collectFocusMappings(AssignmentPathSegmentImpl segment, @NotNull PlusMinusZero relativeMode, EvaluationContext ctx)
throws SchemaException {
assertSourceNotNull(segment.source, ctx.evalAssignment);

AssignmentType assignmentBean = getAssignmentType(segment, ctx);
Expand All @@ -684,7 +683,7 @@ private void evaluateFocusMappings(AssignmentPathSegmentImpl segment, Evaluation

for (MappingType mappingBean: mappingsBean.getMapping()) {
AssignedFocusMappingEvaluationRequest request = new AssignedFocusMappingEvaluationRequest(mappingBean, segment.source,
assignmentPathVariables, segment.sourceDescription);
ctx.evalAssignment, relativeMode, assignmentPathVariables, segment.sourceDescription);
ctx.evalAssignment.addFocusMappingEvaluationRequest(request);
}
}
Expand Down
Expand Up @@ -16,8 +16,7 @@

import com.evolveum.midpoint.model.impl.lens.projector.ComplexConstructionConsumer;
import com.evolveum.midpoint.model.impl.lens.projector.ConstructionProcessor;
import com.evolveum.midpoint.model.impl.lens.projector.mappings.AssignedFocusMappingEvaluationRequest;
import com.evolveum.midpoint.model.impl.lens.projector.mappings.MappingEvaluator;
import com.evolveum.midpoint.model.impl.lens.projector.mappings.*;
import com.evolveum.midpoint.model.impl.lens.projector.policy.PolicyRuleProcessor;
import com.evolveum.midpoint.model.impl.util.ModelImplUtils;
import com.evolveum.midpoint.prism.*;
Expand Down Expand Up @@ -100,35 +99,17 @@ public class AssignmentProcessor {
@Qualifier("modelObjectResolver")
private ObjectResolver objectResolver;

@Autowired
private SystemObjectCache systemObjectCache;

@Autowired
private RelationRegistry relationRegistry;

@Autowired
private PrismContext prismContext;

@Autowired
private MappingFactory mappingFactory;

@Autowired
private MappingEvaluator mappingEvaluator;

@Autowired
private ActivationComputer activationComputer;

@Autowired
private ProvisioningService provisioningService;

@Autowired
private ConstructionProcessor constructionProcessor;

@Autowired
private ObjectTemplateProcessor objectTemplateProcessor;

@Autowired
private PolicyRuleProcessor policyRuleProcessor;
@Autowired private SystemObjectCache systemObjectCache;
@Autowired private RelationRegistry relationRegistry;
@Autowired private PrismContext prismContext;
@Autowired private MappingFactory mappingFactory;
@Autowired private MappingEvaluator mappingEvaluator;
@Autowired private MappingSetEvaluator mappingSetEvaluator;
@Autowired private ActivationComputer activationComputer;
@Autowired private ProvisioningService provisioningService;
@Autowired private ConstructionProcessor constructionProcessor;
@Autowired private ObjectTemplateProcessor objectTemplateProcessor;
@Autowired private PolicyRuleProcessor policyRuleProcessor;

private static final Trace LOGGER = TraceManager.getTrace(AssignmentProcessor.class);

Expand Down Expand Up @@ -310,32 +291,84 @@ private <AH extends AssignmentHolderType> void evaluateFocusMappings(LensContext
LOGGER.trace("Starting evaluation of assignment-held mappings");

ObjectDeltaObject<AH> focusOdo = focusContext.getObjectDeltaObject();
PrismObject<SystemConfigurationType> systemConfiguration = context.getSystemConfiguration();

List<AssignedFocusMappingEvaluationRequest> allRequests = new ArrayList<>();
for (EvaluatedAssignmentImpl<AH> evaluatedAssignment : evaluatedAssignmentTriple.getAllValues()) {
for (AssignedFocusMappingEvaluationRequest request : evaluatedAssignment.getFocusMappingEvaluationRequests()) {
MappingImpl<?,?> mapping = mappingEvaluator.createFocusMapping(mappingFactory, context, request.getMapping(),
request.getOriginObject(), focusOdo, request.getAssignmentPathVariables(), systemConfiguration, now,
request.getSourceDescription(), task, result);
if (mapping != null) {
// TODO: time constraints?
mappingEvaluator.evaluateMapping(mapping, context, task, result);
evaluatedAssignment.addFocusMapping(mapping);
allRequests.addAll(evaluatedAssignment.getFocusMappingEvaluationRequests());
}

MappingSetEvaluator.TripleCustomizer<PrismValue, ItemDefinition> customizer = (triple, abstractRequest) -> {
if (triple == null) {
return null;
}
DeltaSetTriple<ItemValueWithOrigin<PrismValue, ItemDefinition>> rv = prismContext.deltaFactory().createDeltaSetTriple();
AssignedFocusMappingEvaluationRequest request = (AssignedFocusMappingEvaluationRequest) abstractRequest;
//noinspection unchecked
EvaluatedAssignmentImpl<AH> evaluatedAssignment = (EvaluatedAssignmentImpl<AH>) request.getEvaluatedAssignment();
PlusMinusZero relativeMode = request.getRelativeMode();
Set<PlusMinusZero> presence = new HashSet<>();
PlusMinusZero resultingMode = null;
if (evaluatedAssignmentTriple.presentInPlusSet(evaluatedAssignment)) {
resultingMode = PlusMinusZero.compute(PlusMinusZero.PLUS, relativeMode);
presence.add(PlusMinusZero.PLUS);
}
if (evaluatedAssignmentTriple.presentInMinusSet(evaluatedAssignment)) {
resultingMode = PlusMinusZero.compute(PlusMinusZero.MINUS, relativeMode);
presence.add(PlusMinusZero.MINUS);
}
if (evaluatedAssignmentTriple.presentInZeroSet(evaluatedAssignment)) {
resultingMode = PlusMinusZero.compute(PlusMinusZero.ZERO, relativeMode);
presence.add(PlusMinusZero.ZERO);
}
LOGGER.trace("triple customizer: presence = {}, relativeMode = {}, resultingMode = {}", presence, relativeMode,
resultingMode);

if (presence.isEmpty()) {
throw new IllegalStateException("Evaluated assignment is not present in any of plus/minus/zero sets "
+ "of the triple. Assignment = " + evaluatedAssignment + ", triple = " + triple);
} else if (presence.size() > 1) {
// TODO think about this
throw new IllegalStateException("Evaluated assignment is present in more than one plus/minus/zero sets "
+ "of the triple: " + presence + ". Assignment = " + evaluatedAssignment + ", triple = " + triple);
}
if (resultingMode != null) {
switch (resultingMode) {
case PLUS:
rv.addAllToPlusSet(triple.getNonNegativeValues());
break;
case MINUS:
rv.addAllToMinusSet(triple.getNonPositiveValues());
break;
case ZERO:
rv = triple;
break;
}
}
}
return rv;
};

MappingSetEvaluator.EvaluatedMappingConsumer<PrismValue, ItemDefinition> mappingConsumer = (mapping, abstractRequest) -> {
AssignedFocusMappingEvaluationRequest request = (AssignedFocusMappingEvaluationRequest) abstractRequest;
request.getEvaluatedAssignment().addFocusMapping(mapping);
};

LOGGER.trace("Processing output triples from assignment-held mappings");
Map<UniformItemPath, DeltaSetTriple<? extends ItemValueWithOrigin<?, ?>>> focusOutputTripleMap = new HashMap<>();
collectFocusTripleFromMappings(evaluatedAssignmentTriple.getPlusSet(), focusOutputTripleMap, PlusMinusZero.PLUS);
collectFocusTripleFromMappings(evaluatedAssignmentTriple.getMinusSet(), focusOutputTripleMap, PlusMinusZero.MINUS);
collectFocusTripleFromMappings(evaluatedAssignmentTriple.getZeroSet(), focusOutputTripleMap, PlusMinusZero.ZERO);

// TODO choose between these two approaches
//TargetObjectSpecification<AH> targetSpecification = new SelfTargetSpecification<>();
TargetObjectSpecification<AH> targetSpecification = new FixedTargetSpecification<>(focusOdo.getNewObject());

mappingSetEvaluator.evaluateMappingsToTriples(context, allRequests, null, focusOdo, targetSpecification,
focusOutputTripleMap, customizer, mappingConsumer, focusContext.getIteration(),
focusContext.getIterationToken(), now, task, result);

if (LOGGER.isTraceEnabled()) {
for (Entry<UniformItemPath, DeltaSetTriple<? extends ItemValueWithOrigin<?, ?>>> entry : focusOutputTripleMap
.entrySet()) {
LOGGER.trace("Resulting output triple for {}:\n{}", entry.getKey(), entry.getValue().debugDump(1));
}
}

Collection<ItemDelta<?, ?>> focusDeltas = objectTemplateProcessor.computeItemDeltas(focusOutputTripleMap, null,
focusOdo.getObjectDelta(), focusOdo.getNewObject(), focusContext.getObjectDefinition(),
"focus mappings in assignments of " + focusContext.getHumanReadableName());
Expand Down
Expand Up @@ -563,6 +563,7 @@ private EvaluatedAssignmentImpl<AH> evaluateAssignment(ItemDeltaItem<PrismContai
OperationResult subResult = result.createMinorSubresult(OP_EVALUATE_ASSIGNMENT);
PrismContainerValue<AssignmentType> assignment = assignmentIdi.getSingleValue(evaluateOld);
subResult.addParam("assignment", assignment != null ? FocusTypeUtil.dumpAssignment(assignment.asContainerable()) : null);
subResult.addArbitraryObjectAsParam("mode", mode);
subResult.addParam("assignmentPlacementDescription", assignmentPlacementDesc);
try {
// Evaluate assignment. This follows to the assignment targets, follows to the inducements,
Expand Down
Expand Up @@ -86,6 +86,8 @@
import com.evolveum.midpoint.xml.ns._public.common.common_3.VariableBindingDefinitionType;
import com.evolveum.prism.xml.ns._public.types_3.ItemPathType;

import static com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectTemplateMappingEvaluationPhaseType.BEFORE_ASSIGNMENTS;

/**
* Processor to handle object template.
*
Expand Down Expand Up @@ -144,8 +146,13 @@ <AH extends AssignmentHolderType> void processTemplate(LensContext<AH> context,
collectAutoassignMappings(context, mappings, result);

Map<UniformItemPath,DeltaSetTriple<? extends ItemValueWithOrigin<?,?>>> outputTripleMap = new HashMap<>();
NextRecompute nextRecompute = mappingSetEvaluator.evaluateMappingsToTriples(context, mappings, phase, focusOdo, focusOdo.getNewObject(),
outputTripleMap, iteration, iterationToken, now, task, result);

// TODO choose between these two
//TargetObjectSpecification<AH> targetSpecification = new SelfTargetSpecification<>();
TargetObjectSpecification<AH> targetSpecification = new FixedTargetSpecification<>(focusOdo.getNewObject());

NextRecompute nextRecompute = mappingSetEvaluator.evaluateMappingsToTriples(context, mappings, phase, focusOdo,
targetSpecification, outputTripleMap, null, null, iteration, iterationToken, now, task, result);

if (LOGGER.isTraceEnabled()) {
LOGGER.trace("outputTripleMap before item delta computation:\n{}", DebugUtil.debugDumpMapMultiLine(outputTripleMap));
Expand Down Expand Up @@ -213,8 +220,9 @@ public <F extends FocusType, T extends FocusType> Collection<ItemDelta<?,?>> pro
collectAutoassignMappings(context, mappings, result);

Map<UniformItemPath,DeltaSetTriple<? extends ItemValueWithOrigin<?,?>>> outputTripleMap = new HashMap<>();
mappingSetEvaluator.evaluateMappingsToTriples(context, mappings, ObjectTemplateMappingEvaluationPhaseType.BEFORE_ASSIGNMENTS,
focusOdo, target, outputTripleMap, iteration, iterationToken, now, task, result);
mappingSetEvaluator.evaluateMappingsToTriples(context, mappings, BEFORE_ASSIGNMENTS,
focusOdo, new FixedTargetSpecification<>(target), outputTripleMap, null, null, iteration,
iterationToken, now, task, result);

if (LOGGER.isTraceEnabled()) {
LOGGER.trace("outputTripleMap before item delta computation:\n{}", DebugUtil.debugDumpMapMultiLine(outputTripleMap));
Expand Down
Expand Up @@ -8,6 +8,8 @@
package com.evolveum.midpoint.model.impl.lens.projector.mappings;

import com.evolveum.midpoint.model.impl.lens.AssignmentPathVariables;
import com.evolveum.midpoint.model.impl.lens.EvaluatedAssignmentImpl;
import com.evolveum.midpoint.prism.delta.PlusMinusZero;
import com.evolveum.midpoint.xml.ns._public.common.common_3.MappingType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectTemplateMappingEvaluationPhaseType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
Expand All @@ -21,20 +23,46 @@
*/
public class AssignedFocusMappingEvaluationRequest extends FocalMappingEvaluationRequest<MappingType, ObjectType> {

/**
* Evaluated assignment this request is part of. Beware: DO NOT CLONE. It is engaged in identity-based lookup.
*/
@NotNull private final EvaluatedAssignmentImpl<?> evaluatedAssignment;

/**
* Mode of the focus mapping (plus, minus, zero), relative to the assignment being evaluated.
*/
@NotNull private final PlusMinusZero relativeMode;

private final AssignmentPathVariables assignmentPathVariables;
private final String sourceDescription;

public AssignedFocusMappingEvaluationRequest(@NotNull MappingType mapping, @NotNull ObjectType originObject,
AssignmentPathVariables assignmentPathVariables, String sourceDescription) {
@NotNull EvaluatedAssignmentImpl<?> evaluatedAssignment,
@NotNull PlusMinusZero relativeMode, AssignmentPathVariables assignmentPathVariables,
String sourceDescription) {
super(mapping, originObject);
this.evaluatedAssignment = evaluatedAssignment;
this.relativeMode = relativeMode;
this.assignmentPathVariables = assignmentPathVariables;
this.sourceDescription = sourceDescription;
}

@NotNull
public EvaluatedAssignmentImpl<?> getEvaluatedAssignment() {
return evaluatedAssignment;
}

@NotNull
public PlusMinusZero getRelativeMode() {
return relativeMode;
}

@Override
public AssignmentPathVariables getAssignmentPathVariables() {
return assignmentPathVariables;
}

@SuppressWarnings("unused")
public String getSourceDescription() {
return sourceDescription;
}
Expand All @@ -48,6 +76,6 @@ public ObjectTemplateMappingEvaluationPhaseType getEvaluationPhase() {
@Override
public void shortDump(StringBuilder sb) {
sb.append("assigned mapping ");
sb.append("'").append(mapping.getName()).append("' in ").append(sourceDescription);
sb.append("'").append(getMappingInfo()).append("' in ").append(sourceDescription);
}
}
Expand Up @@ -27,6 +27,10 @@
*/
public class AutoassignRoleMappingEvaluationRequest extends FocalMappingEvaluationRequest<AutoassignMappingType, AbstractRoleType> {

// Internal state
private PrismContainerDefinition<AssignmentType> assignmentDef;
private AssignmentType assignmentType;

public AutoassignRoleMappingEvaluationRequest(@NotNull AutoassignMappingType mapping, @NotNull AbstractRoleType role) {
super(mapping, role);
}
Expand Down Expand Up @@ -78,6 +82,6 @@ public ObjectTemplateMappingEvaluationPhaseType getEvaluationPhase() {
@Override
public void shortDump(StringBuilder sb) {
sb.append("autoassign mapping ");
sb.append("'").append(mapping.getName()).append("' in ").append(originObject);
sb.append("'").append(getMappingInfo()).append("' in ").append(originObject);
}
}
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2019 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.model.impl.lens.projector.mappings;

import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.util.ObjectDeltaObject;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentHolderType;

/**
* Target object is a given (fixed) prism object: either the same as focus ODO (but with no updates!),
* or a different one.
*/
public class FixedTargetSpecification<T extends AssignmentHolderType> extends TargetObjectSpecification<T> {

private final PrismObject<T> targetObject;

public FixedTargetSpecification(PrismObject<T> targetObject) {
this.targetObject = targetObject;
}

@Override
public <AH extends AssignmentHolderType> PrismObject<T> getTargetObject(ObjectDeltaObject<AH> updatedFocusOdo) {
return targetObject;
}

@Override
public boolean isUpdatedWithMappingResults() {
return false;
}
}

0 comments on commit 5caec04

Please sign in to comment.