Search in sources :

Example 1 with ValueMatcher

use of com.evolveum.midpoint.model.impl.lens.projector.ValueMatcher in project midpoint by Evolveum.

the class LensUtil method consolidateTripleToDelta.

/**
	 * Consolidate the mappings of a single item to a delta. It takes the convenient structure of ItemValueWithOrigin triple.
	 * It produces the delta considering the mapping exclusion, authoritativeness and strength.
     *
     * filterExistingValues: if true, then values that already exist in the item are not added (and those that don't exist are not removed)
	 */
@NotNull
public static <V extends PrismValue, D extends ItemDefinition, I extends ItemValueWithOrigin<V, D>> ItemDelta<V, D> consolidateTripleToDelta(ItemPath itemPath, DeltaSetTriple<I> triple, D itemDefinition, ItemDelta<V, D> aprioriItemDelta, PrismContainer<?> itemContainer, ValueMatcher<?> valueMatcher, Comparator<V> comparator, boolean addUnchangedValues, boolean filterExistingValues, boolean isExclusiveStrong, String contextDescription, boolean applyWeak) throws ExpressionEvaluationException, PolicyViolationException, SchemaException {
    ItemDelta<V, D> itemDelta = itemDefinition.createEmptyDelta(itemPath);
    Item<V, D> itemExisting = null;
    if (itemContainer != null) {
        itemExisting = itemContainer.findItem(itemPath);
    }
    if (LOGGER.isTraceEnabled()) {
        LOGGER.trace("Consolidating {} triple:\n{}\nApriori Delta:\n{}\nExisting item:\n{}", itemPath, triple.debugDump(1), DebugUtil.debugDump(aprioriItemDelta, 1), DebugUtil.debugDump(itemExisting, 1));
    }
    Collection<V> allValues = collectAllValues(triple, valueMatcher);
    final MutableBoolean itemHasStrongMutable = new MutableBoolean(false);
    SimpleVisitor<I> visitor = pvwo -> {
        if (pvwo.getMapping().getStrength() == MappingStrengthType.STRONG) {
            itemHasStrongMutable.setValue(true);
        }
    };
    triple.accept(visitor);
    boolean ignoreNormalMappings = itemHasStrongMutable.booleanValue() && isExclusiveStrong;
    // a single item (e.g. attribute). But this loop iterates over every potential value of that item.
    for (V value : allValues) {
        LOGGER.trace("  consolidating value: {}", value);
        // Check what to do with the value using the usual "triple routine". It means that if a value is
        // in zero set than we need no delta, plus set means add delta and minus set means delete delta.
        // The first set that the value is present determines the result.
        Collection<ItemValueWithOrigin<V, D>> zeroPvwos = collectPvwosFromSet(value, triple.getZeroSet(), valueMatcher);
        Collection<ItemValueWithOrigin<V, D>> plusPvwos = collectPvwosFromSet(value, triple.getPlusSet(), valueMatcher);
        Collection<ItemValueWithOrigin<V, D>> minusPvwos = collectPvwosFromSet(value, triple.getMinusSet(), valueMatcher);
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("PVWOs for value {}:\nzero = {}\nplus = {}\nminus = {}", value, zeroPvwos, plusPvwos, minusPvwos);
        }
        boolean zeroHasStrong = false;
        if (!zeroPvwos.isEmpty()) {
            for (ItemValueWithOrigin<V, D> pvwo : zeroPvwos) {
                PrismValueDeltaSetTripleProducer<V, D> mapping = pvwo.getMapping();
                if (mapping.getStrength() == MappingStrengthType.STRONG) {
                    zeroHasStrong = true;
                }
            }
        }
        if (zeroHasStrong && aprioriItemDelta != null && aprioriItemDelta.isValueToDelete(value, true)) {
            throw new PolicyViolationException("Attempt to delete value " + value + " from item " + itemPath + " but that value is mandated by a strong mapping (in " + contextDescription + ")");
        }
        if (!zeroPvwos.isEmpty() && !addUnchangedValues) {
            // Value unchanged, nothing to do
            LOGGER.trace("Value {} unchanged, doing nothing", value);
            continue;
        }
        PrismValueDeltaSetTripleProducer<V, D> exclusiveMapping = null;
        Collection<ItemValueWithOrigin<V, D>> pvwosToAdd = null;
        if (addUnchangedValues) {
            pvwosToAdd = MiscUtil.union(zeroPvwos, plusPvwos);
        } else {
            pvwosToAdd = plusPvwos;
        }
        if (!pvwosToAdd.isEmpty()) {
            boolean weakOnly = true;
            boolean hasStrong = false;
            // exclusions and strength
            for (ItemValueWithOrigin<V, D> pvwoToAdd : pvwosToAdd) {
                PrismValueDeltaSetTripleProducer<V, D> mapping = pvwoToAdd.getMapping();
                if (mapping.getStrength() != MappingStrengthType.WEAK) {
                    weakOnly = false;
                }
                if (mapping.getStrength() == MappingStrengthType.STRONG) {
                    hasStrong = true;
                }
                if (mapping.isExclusive()) {
                    if (exclusiveMapping == null) {
                        exclusiveMapping = mapping;
                    } else {
                        String message = "Exclusion conflict in " + contextDescription + ", item " + itemPath + ", conflicting constructions: " + exclusiveMapping + " and " + mapping;
                        LOGGER.error(message);
                        throw new ExpressionEvaluationException(message);
                    }
                }
            }
            if (weakOnly) {
                // Postpone processing of weak values until we process all other values
                LOGGER.trace("Value {} mapping is weak in item {}, postponing processing in {}", value, itemPath, contextDescription);
                continue;
            }
            if (!hasStrong && ignoreNormalMappings) {
                LOGGER.trace("Value {} mapping is normal in item {} and we have exclusiveStrong, skipping processing in {}", value, itemPath, contextDescription);
                continue;
            }
            if (hasStrong && aprioriItemDelta != null && aprioriItemDelta.isValueToDelete(value, true)) {
                throw new PolicyViolationException("Attempt to delete value " + value + " from item " + itemPath + " but that value is mandated by a strong mapping (in " + contextDescription + ")");
            }
            if (!hasStrong && (aprioriItemDelta != null && !aprioriItemDelta.isEmpty())) {
                // There is already a delta, skip this
                LOGGER.trace("Value {} mapping is not strong and the item {} already has a delta that is more concrete, " + "skipping adding in {}", value, itemPath, contextDescription);
                continue;
            }
            if (filterExistingValues && hasValue(itemExisting, value, valueMatcher, comparator)) {
                LOGGER.trace("Value {} NOT added to delta for item {} because the item already has that value in {}", value, itemPath, contextDescription);
                continue;
            }
            LOGGER.trace("Value {} added to delta as ADD for item {} in {}", value, itemPath, contextDescription);
            itemDelta.addValueToAdd((V) value.clone());
            continue;
        }
        // So check for that special case here to avoid removing them.
        if (!minusPvwos.isEmpty() && plusPvwos.isEmpty()) {
            boolean weakOnly = true;
            boolean hasStrong = false;
            boolean hasAuthoritative = false;
            // exclusions and strength
            for (ItemValueWithOrigin<V, D> pvwo : minusPvwos) {
                PrismValueDeltaSetTripleProducer<V, D> mapping = pvwo.getMapping();
                if (mapping.getStrength() != MappingStrengthType.WEAK) {
                    weakOnly = false;
                }
                if (mapping.getStrength() == MappingStrengthType.STRONG) {
                    hasStrong = true;
                }
                if (mapping.isAuthoritative()) {
                    hasAuthoritative = true;
                }
            }
            if (!hasAuthoritative) {
                LOGGER.trace("Value {} has no authoritative mapping for item {}, skipping deletion in {}", value, itemPath, contextDescription);
                continue;
            }
            if (!hasStrong && (aprioriItemDelta != null && !aprioriItemDelta.isEmpty())) {
                // There is already a delta, skip this
                LOGGER.trace("Value {} mapping is not strong and the item {} already has a delta that is more concrete, skipping deletion in {}", value, itemPath, contextDescription);
                continue;
            }
            if (weakOnly && (itemExisting != null && !itemExisting.isEmpty())) {
                // There is already a value, skip this
                LOGGER.trace("Value {} mapping is weak and the item {} already has a value, skipping deletion in {}", value, itemPath, contextDescription);
                continue;
            }
            if (weakOnly && !applyWeak && (itemExisting == null || itemExisting.isEmpty())) {
                // There is a weak mapping on a property, but we do not have full account available, so skipping deletion of the value is better way
                LOGGER.trace("Value {} mapping is weak and the full account could not be fetched, skipping deletion in {}", value, itemPath, contextDescription);
                continue;
            }
            if (filterExistingValues && !hasValue(itemExisting, value, valueMatcher, comparator)) {
                LOGGER.trace("Value {} NOT add to delta as DELETE because item {} the item does not have that value in {} (matcher: {})", value, itemPath, contextDescription, valueMatcher);
                continue;
            }
            LOGGER.trace("Value {} added to delta as DELETE for item {} in {}", value, itemPath, contextDescription);
            itemDelta.addValueToDelete((V) value.clone());
        }
        if (!zeroPvwos.isEmpty()) {
            boolean weakOnly = true;
            boolean hasStrong = false;
            boolean hasAuthoritative = false;
            // exclusions and strength
            for (ItemValueWithOrigin<V, D> pvwo : zeroPvwos) {
                PrismValueDeltaSetTripleProducer<V, D> mapping = pvwo.getMapping();
                if (mapping.getStrength() != MappingStrengthType.WEAK) {
                    weakOnly = false;
                }
                if (mapping.getStrength() == MappingStrengthType.STRONG) {
                    hasStrong = true;
                }
                if (mapping.isAuthoritative()) {
                    hasAuthoritative = true;
                }
            }
            if (aprioriItemDelta != null && aprioriItemDelta.isReplace()) {
                // Any strong mappings in the zero set needs to be re-applied as otherwise the replace will destroy it
                if (hasStrong) {
                    LOGGER.trace("Value {} added to delta for item {} in {} because there is strong mapping in the zero set", value, itemPath, contextDescription);
                    itemDelta.addValueToAdd((V) value.clone());
                    continue;
                }
            }
        }
    }
    Item<V, D> itemNew = null;
    if (itemContainer != null) {
        itemNew = itemContainer.findItem(itemPath);
    }
    if (!hasValue(itemNew, itemDelta)) {
        // The application of computed delta results in no value, apply weak mappings
        Collection<? extends ItemValueWithOrigin<V, D>> nonNegativePvwos = triple.getNonNegativeValues();
        Collection<V> valuesToAdd = addWeakValues(nonNegativePvwos, OriginType.ASSIGNMENTS, applyWeak);
        if (valuesToAdd.isEmpty()) {
            valuesToAdd = addWeakValues(nonNegativePvwos, OriginType.OUTBOUND, applyWeak);
        }
        if (valuesToAdd.isEmpty()) {
            valuesToAdd = addWeakValues(nonNegativePvwos, null, applyWeak);
        }
        LOGGER.trace("No value for item {} in {}, weak mapping processing yielded values: {}", itemPath, contextDescription, valuesToAdd);
        itemDelta.addValuesToAdd(valuesToAdd);
    } else {
        LOGGER.trace("Existing values for item {} in {}, weak mapping processing skipped", new Object[] { itemPath, contextDescription });
    }
    if (itemExisting != null) {
        List<V> existingValues = itemExisting.getValues();
        if (existingValues != null) {
            itemDelta.setEstimatedOldValues(PrismValue.cloneCollection(existingValues));
        }
    }
    return itemDelta;
}
Also used : ObjectResolver(com.evolveum.midpoint.schema.util.ObjectResolver) com.evolveum.midpoint.util.exception(com.evolveum.midpoint.util.exception) ExpressionConstants(com.evolveum.midpoint.schema.constants.ExpressionConstants) BooleanUtils(org.apache.commons.lang.BooleanUtils) DOMUtil(com.evolveum.midpoint.util.DOMUtil) PrismValueDeltaSetTriple(com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple) EvaluatedPolicyRule(com.evolveum.midpoint.model.api.context.EvaluatedPolicyRule) PrismValueDeltaSetTripleProducer(com.evolveum.midpoint.model.common.mapping.PrismValueDeltaSetTripleProducer) com.evolveum.midpoint.prism(com.evolveum.midpoint.prism) PasswordCapabilityType(com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.PasswordCapabilityType) SelectorOptions(com.evolveum.midpoint.schema.SelectorOptions) Utils(com.evolveum.midpoint.model.impl.util.Utils) ObjectDelta(com.evolveum.midpoint.prism.delta.ObjectDelta) Mapping(com.evolveum.midpoint.model.common.mapping.Mapping) Collection(java.util.Collection) ActivationComputer(com.evolveum.midpoint.common.ActivationComputer) ResourceTypeUtil(com.evolveum.midpoint.schema.util.ResourceTypeUtil) ModelExpressionThreadLocalHolder(com.evolveum.midpoint.model.impl.expr.ModelExpressionThreadLocalHolder) MiscUtil(com.evolveum.midpoint.util.MiscUtil) Task(com.evolveum.midpoint.task.api.Task) EvaluatedPolicyRuleTrigger(com.evolveum.midpoint.model.api.context.EvaluatedPolicyRuleTrigger) ResourceShadowDiscriminator(com.evolveum.midpoint.schema.ResourceShadowDiscriminator) Nullable(org.jetbrains.annotations.Nullable) List(java.util.List) ExpressionVariables(com.evolveum.midpoint.repo.common.expression.ExpressionVariables) ExpressionFactory(com.evolveum.midpoint.repo.common.expression.ExpressionFactory) PolyStringType(com.evolveum.prism.xml.ns._public.types_3.PolyStringType) ProvisioningService(com.evolveum.midpoint.provisioning.api.ProvisioningService) PropertyDelta(com.evolveum.midpoint.prism.delta.PropertyDelta) QName(javax.xml.namespace.QName) NotNull(org.jetbrains.annotations.NotNull) com.evolveum.midpoint.xml.ns._public.common.common_3(com.evolveum.midpoint.xml.ns._public.common.common_3) SchemaConstants(com.evolveum.midpoint.schema.constants.SchemaConstants) OperationResult(com.evolveum.midpoint.schema.result.OperationResult) Trace(com.evolveum.midpoint.util.logging.Trace) DebugUtil(com.evolveum.midpoint.util.DebugUtil) PrismDefaultPolyStringNormalizer(com.evolveum.midpoint.prism.polystring.PrismDefaultPolyStringNormalizer) Supplier(java.util.function.Supplier) ArrayList(java.util.ArrayList) CredentialsCapabilityType(com.evolveum.midpoint.xml.ns._public.resource.capabilities_3.CredentialsCapabilityType) ItemDelta(com.evolveum.midpoint.prism.delta.ItemDelta) HashSet(java.util.HashSet) SchemaConstantsGenerated(com.evolveum.midpoint.schema.SchemaConstantsGenerated) RefinedResourceSchema(com.evolveum.midpoint.common.refinery.RefinedResourceSchema) RefinedResourceSchemaImpl(com.evolveum.midpoint.common.refinery.RefinedResourceSchemaImpl) ObjectTypeUtil(com.evolveum.midpoint.schema.util.ObjectTypeUtil) DeltaSetTriple(com.evolveum.midpoint.prism.delta.DeltaSetTriple) CapabilityUtil(com.evolveum.midpoint.schema.CapabilityUtil) PolyString(com.evolveum.midpoint.prism.polystring.PolyString) ItemDeltaItem(com.evolveum.midpoint.repo.common.expression.ItemDeltaItem) Iterator(java.util.Iterator) Expression(com.evolveum.midpoint.repo.common.expression.Expression) ExpressionEvaluationContext(com.evolveum.midpoint.repo.common.expression.ExpressionEvaluationContext) XMLGregorianCalendar(javax.xml.datatype.XMLGregorianCalendar) RefinedObjectClassDefinition(com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition) LoggingUtils(com.evolveum.midpoint.util.logging.LoggingUtils) ItemPath(com.evolveum.midpoint.prism.path.ItemPath) ShadowUtil(com.evolveum.midpoint.schema.util.ShadowUtil) MutableBoolean(org.apache.commons.lang.mutable.MutableBoolean) GetOperationOptions(com.evolveum.midpoint.schema.GetOperationOptions) Source(com.evolveum.midpoint.repo.common.expression.Source) Comparator(java.util.Comparator) Collections(java.util.Collections) TraceManager(com.evolveum.midpoint.util.logging.TraceManager) ValueMatcher(com.evolveum.midpoint.model.impl.lens.projector.ValueMatcher) MutableBoolean(org.apache.commons.lang.mutable.MutableBoolean) PolyString(com.evolveum.midpoint.prism.polystring.PolyString) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

