Skip to content

Commit

Permalink
Fixing and improving mappings and mapping ranges (MID-5559,MID-5560)
Browse files Browse the repository at this point in the history
  • Loading branch information
semancik committed Jul 16, 2019
1 parent 63b54e8 commit e63a79c
Show file tree
Hide file tree
Showing 20 changed files with 1,491 additions and 55 deletions.
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018 Evolveum
* Copyright (c) 2018-2019 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -29,4 +29,7 @@ public interface Mapping<V extends PrismValue,D extends ItemDefinition> {
*/
Long getEtime();

<T> T getStateProperty(String propertyName);

<T> T setStateProperty(String propertyName, T value);
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2017 Evolveum
* Copyright (c) 2010-2019 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -33,6 +33,7 @@

import com.evolveum.midpoint.model.api.ModelExecuteOptions;
import com.evolveum.midpoint.model.api.WorkflowService;
import com.evolveum.midpoint.model.api.context.Mapping;
import com.evolveum.midpoint.model.api.context.ModelContext;
import com.evolveum.midpoint.model.api.context.ModelElementContext;
import com.evolveum.midpoint.model.api.context.ModelProjectionContext;
Expand Down Expand Up @@ -1131,6 +1132,8 @@ TaskType executeChangesAsynchronously(Collection<ObjectDelta<?>> deltas, ModelEx

ModelProjectionContext getProjectionContext();

<V extends PrismValue, D extends ItemDefinition> Mapping<V,D> getMapping();

Object executeAdHocProvisioningScript(ResourceType resource, String language, String code)
throws SchemaException, ObjectNotFoundException,
ExpressionEvaluationException, CommunicationException, ConfigurationException,
Expand Down
Expand Up @@ -17,6 +17,7 @@

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -152,6 +153,10 @@ public class MappingImpl<V extends PrismValue,D extends ItemDefinition> implemen
// This is single-use only. Once evaluated it is not used any more
// it is remembered only for tracing purposes.
private Expression<V,D> expression;

// Mapping state properties that are exposed to the expressions. They can be used by the expressions to "communicate".
// E.g. one expression seting the property and other expression checking the property.
private Map<String,Object> stateProperties;

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

Expand Down Expand Up @@ -272,6 +277,7 @@ public boolean isSourceless() {
return sources.isEmpty();
}

@Override
public MappingStrengthType getStrength() {
return getStrength(mappingType);
}
Expand All @@ -287,6 +293,7 @@ public static MappingStrengthType getStrength(MappingType mappingType) {
return value;
}

@Override
public boolean isAuthoritative() {
if (mappingType == null) {
return true;
Expand All @@ -298,6 +305,7 @@ public boolean isAuthoritative() {
return value;
}

@Override
public boolean isExclusive() {
if (mappingType == null) {
return false;
Expand Down Expand Up @@ -406,6 +414,22 @@ public QName getMappingQName() {
public RefinedObjectClassDefinition getRefinedObjectClassDefinition() {
return refinedObjectClassDefinition;
}

@Override
public <T> T getStateProperty(String propertyName) {
if (stateProperties == null) {
return null;
}
return (T) stateProperties.get(propertyName);
}

@Override
public <T> T setStateProperty(String propertyName, T value) {
if (stateProperties == null) {
stateProperties = new HashMap<>();
}
return (T)stateProperties.put(propertyName, value);
}

// TODO: rename to evaluateAll
public void evaluate(Task task, OperationResult parentResult) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, SecurityViolationException, ConfigurationException, CommunicationException {
Expand Down Expand Up @@ -534,13 +558,11 @@ public void evaluateBody(Task task, OperationResult parentResult) throws Express

// TODO trace source and target values ... and range processing

// TODO: input filter
evaluateExpression(task, result, conditionResultOld, conditionResultNew);
fixDefinition();
recomputeValues();
setOrigin();
// TODO: output filter

adjustForAuthoritative();
checkRange(task, result);

transitionState(MappingEvaluationState.EVALUATED);
Expand All @@ -554,6 +576,21 @@ public void evaluateBody(Task task, OperationResult parentResult) throws Express
}
}

private void adjustForAuthoritative() {
if (isAuthoritative()) {
return;
}
if (outputTriple == null) {
return;
}
// Non-authoritative mappings do not remove values. Simply eliminate any values from the
// minus set to do that.
// However, we need to do this before we process range. Non-authoritative mappings may
// still remove values if range is set. We do not want to ignore minus values from
// range processing.
outputTriple.clearMinusSet();
}

private void checkRange(Task task, OperationResult result)
throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException {
VariableBindingDefinitionType target = mappingType.getTarget();
Expand All @@ -567,7 +604,12 @@ private void checkRange(Task task, OperationResult result)

private void checkRangeTarget(Task task, OperationResult result)
throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException {
String name = outputPath.lastName().getLocalPart();
String name = null;
if (outputPath != null) {
name = outputPath.lastName().getLocalPart();
} else {
name = outputDefinition.getName().getLocalPart();
}
if (originalTargetValues == null) {
throw new IllegalStateException("Couldn't check range for mapping in " + contextDescription + ", as original target values are not known.");
}
Expand Down Expand Up @@ -788,6 +830,10 @@ private void appendTraceHeader(StringBuilder sb) {
} else {
sb.append(expression.shortDebugDump());
}
if (stateProperties != null) {
sb.append("\nState:\n");
DebugUtil.debugDumpMapMultiLine(sb, stateProperties, 1);
}
}

private void appendTraceFooter(StringBuilder sb) {
Expand Down
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2017 Evolveum
* Copyright (c) 2017-2019 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -15,8 +15,11 @@
*/
package com.evolveum.midpoint.model.impl.expr;

import com.evolveum.midpoint.model.api.context.Mapping;
import com.evolveum.midpoint.model.impl.lens.LensContext;
import com.evolveum.midpoint.model.impl.lens.LensProjectionContext;
import com.evolveum.midpoint.prism.ItemDefinition;
import com.evolveum.midpoint.prism.PrismValue;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
Expand All @@ -25,10 +28,11 @@
* @author semancik
*
*/
public class ExpressionEnvironment<F extends ObjectType> {
public class ExpressionEnvironment<F extends ObjectType,V extends PrismValue, D extends ItemDefinition> {

private LensContext<F> lensContext;
private LensProjectionContext projectionContext;
private Mapping<V, D> mapping;
private OperationResult currentResult;
private Task currentTask;

Expand All @@ -39,14 +43,23 @@ public ExpressionEnvironment(Task currentTask, OperationResult currentResult) {
this.currentResult = currentResult;
this.currentTask = currentTask;
}

public ExpressionEnvironment(LensContext<F> lensContext, LensProjectionContext projectionContext,
Task currentTask, OperationResult currentResult) {
this.lensContext = lensContext;
this.projectionContext = projectionContext;
this.currentResult = currentResult;
this.currentTask = currentTask;
}

public ExpressionEnvironment(LensContext<F> lensContext, LensProjectionContext projectionContext, Mapping<V, D> mapping,
Task currentTask, OperationResult currentResult) {
this.lensContext = lensContext;
this.projectionContext = projectionContext;
this.mapping = mapping;
this.currentResult = currentResult;
this.currentTask = currentTask;
}

public LensContext<F> getLensContext() {
return lensContext;
Expand All @@ -64,6 +77,14 @@ public void setProjectionContext(LensProjectionContext projectionContext) {
this.projectionContext = projectionContext;
}

public Mapping<V, D> getMapping() {
return mapping;
}

public void setMapping(Mapping<V, D> mapping) {
this.mapping = mapping;
}

public OperationResult getCurrentResult() {
return currentResult;
}
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2017 Evolveum
* Copyright (c) 2010-2019 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -22,6 +22,7 @@
import com.evolveum.midpoint.common.refinery.RefinedResourceSchemaImpl;
import com.evolveum.midpoint.model.api.*;
import com.evolveum.midpoint.model.api.context.AssignmentPath;
import com.evolveum.midpoint.model.api.context.Mapping;
import com.evolveum.midpoint.model.api.context.ModelContext;
import com.evolveum.midpoint.model.api.context.ModelElementContext;
import com.evolveum.midpoint.model.api.context.ModelProjectionContext;
Expand Down Expand Up @@ -785,6 +786,11 @@ public <F extends ObjectType> ModelElementContext<F> getFocusContext() {
public ModelProjectionContext getProjectionContext() {
return ModelExpressionThreadLocalHolder.getProjectionContext();
}

@Override
public <V extends PrismValue, D extends ItemDefinition> Mapping<V,D> getMapping() {
return ModelExpressionThreadLocalHolder.getMapping();
}

@Override
public Task getCurrentTask() {
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2018 Evolveum
* Copyright (c) 2013-2019 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -20,12 +20,15 @@

import com.evolveum.midpoint.repo.common.expression.Expression;
import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluationContext;
import com.evolveum.midpoint.model.api.context.Mapping;
import com.evolveum.midpoint.model.impl.lens.LensContext;
import com.evolveum.midpoint.model.impl.lens.LensProjectionContext;
import com.evolveum.midpoint.prism.ItemDefinition;
import com.evolveum.midpoint.prism.PrismPropertyDefinition;
import com.evolveum.midpoint.prism.PrismPropertyValue;
import com.evolveum.midpoint.prism.PrismReferenceDefinition;
import com.evolveum.midpoint.prism.PrismReferenceValue;
import com.evolveum.midpoint.prism.PrismValue;
import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.task.api.Task;
Expand All @@ -43,57 +46,65 @@
*/
public class ModelExpressionThreadLocalHolder {

private static ThreadLocal<Deque<ExpressionEnvironment<ObjectType>>> expressionEnvironmentStackTl =
private static ThreadLocal<Deque<ExpressionEnvironment<ObjectType,PrismValue,ItemDefinition>>> expressionEnvironmentStackTl =
new ThreadLocal<>();

public static <F extends ObjectType> void pushExpressionEnvironment(ExpressionEnvironment<F> env) {
Deque<ExpressionEnvironment<ObjectType>> stack = expressionEnvironmentStackTl.get();
public static <F extends ObjectType,V extends PrismValue, D extends ItemDefinition> void pushExpressionEnvironment(ExpressionEnvironment<F,V,D> env) {
Deque<ExpressionEnvironment<ObjectType,PrismValue,ItemDefinition>> stack = expressionEnvironmentStackTl.get();
if (stack == null) {
stack = new ArrayDeque<>();
expressionEnvironmentStackTl.set(stack);
}
stack.push((ExpressionEnvironment<ObjectType>)env);
stack.push((ExpressionEnvironment<ObjectType,PrismValue,ItemDefinition>)env);
}

public static <F extends ObjectType> void popExpressionEnvironment() {
Deque<ExpressionEnvironment<ObjectType>> stack = expressionEnvironmentStackTl.get();
public static <F extends ObjectType,V extends PrismValue, D extends ItemDefinition> void popExpressionEnvironment() {
Deque<ExpressionEnvironment<ObjectType,PrismValue,ItemDefinition>> stack = expressionEnvironmentStackTl.get();
stack.pop();
}

public static <F extends ObjectType> ExpressionEnvironment<F> getExpressionEnvironment() {
Deque<ExpressionEnvironment<ObjectType>> stack = expressionEnvironmentStackTl.get();
public static <F extends ObjectType,V extends PrismValue, D extends ItemDefinition> ExpressionEnvironment<F,V,D> getExpressionEnvironment() {
Deque<ExpressionEnvironment<ObjectType,PrismValue,ItemDefinition>> stack = expressionEnvironmentStackTl.get();
if (stack == null) {
return null;
}
return (ExpressionEnvironment<F>) stack.peek();
return (ExpressionEnvironment<F,V,D>) stack.peek();
}

public static <F extends ObjectType> LensContext<F> getLensContext() {
ExpressionEnvironment<ObjectType> env = getExpressionEnvironment();
public static <F extends ObjectType,V extends PrismValue, D extends ItemDefinition> LensContext<F> getLensContext() {
ExpressionEnvironment<ObjectType,PrismValue,ItemDefinition> env = getExpressionEnvironment();
if (env == null) {
return null;
}
return (LensContext<F>) env.getLensContext();
}

public static <F extends ObjectType,V extends PrismValue, D extends ItemDefinition> Mapping<V,D> getMapping() {
ExpressionEnvironment<ObjectType,PrismValue,ItemDefinition> env = getExpressionEnvironment();
if (env == null) {
return null;
}
return (Mapping<V,D>) env.getMapping();
}

public static <F extends ObjectType> LensProjectionContext getProjectionContext() {
ExpressionEnvironment<ObjectType> env = getExpressionEnvironment();
public static <F extends ObjectType,V extends PrismValue, D extends ItemDefinition> LensProjectionContext getProjectionContext() {
ExpressionEnvironment<ObjectType,PrismValue,ItemDefinition> env = getExpressionEnvironment();
if (env == null) {
return null;
}
return env.getProjectionContext();
}

public static Task getCurrentTask() {
ExpressionEnvironment<ObjectType> env = getExpressionEnvironment();
ExpressionEnvironment<ObjectType,PrismValue,ItemDefinition> env = getExpressionEnvironment();
if (env == null) {
return null;
}
return env.getCurrentTask();
}

public static OperationResult getCurrentResult() {
ExpressionEnvironment<ObjectType> env = getExpressionEnvironment();
ExpressionEnvironment<ObjectType,PrismValue,ItemDefinition> env = getExpressionEnvironment();
if (env == null) {
return null;
}
Expand Down Expand Up @@ -137,7 +148,7 @@ public static PrismValueDeltaSetTriple<PrismReferenceValue> evaluateRefExpressio
public static <T> PrismValueDeltaSetTriple<PrismPropertyValue<T>> evaluateExpressionInContext(
Expression<PrismPropertyValue<T>,PrismPropertyDefinition<T>> expression,
ExpressionEvaluationContext eeContext,
ExpressionEnvironment<?> env)
ExpressionEnvironment<?,?,?> env)
throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException, CommunicationException, ConfigurationException, SecurityViolationException {
ModelExpressionThreadLocalHolder.pushExpressionEnvironment(env);
PrismValueDeltaSetTriple<PrismPropertyValue<T>> exprResultTriple;
Expand Down
Expand Up @@ -1757,7 +1757,7 @@ private void evaluateScriptArgument(ProvisioningScriptArgumentType argument,

ExpressionEvaluationContext params = new ExpressionEvaluationContext(null, variables, shortDesc, task,
result);
ExpressionEnvironment<?> env = new ExpressionEnvironment<>(context,
ExpressionEnvironment<?,?,?> env = new ExpressionEnvironment<>(context,
objectContext instanceof LensProjectionContext ? (LensProjectionContext) objectContext : null, task, result);
PrismValueDeltaSetTriple<PrismPropertyValue<String>> outputTriple = ModelExpressionThreadLocalHolder
.evaluateExpressionInContext(expression, params, env);
Expand Down

0 comments on commit e63a79c

Please sign in to comment.