use of com.evolveum.midpoint.prism.match.MatchingRule in project midpoint by Evolveum.
the class ShadowManager method fixShadow.
/**
* Re-reads the shadow, re-evaluates the identifiers and stored values, updates them if necessary. Returns
* fixed shadow.
*/
public PrismObject<ShadowType> fixShadow(ProvisioningContext ctx, PrismObject<ShadowType> origRepoShadow, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, ConfigurationException, CommunicationException, ExpressionEvaluationException {
PrismObject<ShadowType> currentRepoShadow = repositoryService.getObject(ShadowType.class, origRepoShadow.getOid(), null, parentResult);
ProvisioningContext shadowCtx = ctx.spawn(currentRepoShadow);
RefinedObjectClassDefinition ocDef = shadowCtx.getObjectClassDefinition();
PrismContainer<Containerable> attributesContainer = currentRepoShadow.findContainer(ShadowType.F_ATTRIBUTES);
if (attributesContainer != null && attributesContainer.getValue() != null) {
ObjectDelta<ShadowType> shadowDelta = currentRepoShadow.createModifyDelta();
for (Item<?, ?> item : attributesContainer.getValue().getItems()) {
if (item instanceof PrismProperty<?>) {
PrismProperty<?> attrProperty = (PrismProperty<?>) item;
RefinedAttributeDefinition<Object> attrDef = ocDef.findAttributeDefinition(attrProperty.getElementName());
if (attrDef == null) {
// No definition for this property, it should not be in the shadow
PropertyDelta<?> oldRepoAttrPropDelta = attrProperty.createDelta();
oldRepoAttrPropDelta.addValuesToDelete((Collection) PrismPropertyValue.cloneCollection(attrProperty.getValues()));
shadowDelta.addModification(oldRepoAttrPropDelta);
} else {
MatchingRule matchingRule = matchingRuleRegistry.getMatchingRule(attrDef.getMatchingRuleQName(), attrDef.getTypeName());
List<PrismPropertyValue> valuesToAdd = null;
List<PrismPropertyValue> valuesToDelete = null;
for (PrismPropertyValue attrVal : attrProperty.getValues()) {
Object currentRealValue = attrVal.getValue();
Object normalizedRealValue = matchingRule.normalize(currentRealValue);
if (!normalizedRealValue.equals(currentRealValue)) {
if (attrDef.isSingleValue()) {
shadowDelta.addModificationReplaceProperty(attrProperty.getPath(), normalizedRealValue);
break;
} else {
if (valuesToAdd == null) {
valuesToAdd = new ArrayList<>();
}
valuesToAdd.add(new PrismPropertyValue(normalizedRealValue));
if (valuesToDelete == null) {
valuesToDelete = new ArrayList<>();
}
valuesToDelete.add(new PrismPropertyValue(currentRealValue));
}
}
}
PropertyDelta attrDelta = attrProperty.createDelta(attrProperty.getPath());
if (valuesToAdd != null) {
attrDelta.addValuesToAdd(valuesToAdd);
}
if (valuesToDelete != null) {
attrDelta.addValuesToDelete(valuesToDelete);
}
shadowDelta.addModification(attrDelta);
}
}
}
if (!shadowDelta.isEmpty()) {
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Fixing shadow {} with delta:\n{}", origRepoShadow, shadowDelta.debugDump());
}
try {
repositoryService.modifyObject(ShadowType.class, origRepoShadow.getOid(), shadowDelta.getModifications(), parentResult);
} catch (ObjectAlreadyExistsException e) {
// This should not happen for shadows
throw new SystemException(e.getMessage(), e);
}
shadowDelta.applyTo(currentRepoShadow);
} else {
LOGGER.trace("No need to fixing shadow {} (empty delta)", origRepoShadow);
}
} else {
LOGGER.trace("No need to fixing shadow {} (no atttributes)", origRepoShadow);
}
return currentRepoShadow;
}
use of com.evolveum.midpoint.prism.match.MatchingRule in project midpoint by Evolveum.
the class ResourceObjectConverter method convertToReplace.
private PropertyModificationOperation convertToReplace(PropertyDelta<?> propertyDelta, PrismObject<ShadowType> currentShadow, QName matchingRuleQName) throws SchemaException {
if (propertyDelta.isReplace()) {
// this was probably checked before
throw new IllegalStateException("PropertyDelta is both ADD/DELETE and REPLACE");
}
// let's extract (parent-less) current values
PrismProperty<?> currentProperty = currentShadow.findProperty(propertyDelta.getPath());
Collection<PrismPropertyValue> currentValues = new ArrayList<>();
if (currentProperty != null) {
for (PrismPropertyValue currentValue : currentProperty.getValues()) {
currentValues.add(currentValue.clone());
}
}
final MatchingRule matchingRule;
if (matchingRuleQName != null) {
ItemDefinition def = propertyDelta.getDefinition();
QName typeName;
if (def != null) {
typeName = def.getTypeName();
} else {
// we'll skip testing rule fitness w.r.t type
typeName = null;
}
matchingRule = matchingRuleRegistry.getMatchingRule(matchingRuleQName, typeName);
} else {
matchingRule = null;
}
Comparator comparator = new Comparator<PrismPropertyValue<?>>() {
@Override
public int compare(PrismPropertyValue<?> o1, PrismPropertyValue<?> o2) {
if (o1.equalsComplex(o2, true, false, matchingRule)) {
return 0;
} else {
return 1;
}
}
};
// add values that have to be added
if (propertyDelta.isAdd()) {
for (PrismPropertyValue valueToAdd : propertyDelta.getValuesToAdd()) {
if (!PrismPropertyValue.containsValue(currentValues, valueToAdd, comparator)) {
currentValues.add(valueToAdd.clone());
} else {
LOGGER.warn("Attempting to add a value of {} that is already present in {}: {}", valueToAdd, propertyDelta.getElementName(), currentValues);
}
}
}
// remove values that should not be there
if (propertyDelta.isDelete()) {
for (PrismPropertyValue valueToDelete : propertyDelta.getValuesToDelete()) {
Iterator<PrismPropertyValue> iterator = currentValues.iterator();
boolean found = false;
while (iterator.hasNext()) {
PrismPropertyValue pValue = iterator.next();
LOGGER.trace("Comparing existing {} to about-to-be-deleted {}, matching rule: {}", pValue, valueToDelete, matchingRule);
if (comparator.compare(pValue, valueToDelete) == 0) {
LOGGER.trace("MATCH! compared existing {} to about-to-be-deleted {}", pValue, valueToDelete);
iterator.remove();
found = true;
}
}
if (!found) {
LOGGER.warn("Attempting to remove a value of {} that is not in {}: {}", valueToDelete, propertyDelta.getElementName(), currentValues);
}
}
}
PropertyDelta resultingDelta = new PropertyDelta(propertyDelta.getPath(), propertyDelta.getPropertyDefinition(), propertyDelta.getPrismContext());
resultingDelta.setValuesToReplace(currentValues);
return new PropertyModificationOperation(resultingDelta);
}
use of com.evolveum.midpoint.prism.match.MatchingRule in project midpoint by Evolveum.
the class ObjectTemplateProcessor method computeItemDeltas.
<F extends FocusType, T extends FocusType> Collection<ItemDelta<?, ?>> computeItemDeltas(Map<ItemPath, DeltaSetTriple<? extends ItemValueWithOrigin<?, ?>>> outputTripleMap, @Nullable Map<ItemPath, ObjectTemplateItemDefinitionType> itemDefinitionsMap, ObjectDelta<T> targetObjectAPrioriDelta, PrismObject<T> targetObject, PrismObjectDefinition<F> focusDefinition, String contextDesc) throws ExpressionEvaluationException, PolicyViolationException, SchemaException {
Collection<ItemDelta<?, ?>> itemDeltas = new ArrayList<>();
LOGGER.trace("Computing deltas in {}, focusDelta:\n{}", contextDesc, targetObjectAPrioriDelta);
boolean addUnchangedValues = false;
if (targetObjectAPrioriDelta != null && targetObjectAPrioriDelta.isAdd()) {
addUnchangedValues = true;
}
for (Entry<ItemPath, DeltaSetTriple<? extends ItemValueWithOrigin<?, ?>>> entry : outputTripleMap.entrySet()) {
ItemPath itemPath = entry.getKey();
DeltaSetTriple<? extends ItemValueWithOrigin<?, ?>> outputTriple = entry.getValue();
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Computed triple for {}:\n{}", itemPath, outputTriple.debugDump());
}
final ObjectTemplateItemDefinitionType templateItemDefinition;
if (itemDefinitionsMap != null) {
templateItemDefinition = ItemPathUtil.getFromMap(itemDefinitionsMap, itemPath);
} else {
templateItemDefinition = null;
}
boolean isNonTolerant = templateItemDefinition != null && Boolean.FALSE.equals(templateItemDefinition.isTolerant());
ItemDelta aprioriItemDelta = getAprioriItemDelta(targetObjectAPrioriDelta, itemPath);
// if non-tolerant, we want to gather ZERO & PLUS sets
boolean filterExistingValues = !isNonTolerant;
ItemDefinition itemDefinition = focusDefinition.findItemDefinition(itemPath);
ItemDelta itemDelta = LensUtil.consolidateTripleToDelta(itemPath, (DeltaSetTriple) outputTriple, itemDefinition, aprioriItemDelta, targetObject, null, null, addUnchangedValues, filterExistingValues, false, contextDesc, true);
// Do a quick version of reconciliation. There is not much to reconcile as both the source and the target
// is focus. But there are few cases to handle, such as strong mappings, and sourceless normal mappings.
Collection<? extends ItemValueWithOrigin<?, ?>> zeroSet = outputTriple.getZeroSet();
Item<PrismValue, ItemDefinition> itemNew = null;
if (targetObject != null) {
itemNew = targetObject.findItem(itemPath);
}
for (ItemValueWithOrigin<?, ?> zeroSetIvwo : zeroSet) {
PrismValueDeltaSetTripleProducer<?, ?> mapping = zeroSetIvwo.getMapping();
if ((mapping.getStrength() == null || mapping.getStrength() == MappingStrengthType.NORMAL)) {
if (aprioriItemDelta != null && !aprioriItemDelta.isEmpty()) {
continue;
}
if (!mapping.isSourceless()) {
continue;
}
LOGGER.trace("Adding zero values from normal mapping {}, a-priori delta: {}, isSourceless: {}", mapping, aprioriItemDelta, mapping.isSourceless());
} else if (mapping.getStrength() == MappingStrengthType.WEAK) {
if ((itemNew != null && !itemNew.isEmpty()) || (itemDelta != null && itemDelta.addsAnyValue())) {
continue;
}
LOGGER.trace("Adding zero values from weak mapping {}, itemNew: {}, itemDelta: {}", mapping, itemNew, itemDelta);
} else {
LOGGER.trace("Adding zero values from strong mapping {}", mapping);
}
PrismValue valueFromZeroSet = zeroSetIvwo.getItemValue();
if (itemNew == null || !itemNew.containsRealValue(valueFromZeroSet)) {
LOGGER.trace("Reconciliation will add value {} for item {}. Existing item: {}", valueFromZeroSet, itemPath, itemNew);
itemDelta.addValuesToAdd(valueFromZeroSet.clone());
}
}
if (isNonTolerant) {
if (itemDelta.isDelete()) {
LOGGER.trace("Non-tolerant item with values to DELETE => removing them");
// these are useless now - we move everything to REPLACE
itemDelta.resetValuesToDelete();
}
if (itemDelta.isReplace()) {
LOGGER.trace("Non-tolerant item with resulting REPLACE delta => doing nothing");
} else {
for (ItemValueWithOrigin<?, ?> zeroSetIvwo : zeroSet) {
itemDelta.addValuesToAdd(zeroSetIvwo.getItemValue().clone());
}
itemDelta.addToReplaceDelta();
LOGGER.trace("Non-tolerant item with resulting ADD delta => converted ADD to REPLACE values: {}", itemDelta.getValuesToReplace());
}
// under a special option "createReplaceDelta", but for the time being, let's keep it here
if (itemDelta instanceof PropertyDelta) {
PropertyDelta propertyDelta = ((PropertyDelta) itemDelta);
QName matchingRuleName = templateItemDefinition != null ? templateItemDefinition.getMatchingRule() : null;
MatchingRule matchingRule = matchingRuleRegistry.getMatchingRule(matchingRuleName, null);
if (propertyDelta.isRedundant(targetObject, matchingRule)) {
LOGGER.trace("Computed property delta is redundant => skipping it. Delta = \n{}", propertyDelta.debugDump());
continue;
}
} else {
if (itemDelta.isRedundant(targetObject)) {
LOGGER.trace("Computed item delta is redundant => skipping it. Delta = \n{}", itemDelta.debugDump());
continue;
}
}
PrismUtil.setDeltaOldValue(targetObject, itemDelta);
}
itemDelta.simplify();
itemDelta.validate(contextDesc);
itemDeltas.add(itemDelta);
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Computed delta:\n{}", itemDelta.debugDump());
}
}
return itemDeltas;
}
Aggregations