use of com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple in project midpoint by Evolveum.
the class AssignmentProcessor method processAssignmentsProjectionsWithFocus.
/**
* Processing focus-projection assignments (including roles).
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private <F extends FocusType> void processAssignmentsProjectionsWithFocus(LensContext<F> context, XMLGregorianCalendar now, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException, PolicyViolationException, CommunicationException, ConfigurationException, SecurityViolationException {
// PREPARE ASSIGNMENT DELTA
LensFocusContext<F> focusContext = context.getFocusContext();
ObjectDelta<F> focusDelta = focusContext.getDelta();
if (focusDelta != null && focusDelta.isDelete()) {
processFocusDelete(context, result);
return;
}
checkAssignmentDeltaSanity(context);
// ASSIGNMENT EVALUATION
// Initializing assignment evaluator. This will be used later to process all the assignments including the nested
// assignments (roles).
AssignmentEvaluator<F> assignmentEvaluator = createAssignmentEvaluator(context, now);
ObjectType source = determineSource(focusContext);
AssignmentTripleEvaluator<F> assignmentTripleEvaluator = new AssignmentTripleEvaluator<>();
assignmentTripleEvaluator.setActivationComputer(activationComputer);
assignmentTripleEvaluator.setAssignmentEvaluator(assignmentEvaluator);
assignmentTripleEvaluator.setContext(context);
assignmentTripleEvaluator.setNow(now);
assignmentTripleEvaluator.setPrismContext(prismContext);
assignmentTripleEvaluator.setResult(result);
assignmentTripleEvaluator.setSource(source);
assignmentTripleEvaluator.setTask(task);
// Normal processing. The enforcement policy requires that assigned accounts should be added, so we need to figure out
// which assignments were added. Do a complete recompute for all the enforcement modes. We can do that because this does
// not create deltas, it just creates the triples. So we can decide what to do later when we convert triples to deltas.
// Evaluates all assignments and sorts them to triple: added, removed and untouched assignments.
// This is where most of the assignment-level action happens.
DeltaSetTriple<EvaluatedAssignmentImpl<F>> evaluatedAssignmentTriple = assignmentTripleEvaluator.processAllAssignments();
policyRuleProcessor.addGlobalPoliciesToAssignments(context, evaluatedAssignmentTriple, task, result);
context.setEvaluatedAssignmentTriple((DeltaSetTriple) evaluatedAssignmentTriple);
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("evaluatedAssignmentTriple:\n{}", evaluatedAssignmentTriple.debugDump());
}
// PROCESSING POLICIES
policyRuleProcessor.processPolicies(context, evaluatedAssignmentTriple, result);
boolean needToReevaluateAssignments = policyRuleProcessor.processPruning(context, evaluatedAssignmentTriple, result);
if (needToReevaluateAssignments) {
LOGGER.debug("Re-evaluating assignments because exclusion pruning rule was triggered");
evaluatedAssignmentTriple = assignmentTripleEvaluator.processAllAssignments();
context.setEvaluatedAssignmentTriple((DeltaSetTriple) evaluatedAssignmentTriple);
policyRuleProcessor.addGlobalPoliciesToAssignments(context, evaluatedAssignmentTriple, task, result);
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("re-evaluatedAssignmentTriple:\n{}", evaluatedAssignmentTriple.debugDump());
}
policyRuleProcessor.processPolicies(context, evaluatedAssignmentTriple, result);
}
//policyRuleProcessor.storeAssignmentPolicySituation(context, evaluatedAssignmentTriple, result);
// PROCESSING FOCUS
Map<ItemPath, DeltaSetTriple<? extends ItemValueWithOrigin<?, ?>>> focusOutputTripleMap = new HashMap<>();
collectFocusTripleFromMappings(evaluatedAssignmentTriple.getPlusSet(), focusOutputTripleMap, PlusMinusZero.PLUS);
collectFocusTripleFromMappings(evaluatedAssignmentTriple.getMinusSet(), focusOutputTripleMap, PlusMinusZero.MINUS);
collectFocusTripleFromMappings(evaluatedAssignmentTriple.getZeroSet(), focusOutputTripleMap, PlusMinusZero.ZERO);
ObjectDeltaObject<F> focusOdo = focusContext.getObjectDeltaObject();
Collection<ItemDelta<?, ?>> focusDeltas = objectTemplateProcessor.computeItemDeltas(focusOutputTripleMap, null, focusOdo.getObjectDelta(), focusOdo.getNewObject(), focusContext.getObjectDefinition(), "focus mappings in assignments of " + focusContext.getHumanReadableName());
LOGGER.trace("Computed focus deltas: {}", focusDeltas);
focusContext.applyProjectionWaveSecondaryDeltas(focusDeltas);
focusContext.recompute();
// PROCESSING PROJECTIONS
// Evaluate the constructions in assignements now. These were not evaluated in the first pass of AssignmentEvaluator
// because there may be interaction from focusMappings of some roles to outbound mappings of other roles.
// Now we have complete focus with all the focusMappings so we can evaluate the constructions
evaluateConstructions(context, evaluatedAssignmentTriple, task, result);
ComplexConstructionConsumer<ResourceShadowDiscriminator, Construction<F>> consumer = new ComplexConstructionConsumer<ResourceShadowDiscriminator, Construction<F>>() {
private boolean processOnlyExistingProjCxts;
@Override
public boolean before(ResourceShadowDiscriminator rat) {
if (rat.getResourceOid() == null) {
throw new IllegalStateException("Resource OID null in ResourceAccountType during assignment processing");
}
if (rat.getIntent() == null) {
throw new IllegalStateException("Account type is null in ResourceAccountType during assignment processing");
}
processOnlyExistingProjCxts = false;
if (ModelExecuteOptions.isLimitPropagation(context.getOptions())) {
if (context.getTriggeredResourceOid() != null && !rat.getResourceOid().equals(context.getTriggeredResourceOid())) {
LOGGER.trace("Skipping processing construction for shadow identified by {} because of limitation to propagate changes only for resource {}", rat, context.getTriggeredResourceOid());
return false;
}
if (SchemaConstants.CHANGE_CHANNEL_DISCOVERY.equals(QNameUtil.uriToQName(context.getChannel()))) {
// TODO is this message OK? [med]
LOGGER.trace("Processing of shadow identified by {} will be skipped because of limitation for discovery channel.");
processOnlyExistingProjCxts = true;
}
}
return true;
}
@Override
public void onAssigned(ResourceShadowDiscriminator rat, String desc) {
LensProjectionContext projectionContext = LensUtil.getOrCreateProjectionContext(context, rat);
projectionContext.setAssigned(true);
projectionContext.setAssignedOld(false);
projectionContext.setLegalOld(false);
AssignmentPolicyEnforcementType assignmentPolicyEnforcement = projectionContext.getAssignmentPolicyEnforcementType();
if (assignmentPolicyEnforcement != AssignmentPolicyEnforcementType.NONE) {
LOGGER.trace("Projection {} legal: assigned (valid)", desc);
projectionContext.setLegal(true);
}
}
@Override
public void onUnchangedValid(ResourceShadowDiscriminator key, String desc) {
LensProjectionContext projectionContext = context.findProjectionContext(key);
if (projectionContext == null) {
if (processOnlyExistingProjCxts) {
return;
}
// The projection should exist before the change but it does not
// This happens during reconciliation if there is an inconsistency.
// Pretend that the assignment was just added. That should do.
projectionContext = LensUtil.getOrCreateProjectionContext(context, key);
}
LOGGER.trace("Projection {} legal: unchanged (valid)", desc);
projectionContext.setLegal(true);
projectionContext.setLegalOld(true);
projectionContext.setAssigned(true);
projectionContext.setAssignedOld(true);
}
@Override
public void onUnchangedInvalid(ResourceShadowDiscriminator rat, String desc) {
LensProjectionContext projectionContext = context.findProjectionContext(rat);
if (projectionContext == null) {
if (processOnlyExistingProjCxts) {
return;
}
// The projection should exist before the change but it does not
// This happens during reconciliation if there is an inconsistency.
// Pretend that the assignment was just added. That should do.
projectionContext = LensUtil.getOrCreateProjectionContext(context, rat);
}
LOGGER.trace("Projection {} illegal: unchanged (invalid)", desc);
projectionContext.setLegal(false);
projectionContext.setLegalOld(false);
projectionContext.setAssigned(false);
projectionContext.setAssignedOld(false);
}
@Override
public void onUnassigned(ResourceShadowDiscriminator rat, String desc) {
if (accountExists(context, rat)) {
LensProjectionContext projectionContext = context.findProjectionContext(rat);
if (projectionContext == null) {
if (processOnlyExistingProjCxts) {
return;
}
projectionContext = LensUtil.getOrCreateProjectionContext(context, rat);
}
projectionContext.setAssigned(false);
projectionContext.setAssignedOld(true);
projectionContext.setLegalOld(true);
AssignmentPolicyEnforcementType assignmentPolicyEnforcement = projectionContext.getAssignmentPolicyEnforcementType();
// TODO: check for MARK and LEGALIZE enforcement policies ....add delete laso for relative enforcemenet
if (assignmentPolicyEnforcement == AssignmentPolicyEnforcementType.FULL || assignmentPolicyEnforcement == AssignmentPolicyEnforcementType.RELATIVE) {
LOGGER.trace("Projection {} illegal: unassigned", desc);
projectionContext.setLegal(false);
} else {
LOGGER.trace("Projection {} legal: unassigned, but allowed by policy ({})", desc, assignmentPolicyEnforcement);
projectionContext.setLegal(true);
}
} else {
LOGGER.trace("Projection {} nothing: unassigned (valid->invalid) but not there", desc);
// We have to delete something that is not there. Nothing to do.
}
}
@Override
public void after(ResourceShadowDiscriminator rat, String desc, DeltaMapTriple<ResourceShadowDiscriminator, ConstructionPack<Construction<F>>> constructionMapTriple) {
PrismValueDeltaSetTriple<PrismPropertyValue<Construction>> projectionConstructionDeltaSetTriple = new PrismValueDeltaSetTriple<>(getConstructions(constructionMapTriple.getZeroMap().get(rat), true), getConstructions(constructionMapTriple.getPlusMap().get(rat), true), getConstructions(constructionMapTriple.getMinusMap().get(rat), false));
LensProjectionContext projectionContext = context.findProjectionContext(rat);
if (projectionContext != null) {
// This can be null in a exotic case if we delete already deleted account
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Construction delta set triple for {}:\n{}", rat, projectionConstructionDeltaSetTriple.debugDump(1));
}
projectionContext.setConstructionDeltaSetTriple(projectionConstructionDeltaSetTriple);
if (isForceRecon(constructionMapTriple.getZeroMap().get(rat)) || isForceRecon(constructionMapTriple.getPlusMap().get(rat)) || isForceRecon(constructionMapTriple.getMinusMap().get(rat))) {
projectionContext.setDoReconciliation(true);
}
}
}
};
constructionProcessor.processConstructions(context, evaluatedAssignmentTriple, evaluatedAssignment -> evaluatedAssignment.getConstructionTriple(), construction -> getConstructionMapKey(context, construction, task, result), consumer, task, result);
removeIgnoredContexts(context);
finishLegalDecisions(context);
}
use of com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple in project midpoint by Evolveum.
the class MappingEvaluator method computeTargetValues.
private <V extends PrismValue, F extends FocusType> Collection<V> computeTargetValues(VariableBindingDefinitionType target, Object defaultTargetContext, ExpressionVariables variables, ObjectResolver objectResolver, String contextDesc, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException {
if (target == null) {
// Is this correct? What about default targets?
return null;
}
ItemPathType itemPathType = target.getPath();
if (itemPathType == null) {
// Is this correct? What about default targets?
return null;
}
ItemPath path = itemPathType.getItemPath();
Object object = ExpressionUtil.resolvePath(path, variables, defaultTargetContext, objectResolver, contextDesc, task, result);
if (object == null) {
return new ArrayList<>();
} else if (object instanceof Item) {
return ((Item) object).getValues();
} else if (object instanceof PrismValue) {
return (List<V>) Collections.singletonList((PrismValue) object);
} else if (object instanceof ItemDeltaItem) {
ItemDeltaItem<V, ?> idi = (ItemDeltaItem<V, ?>) object;
PrismValueDeltaSetTriple<V> triple = idi.toDeltaSetTriple();
return triple != null ? triple.getNonNegativeValues() : new ArrayList<V>();
} else {
throw new IllegalStateException("Unsupported target value(s): " + object.getClass() + " (" + object + ")");
}
}
use of com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple in project midpoint by Evolveum.
the class ConsolidationProcessor method hasActiveWeakMapping.
private <V extends PrismValue, D extends ItemDefinition> boolean hasActiveWeakMapping(Map<QName, DeltaSetTriple<ItemValueWithOrigin<V, D>>> squeezedAttributes, LensProjectionContext accCtx) throws SchemaException {
for (Map.Entry<QName, DeltaSetTriple<ItemValueWithOrigin<V, D>>> entry : squeezedAttributes.entrySet()) {
DeltaSetTriple<ItemValueWithOrigin<V, D>> ivwoTriple = entry.getValue();
boolean hasWeak = false;
for (ItemValueWithOrigin<V, D> ivwo : ivwoTriple.getAllValues()) {
PrismValueDeltaSetTripleProducer<V, D> mapping = ivwo.getMapping();
if (mapping.getStrength() == MappingStrengthType.WEAK) {
// We only care about mappings that change something. If the weak mapping is not
// changing anything then it will not be applied in this step anyway. Therefore
// there is no point in loading the real values just because there is such mapping.
// Note: we can be sure that we are NOT doing reconciliation. If we do reconciliation
// then we cannot get here in the first place (the projection is already loaded).
PrismValueDeltaSetTriple<?> outputTriple = mapping.getOutputTriple();
if (outputTriple != null && !outputTriple.isEmpty() && !outputTriple.isZeroOnly()) {
return true;
}
hasWeak = true;
}
}
if (hasWeak) {
// unless we fetch the real values.
if (ivwoTriple.hasMinusSet()) {
for (ItemValueWithOrigin<V, D> ivwo : ivwoTriple.getMinusSet()) {
PrismValueDeltaSetTripleProducer<V, D> mapping = ivwo.getMapping();
PrismValueDeltaSetTriple<?> outputTriple = mapping.getOutputTriple();
if (outputTriple != null && !outputTriple.isEmpty()) {
return true;
}
}
}
for (ItemValueWithOrigin<V, D> ivwo : ivwoTriple.getNonNegativeValues()) {
PrismValueDeltaSetTripleProducer<V, D> mapping = ivwo.getMapping();
PrismValueDeltaSetTriple<?> outputTriple = mapping.getOutputTriple();
if (outputTriple != null && outputTriple.hasMinusSet()) {
return true;
}
}
ObjectDelta<ShadowType> projectionDelta = accCtx.getDelta();
if (projectionDelta != null) {
PropertyDelta<?> aPrioriAttributeDelta = projectionDelta.findPropertyDelta(new ItemPath(ShadowType.F_ATTRIBUTES, entry.getKey()));
if (aPrioriAttributeDelta != null && aPrioriAttributeDelta.isDelete()) {
return true;
}
if (aPrioriAttributeDelta != null && aPrioriAttributeDelta.isReplace() && aPrioriAttributeDelta.getValuesToReplace().isEmpty()) {
return true;
}
}
}
}
return false;
}
use of com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple in project midpoint by Evolveum.
the class ProjectionCredentialsProcessor method processProjectionPasswordMapping.
private <F extends FocusType> void processProjectionPasswordMapping(LensContext<F> context, final LensProjectionContext projCtx, final ValuePolicyType passwordPolicy, XMLGregorianCalendar now, Task task, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException, CommunicationException, ConfigurationException, SecurityViolationException {
LensFocusContext<F> focusContext = context.getFocusContext();
PrismObject<F> userNew = focusContext.getObjectNew();
if (userNew == null) {
// This must be a user delete or something similar. No point in proceeding
LOGGER.trace("userNew is null, skipping credentials processing");
return;
}
PrismObjectDefinition<ShadowType> accountDefinition = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(ShadowType.class);
PrismPropertyDefinition<ProtectedStringType> projPasswordPropertyDefinition = accountDefinition.findPropertyDefinition(SchemaConstants.PATH_PASSWORD_VALUE);
ResourceShadowDiscriminator rsd = projCtx.getResourceShadowDiscriminator();
RefinedObjectClassDefinition refinedProjDef = projCtx.getStructuralObjectClassDefinition();
if (refinedProjDef == null) {
LOGGER.trace("No RefinedObjectClassDefinition, therefore also no password outbound definition, skipping credentials processing for projection {}", rsd);
return;
}
List<MappingType> outboundMappingTypes = refinedProjDef.getPasswordOutbound();
if (outboundMappingTypes == null || outboundMappingTypes.isEmpty()) {
LOGGER.trace("No outbound password mapping for {}, skipping credentials processing", rsd);
return;
}
// HACK
if (!projCtx.isDoReconciliation() && !projCtx.isAdd() && !isActivated(outboundMappingTypes, focusContext.getDelta())) {
LOGGER.trace("Outbound password mappings not activated for type {}, skipping credentials processing", rsd);
return;
}
final ObjectDelta<ShadowType> projDelta = projCtx.getDelta();
final PropertyDelta<ProtectedStringType> projPasswordDelta;
if (projDelta != null && projDelta.getChangeType() == MODIFY) {
projPasswordDelta = projDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE);
} else {
projPasswordDelta = null;
}
checkExistingDeltaSanity(projCtx, projPasswordDelta);
boolean evaluateWeak = getEvaluateWeak(projCtx);
final ItemDeltaItem<PrismPropertyValue<PasswordType>, PrismPropertyDefinition<ProtectedStringType>> userPasswordIdi = focusContext.getObjectDeltaObject().findIdi(SchemaConstants.PATH_PASSWORD_VALUE);
StringPolicyResolver stringPolicyResolver = new StringPolicyResolver() {
@Override
public void setOutputPath(ItemPath outputPath) {
}
@Override
public void setOutputDefinition(ItemDefinition outputDefinition) {
}
@Override
public StringPolicyType resolve() {
if (passwordPolicy == null) {
return null;
}
return passwordPolicy.getStringPolicy();
}
};
MappingInitializer<PrismPropertyValue<ProtectedStringType>, PrismPropertyDefinition<ProtectedStringType>> initializer = (builder) -> {
builder.defaultTargetDefinition(projPasswordPropertyDefinition);
builder.defaultSource(new Source<>(userPasswordIdi, ExpressionConstants.VAR_INPUT));
builder.stringPolicyResolver(stringPolicyResolver);
return builder;
};
MappingOutputProcessor<PrismPropertyValue<ProtectedStringType>> processor = (mappingOutputPath, outputStruct) -> {
PrismValueDeltaSetTriple<PrismPropertyValue<ProtectedStringType>> outputTriple = outputStruct.getOutputTriple();
if (outputTriple == null) {
LOGGER.trace("Credentials 'password' expression resulted in null output triple, skipping credentials processing for {}", rsd);
return false;
}
boolean projectionIsNew = projDelta != null && (projDelta.getChangeType() == ChangeType.ADD || projCtx.getSynchronizationPolicyDecision() == SynchronizationPolicyDecision.ADD);
Collection<PrismPropertyValue<ProtectedStringType>> newValues = outputTriple.getPlusSet();
if (projectionIsNew) {
newValues = outputTriple.getNonNegativeValues();
} else {
newValues = outputTriple.getPlusSet();
}
if (!canGetCleartext(newValues)) {
ObjectDelta<ShadowType> projectionPrimaryDelta = projCtx.getPrimaryDelta();
if (projectionPrimaryDelta != null) {
PropertyDelta<ProtectedStringType> passwordPrimaryDelta = projectionPrimaryDelta.findPropertyDelta(SchemaConstants.PATH_PASSWORD_VALUE);
if (passwordPrimaryDelta != null) {
// We have only hashed value coming from the mapping. There are not very useful
// for provisioning. But we have primary projection delta - and that is very likely
// to be better.
// Skip all password mappings in this case. Primary delta trumps everything.
// No weak, normal or even strong mapping can change that.
// We need to disregard even strong mapping in this case. If we would heed the strong
// mapping then account initialization won't be possible.
LOGGER.trace("We have primary password delta in projection, skipping credentials processing");
return false;
}
}
}
return true;
};
mappingEvaluator.evaluateOutboundMapping(context, projCtx, outboundMappingTypes, SchemaConstants.PATH_PASSWORD_VALUE, SchemaConstants.PATH_PASSWORD_VALUE, initializer, processor, now, true, evaluateWeak, "password mapping", task, result);
}
use of com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple in project midpoint by Evolveum.
the class PathExpressionEvaluator method evaluate.
/* (non-Javadoc)
* @see com.evolveum.midpoint.common.expression.ExpressionEvaluator#evaluate(java.util.Collection, java.util.Map, boolean, java.lang.String, com.evolveum.midpoint.schema.result.OperationResult)
*/
@Override
public PrismValueDeltaSetTriple<V> evaluate(ExpressionEvaluationContext context) throws SchemaException, ExpressionEvaluationException, ObjectNotFoundException {
ItemDeltaItem<?, ?> resolveContext = null;
if (context.getSources() != null && context.getSources().size() == 1) {
Source<?, ?> source = context.getSources().iterator().next();
if (path.isEmpty()) {
PrismValueDeltaSetTriple<V> outputTriple = (PrismValueDeltaSetTriple<V>) source.toDeltaSetTriple();
return outputTriple.clone();
}
resolveContext = source;
}
Map<QName, Object> variablesAndSources = ExpressionUtil.compileVariablesAndSources(context);
ItemPath resolvePath = path;
ItemPathSegment first = path.first();
if (first instanceof NameItemPathSegment && first.isVariable()) {
QName variableName = ((NameItemPathSegment) first).getName();
Object variableValue;
if (variablesAndSources.containsKey(variableName)) {
variableValue = variablesAndSources.get(variableName);
} else if (QNameUtil.matchAny(variableName, variablesAndSources.keySet())) {
QName fullVariableName = QNameUtil.resolveNs(variableName, variablesAndSources.keySet());
variableValue = variablesAndSources.get(fullVariableName);
} else {
throw new ExpressionEvaluationException("No variable with name " + variableName + " in " + context.getContextDescription());
}
if (variableValue == null) {
return null;
}
if (variableValue instanceof Item || variableValue instanceof ItemDeltaItem<?, ?>) {
resolveContext = ExpressionUtil.toItemDeltaItem(variableValue, objectResolver, "path expression in " + context.getContextDescription(), context.getResult());
} else if (variableValue instanceof PrismPropertyValue<?>) {
PrismValueDeltaSetTriple<V> outputTriple = new PrismValueDeltaSetTriple<>();
outputTriple.addToZeroSet((V) variableValue);
return ExpressionUtil.toOutputTriple(outputTriple, outputDefinition, context.getAdditionalConvertor(), null, protector, prismContext);
} else {
throw new ExpressionEvaluationException("Unexpected variable value " + variableValue + " (" + variableValue.getClass() + ")");
}
resolvePath = path.rest();
}
if (resolveContext == null) {
return null;
}
while (!resolvePath.isEmpty()) {
if (resolveContext.isContainer()) {
resolveContext = resolveContext.findIdi(resolvePath.head());
resolvePath = resolvePath.tail();
if (resolveContext == null) {
throw new ExpressionEvaluationException("Cannot find item using path " + path + " in " + context.getContextDescription());
}
} else if (resolveContext.isStructuredProperty()) {
// The output path does not really matter. The delta will be converted to triple anyway
// But the path cannot be null, oherwise the code will die
resolveContext = resolveContext.resolveStructuredProperty(resolvePath, (PrismPropertyDefinition) outputDefinition, new ItemPath());
break;
} else if (resolveContext.isNull()) {
break;
} else {
throw new ExpressionEvaluationException("Cannot resolve path " + resolvePath + " on " + resolveContext + " in " + context.getContextDescription());
}
}
PrismValueDeltaSetTriple<V> outputTriple = ItemDelta.toDeltaSetTriple((Item<V, D>) resolveContext.getItemOld(), (ItemDelta<V, D>) resolveContext.getDelta());
if (outputTriple == null) {
return null;
}
return ExpressionUtil.toOutputTriple(outputTriple, outputDefinition, context.getAdditionalConvertor(), null, protector, prismContext);
}
Aggregations