Skip to content

Commit

Permalink
Implement association ranges
Browse files Browse the repository at this point in the history
(Consolidation of association values works, but not very convincingly.
The algorithm is not able to create equivalence classes correctly.)

Related to MID-6228.
  • Loading branch information
mederly committed Sep 24, 2020
1 parent 95fac4a commit 20331ef
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 78 deletions.
Expand Up @@ -9,13 +9,15 @@

import com.evolveum.midpoint.common.refinery.RefinedAssociationDefinition;
import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition;
import com.evolveum.midpoint.prism.OriginType;
import com.evolveum.midpoint.prism.PrismContainerDefinition;
import com.evolveum.midpoint.prism.PrismContainerValue;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentHolderType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.MappingKindType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.MappingType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowAssociationType;
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.util.QNameUtil;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;

import org.jetbrains.annotations.NotNull;

import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
* Evaluation of an association mapping in resource object construction (assigned/plain).
Expand All @@ -26,7 +28,9 @@ class AssociationEvaluation<AH extends AssignmentHolderType>
AssociationEvaluation(ConstructionEvaluation<AH, ?> constructionEvaluation,
RefinedAssociationDefinition associationDefinition, MappingType mappingBean,
OriginType originType, MappingKindType mappingKind) {
super(constructionEvaluation, associationDefinition.getName(), associationDefinition,
super(constructionEvaluation, associationDefinition.getName(),
ShadowType.F_ASSOCIATION.append(associationDefinition.getName()),
associationDefinition,
constructionEvaluation.construction.getAssociationContainerDefinition(),
mappingBean, originType, mappingKind);
}
Expand All @@ -40,4 +44,18 @@ protected String getItemType() {
RefinedObjectClassDefinition getAssociationTargetObjectClassDefinition() {
return itemRefinedDefinition.getAssociationTarget();
}

@Override
protected Collection<PrismContainerValue<ShadowAssociationType>> getOriginalTargetValuesFromShadow(
@NotNull PrismObject<ShadowType> shadow) {
// Note that it's possible that association values are simply not known. However, returning
// an empty list is the best we can do in such situations.
List<ShadowAssociationType> allValues = shadow.asObjectable().getAssociation();

//noinspection unchecked
return allValues.stream()
.filter(value -> QNameUtil.match(value.getName(), itemName))
.map(value -> (PrismContainerValue<ShadowAssociationType>) value.asPrismContainerValue())
.collect(Collectors.toList());
}
}
Expand Up @@ -9,12 +9,16 @@

import com.evolveum.midpoint.common.refinery.RefinedAttributeDefinition;
import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition;
import com.evolveum.midpoint.prism.OriginType;
import com.evolveum.midpoint.prism.PrismPropertyDefinition;
import com.evolveum.midpoint.prism.PrismPropertyValue;
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentHolderType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.MappingKindType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.MappingType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType;

import org.jetbrains.annotations.NotNull;

import java.util.Collection;
import java.util.Collections;

/**
* Evaluation of an attribute mapping in resource object construction (assigned/plain).
Expand All @@ -25,7 +29,9 @@ class AttributeEvaluation<AH extends AssignmentHolderType>
AttributeEvaluation(ConstructionEvaluation<AH, ?> constructionEvaluation,
RefinedAttributeDefinition<?> refinedAttributeDefinition, MappingType mappingBean,
OriginType origin, MappingKindType mappingKind) {
super(constructionEvaluation, refinedAttributeDefinition.getItemName(), refinedAttributeDefinition,
super(constructionEvaluation, refinedAttributeDefinition.getItemName(),
ShadowType.F_ATTRIBUTES.append(refinedAttributeDefinition.getItemName()),
refinedAttributeDefinition,
refinedAttributeDefinition, mappingBean, origin, mappingKind);
}

Expand All @@ -38,4 +44,20 @@ protected String getItemType() {
RefinedObjectClassDefinition getAssociationTargetObjectClassDefinition() {
return null;
}

@Override
protected Collection<PrismPropertyValue<?>> getOriginalTargetValuesFromShadow(@NotNull PrismObject<ShadowType> shadow) {
PrismProperty<?> attribute = shadow.findProperty(itemPath);
if (attribute != null) {
//noinspection unchecked
return (Collection) attribute.getValues();
} else {
// Either the projection is fully loaded and the attribute does not exist,
// or the projection is not loaded (contrary to the fact that loading was requested).
// In both cases the wisest approach is to return empty list, keeping mapping from failing,
// and not removing anything. In the future we may consider issuing a warning, if we don't have
// full shadow, and range specification is present.
return Collections.emptyList();
}
}
}
Expand Up @@ -56,7 +56,14 @@ abstract class ItemEvaluation<AH extends AssignmentHolderType, V extends PrismVa
/**
* Name of the attribute or association.
*/
@NotNull private final ItemName itemName;
@NotNull final ItemName itemName;

/**
* Path to the attribute or association.
* We know that for the association the path is imprecise: association/name.
* But the mapping will need to live with it.
*/
@NotNull final ItemPath itemPath;

/**
* Refined definition of attribute/association.
Expand Down Expand Up @@ -88,12 +95,15 @@ abstract class ItemEvaluation<AH extends AssignmentHolderType, V extends PrismVa
*/
private MappingImpl<V, D> evaluatedMapping;

ItemEvaluation(ConstructionEvaluation<AH, ?> constructionEvaluation, @NotNull ItemName itemName, @NotNull RD itemRefinedDefinition,
ItemEvaluation(ConstructionEvaluation<AH, ?> constructionEvaluation, @NotNull ItemName itemName,
@NotNull ItemPath itemPath,
@NotNull RD itemRefinedDefinition,
@NotNull D itemPrismDefinition, @NotNull MappingType mappingBean, @NotNull OriginType originType,
@NotNull MappingKindType mappingKind) {
this.constructionEvaluation = constructionEvaluation;
this.construction = constructionEvaluation.construction;
this.itemName = itemName;
this.itemPath = itemPath;
this.itemRefinedDefinition = itemRefinedDefinition;
this.itemPrismDefinition = itemPrismDefinition;
this.mappingBean = mappingBean;
Expand Down Expand Up @@ -153,9 +163,7 @@ private MappingImpl<V, D> evaluateMapping()

LensContext<AH> context = construction.lensContext;

ItemPath targetPath = ItemPath.create(ShadowType.F_ATTRIBUTES, itemName); // TODO associations!

if (construction.initializeMappingBuilder(mappingBuilder, targetPath, itemName, itemPrismDefinition,
if (construction.initializeMappingBuilder(mappingBuilder, itemPath, itemName, itemPrismDefinition,
getAssociationTargetObjectClassDefinition()) == null) {
return null;
}
Expand All @@ -177,7 +185,7 @@ private MappingImpl<V, D> evaluateMapping()
mappingBuilder.addVariableDefinition(ExpressionConstants.VAR_LEGAL, getLegal());
mappingBuilder.addVariableDefinition(ExpressionConstants.VAR_ASSIGNED, getAssigned());

mappingBuilder.originalTargetValues(getOriginalTargetValues(projCtx, projectionOdo, targetPath));
mappingBuilder.originalTargetValues(getOriginalTargetValues());
mappingBuilder.valuePolicySupplier(createValuePolicySupplier());

// TODO: other variables?
Expand Down Expand Up @@ -227,34 +235,24 @@ public ValuePolicyType get(OperationResult result) {
};
}

private Collection<V> getOriginalTargetValues(LensProjectionContext projCtx, ObjectDeltaObject<ShadowType> projectionOdo, ItemPath targetPath) {
// TODO what if target is required?
private Collection<V> getOriginalTargetValues() {
LensProjectionContext projCtx = constructionEvaluation.projectionContext;
ObjectDeltaObject<ShadowType> projectionOdo = constructionEvaluation.getProjectionOdo();

if (projCtx == null || projCtx.isDelete() || projCtx.isAdd() || projectionOdo == null) {
return Collections.emptyList();
} else {
PrismObject<ShadowType> oldObject = projectionOdo.getOldObject();
if (oldObject != null) {
PrismProperty<Object> attributeOld = oldObject.findProperty(targetPath);
if (attributeOld == null) {
if (projCtx.hasFullShadow()) {
// We know that the attribute has no values
return Collections.emptyList();
} else {
// We do not have full shadow. Therefore we know nothing about attribute values.
// We cannot set originalTargetValues here.
// TODO log a warning?
return Collections.emptyList(); // this is a hack
}
} else {
//noinspection unchecked
return (Collection<V>) attributeOld.getValues();
}
return getOriginalTargetValuesFromShadow(oldObject);
} else {
return Collections.emptyList();
}
}
}

protected abstract Collection<V> getOriginalTargetValuesFromShadow(@NotNull PrismObject<ShadowType> shadow);

private Object getIteration() {
return constructionEvaluation.projectionContext != null ?
LensUtil.getIterationVariableValue(constructionEvaluation.projectionContext) : null;
Expand Down

0 comments on commit 20331ef

Please sign in to comment.