ActivationComputer (com.evolveum.midpoint.common.ActivationComputer)1 RefinedObjectClassDefinition (com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition)1 RefinedResourceSchema (com.evolveum.midpoint.common.refinery.RefinedResourceSchema)1 RefinedResourceSchemaImpl (com.evolveum.midpoint.common.refinery.RefinedResourceSchemaImpl)1 EvaluatedPolicyRule (com.evolveum.midpoint.model.api.context.EvaluatedPolicyRule)1 EvaluatedPolicyRuleTrigger (com.evolveum.midpoint.model.api.context.EvaluatedPolicyRuleTrigger)1 Mapping (com.evolveum.midpoint.model.common.mapping.Mapping)1 PrismValueDeltaSetTripleProducer (com.evolveum.midpoint.model.common.mapping.PrismValueDeltaSetTripleProducer)1 ModelExpressionThreadLocalHolder (com.evolveum.midpoint.model.impl.expr.ModelExpressionThreadLocalHolder)1 ValueMatcher (com.evolveum.midpoint.model.impl.lens.projector.ValueMatcher)1 Utils (com.evolveum.midpoint.model.impl.util.Utils)1 com.evolveum.midpoint.prism (com.evolveum.midpoint.prism)1 DeltaSetTriple (com.evolveum.midpoint.prism.delta.DeltaSetTriple)1 ItemDelta (com.evolveum.midpoint.prism.delta.ItemDelta)1 ObjectDelta (com.evolveum.midpoint.prism.delta.ObjectDelta)1 PrismValueDeltaSetTriple (com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple)1 PropertyDelta (com.evolveum.midpoint.prism.delta.PropertyDelta)1 ItemPath (com.evolveum.midpoint.prism.path.ItemPath)1 PolyString (com.evolveum.midpoint.prism.polystring.PolyString)1 PrismDefaultPolyStringNormalizer (com.evolveum.midpoint.prism.polystring.PrismDefaultPolyStringNormalizer)1