Skip to content

Commit

Permalink
MID-4061: added metadata.autoCreateIdentifier (for mapping name)
Browse files Browse the repository at this point in the history
  • Loading branch information
mederly committed Nov 7, 2017
1 parent 5d8d106 commit 7805f45
Show file tree
Hide file tree
Showing 16 changed files with 164 additions and 86 deletions.
Expand Up @@ -134,6 +134,14 @@ public C getRealValue() {
return getValue().asContainerable();
}

public PrismContainerValue<C> getOrCreateValue() {
if (getValues().size() == 0) {
return createNewValue();
} else {
return getValue();
}
}

public PrismContainerValue<C> getValue() {
if (getValues().size() == 1) {
return getValues().get(0);
Expand Down
Expand Up @@ -17,25 +17,22 @@

import com.evolveum.midpoint.prism.delta.ItemDelta;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.util.DebugDumpable;
import com.evolveum.midpoint.util.DebugUtil;
import com.evolveum.midpoint.util.MiscUtil;
import com.evolveum.midpoint.util.exception.SchemaException;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.w3c.dom.Element;

import javax.xml.namespace.QName;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

/**
* @author semancik
Expand Down Expand Up @@ -237,11 +234,15 @@ public boolean representsSameValue(PrismValue other, boolean lax) {
}

public static <V extends PrismValue> boolean containsRealValue(Collection<V> collection, V value) {
return containsRealValue(collection, value, Function.identity());
}

public static <X, V extends PrismValue> boolean containsRealValue(Collection<X> collection, V value, Function<X, V> valueExtractor) {
if (collection == null) {
return false;
}
for (V colVal: collection) {
if (colVal.equalsRealValue(value)) {
for (X colVal: collection) {
if (valueExtractor.apply(colVal).equalsRealValue(value)) {
return true;
}
}
Expand Down
Expand Up @@ -1035,7 +1035,6 @@
</xsd:documentation>
<xsd:appinfo>
<a:operational>true</a:operational>
<a:indexed>true</a:indexed>
<a:since>3.7</a:since>
</xsd:appinfo>
</xsd:annotation>
Expand All @@ -1048,7 +1047,6 @@
</xsd:documentation>
<xsd:appinfo>
<a:operational>true</a:operational>
<a:indexed>true</a:indexed>
<a:since>3.7</a:since>
</xsd:appinfo>
</xsd:annotation>
Expand All @@ -1062,7 +1060,6 @@
</xsd:documentation>
<xsd:appinfo>
<a:operational>true</a:operational>
<!--<a:indexed>true</a:indexed>-->
<a:objectReferenceTargetType>tns:UserType</a:objectReferenceTargetType>
<a:since>3.7</a:since>
</xsd:appinfo>
Expand All @@ -1088,6 +1085,21 @@
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
<xsd:element name="autoCreateIdentifier" type="xsd:string" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
<p>
Identifies the reason of automated creation of this object or assignment.
Currently it is the name of a mapping that caused creation of a given assignment.
In the future we might put here e.g. name of a policy rule or analogous entity.
</p>
</xsd:documentation>
<xsd:appinfo>
<a:operational>true</a:operational>
<a:since>3.7</a:since>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:complexType>

Expand Down
Expand Up @@ -101,7 +101,7 @@ public static void assertFocusDefinition(ComplexTypeDefinition complexTypeDefini
assertFalse("Metadata is runtime", metadataContainer.isRuntimeSchema());
assertFalse("Metadata is dynamic", metadataContainer.isDynamic());
assertTrue("Metadata is NOT operational", metadataContainer.isOperational());
assertEquals("Metadata size", 21, metadataContainer.getDefinitions().size());
assertEquals("Metadata size", 22, metadataContainer.getDefinitions().size());

PrismReferenceDefinition tenantRefDef = complexTypeDefinition.findItemDefinition(UserType.F_TENANT_REF, PrismReferenceDefinition.class);
PrismAsserts.assertDefinition(tenantRefDef, UserType.F_TENANT_REF, ObjectReferenceType.COMPLEX_TYPE, 0, 1);
Expand Down
Expand Up @@ -222,8 +222,8 @@ public static <F extends FocusType> void assertNotAssignedOrg(PrismObject<F> use
}
}

public static void assertAssignedOrg(PrismObject<? extends FocusType> focus, String orgOid) {
assertAssigned(focus, orgOid, OrgType.COMPLEX_TYPE);
public static AssignmentType assertAssignedOrg(PrismObject<? extends FocusType> focus, String orgOid) {
return assertAssigned(focus, orgOid, OrgType.COMPLEX_TYPE);
}

public static void assertNotAssignedOrg(PrismObject<? extends FocusType> focus, String orgOid) {
Expand Down
Expand Up @@ -1315,6 +1315,11 @@ private String toStringStrength() {
return null;
}

@Override
public String getIdentifier() {
return mappingType != null ? mappingType.getName() : null;
}

/**
* Builder is used to construct a configuration of Mapping object, which - after building - becomes
* immutable.
Expand Down
Expand Up @@ -48,4 +48,9 @@ public interface PrismValueDeltaSetTripleProducer<V extends PrismValue, D extend
*/
boolean isSourceless();

/**
* Identifier of this producer; e.g. mapping name.
*/
String getIdentifier();

}
Expand Up @@ -87,6 +87,7 @@
import org.jetbrains.annotations.NotNull;

import static com.evolveum.midpoint.util.MiscUtil.getSingleValue;
import static java.util.Collections.singleton;

/**
* @author semancik
Expand Down Expand Up @@ -198,6 +199,8 @@ ItemDelta<V,D> consolidateTripleToDelta(
boolean addUnchangedValues, boolean filterExistingValues, boolean isExclusiveStrong,
String contextDescription, boolean applyWeak) throws ExpressionEvaluationException, PolicyViolationException, SchemaException {

boolean isAssignment = new ItemPath(FocusType.F_ASSIGNMENT).equivalent(itemPath);

ItemDelta<V,D> itemDelta = itemDefinition.createEmptyDelta(itemPath);

Item<V,D> itemExisting = null;
Expand Down Expand Up @@ -238,10 +241,7 @@ ItemDelta<V,D> consolidateTripleToDelta(
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);
}
LOGGER.trace("PVWOs for value {}:\nzero = {}\nplus = {}\nminus = {}", value, zeroPvwos, plusPvwos, minusPvwos);

boolean zeroHasStrong = false;
if (!zeroPvwos.isEmpty()) {
Expand All @@ -264,7 +264,7 @@ ItemDelta<V,D> consolidateTripleToDelta(
}

PrismValueDeltaSetTripleProducer<V, D> exclusiveMapping = null;
Collection<ItemValueWithOrigin<V,D>> pvwosToAdd = null;
Collection<ItemValueWithOrigin<V,D>> pvwosToAdd;
if (addUnchangedValues) {
pvwosToAdd = MiscUtil.union(zeroPvwos, plusPvwos);
} else {
Expand Down Expand Up @@ -322,7 +322,7 @@ ItemDelta<V,D> consolidateTripleToDelta(
continue;
}
LOGGER.trace("Value {} added to delta as ADD for item {} in {}", value, itemPath, contextDescription);
itemDelta.addValueToAdd((V)value.clone());
itemDelta.addValueToAdd(cloneAndApplyMetadata(value, isAssignment, pvwosToAdd));
continue;
}

Expand Down Expand Up @@ -404,7 +404,7 @@ ItemDelta<V,D> consolidateTripleToDelta(
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());
itemDelta.addValueToAdd(cloneAndApplyMetadata(value, isAssignment, zeroPvwos));
continue;
}
}
Expand All @@ -418,19 +418,20 @@ ItemDelta<V,D> consolidateTripleToDelta(
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);
Collection<ItemValueWithOrigin<V,D>> valuesToAdd = selectWeakValues(nonNegativePvwos, OriginType.ASSIGNMENTS, applyWeak);
if (valuesToAdd.isEmpty()) {
valuesToAdd = addWeakValues(nonNegativePvwos, OriginType.OUTBOUND, applyWeak);
valuesToAdd = selectWeakValues(nonNegativePvwos, OriginType.OUTBOUND, applyWeak);
}
if (valuesToAdd.isEmpty()) {
valuesToAdd = addWeakValues(nonNegativePvwos, null, applyWeak);
valuesToAdd = selectWeakValues(nonNegativePvwos, null, applyWeak);
}
LOGGER.trace("No value for item {} in {}, weak mapping processing yielded values: {}",
itemPath, contextDescription, valuesToAdd);
itemDelta.addValuesToAdd(valuesToAdd);
for (ItemValueWithOrigin<V, D> valueWithOrigin : valuesToAdd) {
itemDelta.addValueToAdd(cloneAndApplyMetadata(valueWithOrigin.getItemValue(), isAssignment, singleton(valueWithOrigin)));
}
} else {
LOGGER.trace("Existing values for item {} in {}, weak mapping processing skipped",
new Object[]{itemPath, contextDescription});
LOGGER.trace("Existing values for item {} in {}, weak mapping processing skipped", itemPath, contextDescription);
}

if (itemExisting != null) {
Expand All @@ -441,16 +442,55 @@ ItemDelta<V,D> consolidateTripleToDelta(
}

return itemDelta;

}

public static <V extends PrismValue, D extends ItemDefinition> V cloneAndApplyMetadata(V value, boolean isAssignment,
Collection<ItemValueWithOrigin<V, D>> origins) throws SchemaException {
return cloneAndApplyMetadata(value, isAssignment, () -> getAutoCreationIdentifier(origins));
}

public static <V extends PrismValue> Collection<V> cloneAndApplyMetadata(Collection<V> values, boolean isAssignment,
MappingType mapping) throws SchemaException {
List<V> rv = new ArrayList<>();
for (V value : values) {
rv.add(cloneAndApplyMetadata(value, isAssignment, mapping::getName));
}
return rv;
}

public static <V extends PrismValue> V cloneAndApplyMetadata(V value, boolean isAssignment,
MappingType mapping) throws SchemaException {
return cloneAndApplyMetadata(value, isAssignment, mapping::getName);
}

private static <V extends PrismValue> V cloneAndApplyMetadata(V value, boolean isAssignment,
Supplier<String> autoCreateIdentifierSupplier) throws SchemaException {
//noinspection unchecked
V cloned = (V) value.clone();
if (isAssignment && cloned instanceof PrismContainerValue) {
String autoCreationIdentifier = autoCreateIdentifierSupplier.get();
if (autoCreationIdentifier != null) {
//noinspection unchecked
PrismContainer<MetadataType> metadataContainer = ((PrismContainerValue) cloned).findOrCreateContainer(AssignmentType.F_METADATA);
metadataContainer.getOrCreateValue().asContainerable().setAutoCreateIdentifier(autoCreationIdentifier);
}
}
return cloned;
}

private static <V extends PrismValue, D extends ItemDefinition> String getAutoCreationIdentifier(Collection<ItemValueWithOrigin<V, D>> origins) {
// let's ignore conflicts (name1 vs name2, named vs unnamed) for now
for (ItemValueWithOrigin<V, D> origin : origins) {
if (origin.getMapping() != null && origin.getMapping().getIdentifier() != null) {
return origin.getMapping().getIdentifier();
}
}
return null;
}

private static <V extends PrismValue, D extends ItemDefinition> boolean hasValue(Item<V,D> item, ItemDelta<V,D> itemDelta) throws SchemaException {
if (item == null || item.isEmpty()) {
if (itemDelta != null && itemDelta.addsAnyValue()) {
return true;
} else {
return false;
}
return itemDelta != null && itemDelta.addsAnyValue();
} else {
if (itemDelta == null || itemDelta.isEmpty()) {
return true;
Expand All @@ -462,12 +502,12 @@ private static <V extends PrismValue, D extends ItemDefinition> boolean hasValue
}
}

private static <V extends PrismValue, D extends ItemDefinition> Collection<V> addWeakValues(Collection<? extends ItemValueWithOrigin<V,D>> pvwos, OriginType origin, boolean applyWeak) {
Collection<V> values = new ArrayList<V>();
private static <V extends PrismValue, D extends ItemDefinition> Collection<ItemValueWithOrigin<V,D>> selectWeakValues(Collection<? extends ItemValueWithOrigin<V,D>> pvwos, OriginType origin, boolean applyWeak) {
Collection<ItemValueWithOrigin<V,D>> values = new ArrayList<>();
for (ItemValueWithOrigin<V,D> pvwo: pvwos) {
if (pvwo.getMapping().getStrength() == MappingStrengthType.WEAK && applyWeak) {
if (origin == null || origin == pvwo.getItemValue().getOriginType()) {
values.add((V)pvwo.getItemValue().clone());
values.add(pvwo);
}
}
}
Expand Down
Expand Up @@ -206,6 +206,10 @@ public boolean isAuthoritative() {
public boolean isSourceless() {
return false;
}
@Override
public String getIdentifier() {
return null;
}
};
Collection<PrismValueDeltaSetTripleProducer<PrismPropertyValue<QName>,PrismPropertyDefinition<QName>>> col = new ArrayList<>(1);
col.add(prod);
Expand Down
Expand Up @@ -547,6 +547,7 @@ private <A, F extends FocusType, V extends PrismValue,D extends ItemDefinition>
if (ItemPath.isNullOrEmpty(targetFocusItemPath)) {
throw new ConfigurationException("Empty target path in "+mapping.getContextDescription());
}
boolean isAssignment = new ItemPath(FocusType.F_ASSIGNMENT).equivalent(targetFocusItemPath);
Item targetFocusItem = null;
if (focusNew != null) {
targetFocusItem = focusNew.findItem(targetFocusItemPath);
Expand All @@ -567,9 +568,7 @@ private <A, F extends FocusType, V extends PrismValue,D extends ItemDefinition>
// values in ZERO set will be compared with existing values in user property
// the differences will be added to delta

if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Inbound mapping for {} returned triple:\n{}", accountAttributeName, triple == null ? "null" : triple.debugDump());
}
LOGGER.trace("Inbound mapping for {} returned triple:\n{}", accountAttributeName, DebugUtil.debugDumpLazily(triple));

if (triple != null) {

Expand All @@ -585,8 +584,8 @@ private <A, F extends FocusType, V extends PrismValue,D extends ItemDefinition>

//if property is not multi value replace existing attribute
if (targetFocusItem != null && !targetFocusItem.getDefinition().isMultiValue() && !targetFocusItem.isEmpty()) {
Collection<V> replace = new ArrayList<V>();
replace.add((V) value.clone());
Collection<V> replace = new ArrayList<>();
replace.add(LensUtil.cloneAndApplyMetadata(value, isAssignment, inboundMappingType));
outputFocusItemDelta.setValuesToReplace(replace);

if (alreadyReplaced) {
Expand All @@ -595,7 +594,7 @@ private <A, F extends FocusType, V extends PrismValue,D extends ItemDefinition>
alreadyReplaced = true;
}
} else {
outputFocusItemDelta.addValueToAdd(value.clone());
outputFocusItemDelta.addValueToAdd(LensUtil.cloneAndApplyMetadata(value, isAssignment, inboundMappingType));
}
}
}
Expand All @@ -614,8 +613,9 @@ private <A, F extends FocusType, V extends PrismValue,D extends ItemDefinition>
}

Item shouldBeItem = targetItemDef.instantiate();
shouldBeItem.addAll(PrismValue.cloneCollection(triple.getZeroSet()));
shouldBeItem.addAll(PrismValue.cloneCollection(triple.getPlusSet()));
// added metadata is not a problem, as they are ignored when diffing
shouldBeItem.addAll(LensUtil.cloneAndApplyMetadata(triple.getZeroSet(), isAssignment, inboundMappingType));
shouldBeItem.addAll(LensUtil.cloneAndApplyMetadata(triple.getPlusSet(), isAssignment, inboundMappingType));
if (targetFocusItem != null) {
ItemDelta diffDelta = targetFocusItem.diff(shouldBeItem);
if (LOGGER.isTraceEnabled()) {
Expand Down

0 comments on commit 7805f45

Please sign in to comment.