Skip to content

Commit

Permalink
Add "afterProjections" template evaluation phase
Browse files Browse the repository at this point in the history
Some mappings (e.g. those that need to catch hasLinkedAccount
transition) should be executed after projection activation is computed.
For such cases we have created experimental "afterProjections"
evaluation phase.

This resolves MID-6406.

Also, now muting "not found" fatal error when setting situation
on deleted shadow.
  • Loading branch information
mederly committed Sep 16, 2020
1 parent 52d764a commit a9b88d8
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 16 deletions.
Expand Up @@ -15071,18 +15071,41 @@
<xsd:restriction base="xsd:string">
<xsd:enumeration value="beforeAssignments">
<xsd:annotation>
<xsd:documentation>
Evaluation of template mappings before assignments are evaluated.
This is the most common phase for template mappings.
</xsd:documentation>
<xsd:appinfo>
<jaxb:typesafeEnumMember name="BEFORE_ASSIGNMENTS"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="afterAssignments">
<xsd:annotation>
<xsd:documentation>
Evaluation of template mappings after assignments are evaluated
but before uniqueness check is done and before projections are considered.
</xsd:documentation>
<xsd:appinfo>
<jaxb:typesafeEnumMember name="AFTER_ASSIGNMENTS"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="afterProjections">
<xsd:annotation>
<xsd:documentation>
Evaluation of template mappings after activation and values of projections
are processed. So, it is possible to use e.g. hasLinkedAccount function call
here to determine the new state of a projection. On the other hand, results of
these mappings are not reflected in projection outbound mappings.
</xsd:documentation>
<xsd:appinfo>
<a:experimental>true</a:experimental>
<a:since>4.2</a:since>
<jaxb:typesafeEnumMember name="AFTER_PROJECTIONS"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>

Expand Down Expand Up @@ -23102,6 +23125,7 @@
<xsd:element name="projectionCredentials" type="tns:PartialProcessingTypeType" minOccurs="0" default="automatic"/>
<xsd:element name="projectionReconciliation" type="tns:PartialProcessingTypeType" minOccurs="0" default="automatic"/>
<xsd:element name="projectionLifecycle" type="tns:PartialProcessingTypeType" minOccurs="0" default="automatic"/>
<xsd:element name="objectTemplateAfterProjections" type="tns:PartialProcessingTypeType" minOccurs="0" default="automatic"/>
<xsd:element name="approvals" type="tns:PartialProcessingTypeType" minOccurs="0" default="automatic"/>
<xsd:element name="execution" type="tns:PartialProcessingTypeType" minOccurs="0" default="automatic"/>
<xsd:element name="notification" type="tns:PartialProcessingTypeType" minOccurs="0" default="automatic"/>
Expand Down
Expand Up @@ -57,7 +57,7 @@ PrismValueDeltaSetTriple<V> evaluate() throws ExpressionEvaluationException, Obj
recordEvaluationStart(ValueTransformationEvaluationModeType.SINGLE_SHOT);

PrismValueDeltaSetTriple<V> outputTriple;
if (context.hasDeltas() || expressionDependsOnSystemState()) {
if (context.hasDeltas()) {
outputTriple = evaluateAbsoluteExpressionWithDeltas();
} else {
outputTriple = evaluateAbsoluteExpressionWithoutDeltas();
Expand All @@ -67,14 +67,6 @@ PrismValueDeltaSetTriple<V> evaluate() throws ExpressionEvaluationException, Obj
return outputTriple;
}

// FIXME remove this temporary hack - MID-6406
private boolean expressionDependsOnSystemState() {
E evaluatorBean = evaluator.getExpressionEvaluatorBean();
return evaluatorBean instanceof ScriptExpressionEvaluatorType &&
((ScriptExpressionEvaluatorType) evaluatorBean).getCode() != null &&
((ScriptExpressionEvaluatorType) evaluatorBean).getCode().contains("hasLinkedAccount");
}

private PrismValueDeltaSetTriple<V> evaluateAbsoluteExpressionWithDeltas() throws ExpressionEvaluationException,
ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException {

Expand Down
Expand Up @@ -853,6 +853,7 @@ private <F extends ObjectType> void updateSituationInShadow(Task task, Synchroni
SelectorOptions.createCollection(getOptions), task, result);
} catch (ObjectNotFoundException ex) {
LOGGER.trace("Shadow is gone, skipping modifying situation in shadow.");
result.muteLastSubresultError();
result.recordSuccess();
return;
} catch (Exception ex) {
Expand Down
Expand Up @@ -33,4 +33,5 @@ public class Components {
public static final String PROJECTION_RECONCILIATION = "projectionReconciliation";
public static final String PROJECTION_VALUES_POST_RECON = "projectionValuesPostRecon";
public static final String PROJECTION_LIFECYCLE = "projectionLifecycle";
public static final String OBJECT_TEMPLATE_AFTER_PROJECTIONS = "objectTemplateAfterProjections";
}
Expand Up @@ -12,6 +12,7 @@

import javax.xml.datatype.XMLGregorianCalendar;

import com.evolveum.midpoint.model.impl.lens.projector.focus.ObjectTemplateProcessor;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;

import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -71,7 +72,7 @@ public class Projector {
@Autowired private ProjectionCredentialsProcessor projectionCredentialsProcessor;
@Autowired private ActivationProcessor activationProcessor;
@Autowired private DependencyProcessor dependencyProcessor;
@Autowired private ConsolidationProcessor consolidationProcessor;
@Autowired private ObjectTemplateProcessor objectTemplateProcessor;
@Autowired private Clock clock;
@Autowired private ClockworkMedic medic;

Expand Down Expand Up @@ -211,6 +212,12 @@ private <F extends ObjectType> void projectInternal(LensContext<F> context, Stri
}

context.checkConsistenceIfNeeded();

medic.partialExecute(Components.OBJECT_TEMPLATE_AFTER_PROJECTIONS, objectTemplateProcessor,
objectTemplateProcessor::processTemplateAfterProjections,
partialProcessingOptions::getObjectTemplateAfterAssignments,
Projector.class, context, now, task, result);

context.incrementProjectionWave();

dependencyProcessor.checkDependenciesFinal(context, result);
Expand Down
Expand Up @@ -6,9 +6,6 @@
*/
package com.evolveum.midpoint.model.impl.lens.projector.focus;

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

import javax.xml.datatype.XMLGregorianCalendar;

import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -27,6 +24,8 @@
import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentHolderType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType;

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

/**
* Processor to handle object template.
*
Expand Down Expand Up @@ -60,6 +59,17 @@ <AH extends AssignmentHolderType> void processTemplateAfterAssignments(LensConte
applyEvaluationResultsToFocus(evaluation);
}

@ProcessorMethod
public <AH extends AssignmentHolderType> void processTemplateAfterProjections(LensContext<AH> context,
XMLGregorianCalendar now, Task task, OperationResult result)
throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, PolicyViolationException,
SecurityViolationException, ConfigurationException, CommunicationException {
TemplateMappingsEvaluation<AH, AH> evaluation = TemplateMappingsEvaluation.createForStandardTemplate(
beans, context, AFTER_PROJECTIONS, now, task, result);
evaluation.computeItemDeltas();
applyEvaluationResultsToFocus(evaluation);
}

private <AH extends AssignmentHolderType> void applyEvaluationResultsToFocus(TemplateMappingsEvaluation<AH, AH> evaluation)
throws SchemaException {
LensFocusContext<AH> focusContext = evaluation.getFocusContext();
Expand Down
Expand Up @@ -438,7 +438,7 @@
<code>midpoint.hasLinkedAccount('10000000-0000-0000-0000-000000000004')</code>
</script>
</condition>
<evaluationPhase>afterAssignments</evaluationPhase>
<evaluationPhase>afterProjections</evaluationPhase>
</mapping>

<mapping>
Expand Down
Expand Up @@ -18,6 +18,7 @@
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.prism.util.CloneUtil;
import com.evolveum.midpoint.repo.common.expression.ExpressionEvaluationContext;
import com.evolveum.midpoint.repo.common.expression.ExpressionUtil;
import com.evolveum.midpoint.schema.result.OperationResult;
Expand All @@ -33,6 +34,9 @@
public class LiteralExpressionEvaluator<V extends PrismValue,D extends ItemDefinition>
extends AbstractExpressionEvaluator<V, D, Collection<JAXBElement<?>>> {

private Item<V, D> literalItem;
private boolean literalItemParsed;

LiteralExpressionEvaluator(QName elementName, Collection<JAXBElement<?>> evaluatorElements,
D outputDefinition, Protector protector, PrismContext prismContext) {
super(elementName, evaluatorElements, outputDefinition, protector, prismContext);
Expand All @@ -45,7 +49,7 @@ public PrismValueDeltaSetTriple<V> evaluate(ExpressionEvaluationContext context,

ExpressionUtil.checkEvaluatorProfileSimple(this, context);

Item<V,D> output = StaticExpressionUtil.parseValueElements(expressionEvaluatorBean, outputDefinition, context.getContextDescription());
Item<V,D> output = CloneUtil.clone(parseLiteralItem(context.getContextDescription()));

for (V value : output.getValues()) {
addInternalOrigin(value, context);
Expand All @@ -56,8 +60,30 @@ public PrismValueDeltaSetTriple<V> evaluate(ExpressionEvaluationContext context,
return outputTriple;
}

private Item<V, D> parseLiteralItem(String contextDescription) throws SchemaException {
if (!literalItemParsed) {
literalItem = StaticExpressionUtil.parseValueElements(expressionEvaluatorBean, outputDefinition, contextDescription);
literalItemParsed = true;
}
return literalItem;
}

@Override
public String shortDebugDump() {
return "literal: "+expressionEvaluatorBean; // TODO
try {
return "literal: " + shortDebugDump(parseLiteralItem("shortDebugDump"));
} catch (SchemaException e) {
return "literal: couldn't parse: " + expressionEvaluatorBean;
}
}

private String shortDebugDump(Item<V, D> item) {
if (item == null || item.hasNoValues()) {
return "no values";
} else if (item.size() == 1) {
return String.valueOf(item.getAnyValue());
} else {
return String.valueOf(item.getValues());
}
}
}

0 comments on commit a9b88d8

Please sign in to comment.