Skip to content

Commit

Permalink
merge: fixes in mergers and handling of naturalKey
Browse files Browse the repository at this point in the history
  • Loading branch information
1azyman committed Mar 21, 2024
1 parent 8100ec3 commit ea81e42
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,24 +38,22 @@ public abstract class BaseItemMerger<T extends Item<?, ?>> implements ItemMerger
/** Marks any values inherited from "source" to "target" with appropriate (presumably source-related) origin. */
@Nullable protected final OriginMarker originMarker;

/**
* TODO: rename
*
* If fullMerge is true, item/values that don't exist in source will be removed from target.
* IF fullMerge is false then, item/values that don't exist in source will be left untouched in target.
*/
private boolean fullMerge;
private MergeStrategy strategy;

protected BaseItemMerger(@Nullable OriginMarker originMarker) {
this.originMarker = originMarker;
}

public boolean isFullMerge() {
return fullMerge;
protected boolean isFullMerge() {
return strategy == MergeStrategy.FULL;
}

public void setFullMerge(boolean fullMerge) {
this.fullMerge = fullMerge;
public MergeStrategy getStrategy() {
return strategy;
}

public void setStrategy(MergeStrategy strategy) {
this.strategy = strategy;
}

@Override
Expand All @@ -71,7 +69,7 @@ public void merge(
T sourceItem = (T) sourceParent.findItem(itemName);
// some shortcuts first
if (sourceItem == null || sourceItem.hasNoValues()) {
if (fullMerge) {
if (isFullMerge()) {
LOGGER.trace(" -> Nothing found at source; removing target item");
targetParent.removePaths(Arrays.asList(itemName));
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@
import com.evolveum.midpoint.prism.path.ItemName;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.path.PathKeyedMap;
import com.evolveum.midpoint.prism.schema.SchemaRegistry;
import com.evolveum.midpoint.schema.merger.key.NaturalKey;
import com.evolveum.midpoint.schema.merger.key.NaturalKeyImpl;
import com.evolveum.midpoint.util.MiscUtil;
import com.evolveum.midpoint.util.exception.ConfigurationException;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SystemException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;

Expand Down Expand Up @@ -117,26 +119,102 @@ private ItemMerger determineChildMerger(ItemName itemName, PrismContainerValue<?
ItemDefinition<?> childDef = ctd.findItemDefinition(itemName);
stateCheck(childDef != null, "No definition of %s in %s", itemName, ctd);

return findMerger(childDef);
}

private ItemMerger findMerger(ItemDefinition<?> childDef) {
ItemName itemName = childDef.getItemName();
Class<?> valueClass = childDef.getTypeClass();

List<QName> identifiers = childDef.getNaturalKey();
// try to find merger based on definition annotations
ItemMerger mergerByAnnotation = findMergerByAnnotation(childDef);
if (mergerByAnnotation != null) {
LOGGER.trace(
"Annotation-specific {} for {} (value class {}) with key {}",
mergerByAnnotation.getClass().getName(), itemName, valueClass);
}

// try to find merger based on class and supertypes (from custom mergers)
if (valueClass != null) {
ItemMerger mergerByType = findMergerByType(valueClass);
if (mergerByType != null) {
LOGGER.trace(
"Type-specific merger for {} (type {}) was found: {}",
childDef.getItemName(), valueClass, mergerByType);
return mergerByType;
}
}

// try to search for merger annotations in parent definitions
ItemMerger merger = findMergerByAnnotationRecursively(childDef);
if (merger != null) {
return merger;
}

LOGGER.trace("Using default merger for {} (value class {})", itemName, valueClass);
return createDefaultSubMerger(childDef, valueClass);
}

private ItemMerger findMergerByAnnotationRecursively(Definition def) {
ComplexTypeDefinition ctd = null;
if (def instanceof ComplexTypeDefinition c) {
ctd = c;
} else if (def instanceof PrismContainerDefinition<?> pcd) {
ctd = pcd.getComplexTypeDefinition();
}

if (ctd == null) {
return null;
}

ItemMerger merger = findMergerByAnnotation(ctd);
if (merger != null ) {
return merger;
}

QName superType = ctd.getSuperType();
if (superType == null) {
return null;
}

SchemaRegistry registry = def.getSchemaRegistry();
ctd = registry.findComplexTypeDefinitionByType(superType);

return findMergerByAnnotationRecursively(ctd);
}

private ItemMerger findMergerByAnnotation(Definition def) {
Class<?> valueClass = def.getTypeClass();

ItemName itemName = def instanceof ItemDefinition id ? id.getItemName() : null;

// try to use a:naturalKey annotation
List<QName> identifiers = def.getNaturalKey();
if (identifiers != null && !identifiers.isEmpty()) {
NaturalKey key = NaturalKeyImpl.of(identifiers.toArray(new QName[0]));

LOGGER.trace("Using generic item merger for {} (value class {}) with key {}", itemName, valueClass, key);
GenericItemMerger merger = new GenericItemMerger(originMarker, key);
merger.setFullMerge(isFullMerge());
merger.setStrategy(getStrategy());
return merger;
}

// try to use a:merger annotation (merger identifier for custom mergers)
String customMerger = def.getMerger();
TypeSpecificMergersConfigurator.TypedMergerSupplier typedSupplier =
customMerger != null ? identifierSpecificMergers.get(customMerger) : null;

if (typedSupplier != null) {
ItemMerger merger = typedSupplier.supplier().get();
LOGGER.trace("Using custom merger for {} (value class {}) with identifier {}", itemName, valueClass, merger.getClass());
return merger;
}

String customMerger = childDef.getMerger();
TypeSpecificMergersConfigurator.TypedMergerSupplier typedSupplier = identifierSpecificMergers.get(customMerger);
if (customMerger == null || typedSupplier == null) {
LOGGER.trace("Using default merger for {} (value class {})", itemName, valueClass);
return createDefaultSubMerger(itemName, valueClass);
if (customMerger != null) {
throw new SystemException(String.format("Merger with identifier %s was not found", customMerger));
}

return typedSupplier.supplier().get();
return null;
}

private ItemMerger findMergerByType(Class<?> valueClass) {
Expand All @@ -157,22 +235,11 @@ private ItemMerger findMergerByType(Class<?> valueClass) {
return entryFound != null ? entryFound.getValue().get() : null;
}

private ItemMerger createDefaultSubMerger(ItemName itemName, Class<?> valueClass) {
if (valueClass != null) {
// check custom mergers
ItemMerger mergerByType = findMergerByType(valueClass);
if (mergerByType != null) {
LOGGER.trace("Type-specific merger for {} (type {}) was found: {}", itemName, valueClass, mergerByType);
return mergerByType;
}
}

// todo check for merge annotation in parent definitions...

private ItemMerger createDefaultSubMerger(ItemDefinition<?> def, Class<?> valueClass) {
GenericItemMerger merger = new GenericItemMerger(
originMarker,
createSubChildMergersMap(itemName));
merger.setFullMerge(isFullMerge());
createSubChildMergersMap(def.getItemName()));
merger.setStrategy(getStrategy());

return merger;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@

package com.evolveum.midpoint.schema.merger;

/**
* TODO better strategy names
*/
public enum MergeStrategy {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,6 @@ static Map<Class<?>, Supplier<ItemMerger>> createStandardTypeSpecificMergersMap(
entry(
GuiObjectDetailsPageType.class,
() -> new GenericItemMerger(marker, DefaultNaturalKeyImpl.of(GuiObjectDetailsPageType.F_TYPE))),
entry(
VirtualContainersSpecificationType.class,
() -> new GenericItemMerger(
marker,
DefaultNaturalKeyImpl.of(
VirtualContainersSpecificationType.F_IDENTIFIER,
VirtualContainersSpecificationType.F_PATH))),
entry(
GuiResourceDetailsPageType.class,
() -> new GenericItemMerger(marker, DefaultNaturalKeyImpl.of(
Expand All @@ -88,10 +81,6 @@ static Map<Class<?>, Supplier<ItemMerger>> createStandardTypeSpecificMergersMap(
entry(
ClassLoggerLevelOverrideType.class,
() -> new GenericItemMerger(marker, DefaultNaturalKeyImpl.of(ClassLoggerLevelOverrideType.F_LOGGER))),
entry(
AuthorizationType.class,
() -> new GenericItemMerger(
marker, DefaultNaturalKeyImpl.of(AuthorizationType.F_NAME, AuthorizationType.F_ACTION))),
entry(
ObjectSelectorType.class,
() -> new GenericItemMerger(
Expand Down Expand Up @@ -128,28 +117,6 @@ static Map<Class<?>, Supplier<ItemMerger>> createStandardTypeSpecificMergersMap(
DefaultNaturalKeyImpl.of(
ModificationPolicyConstraintType.F_NAME,
ModificationPolicyConstraintType.F_OPERATION))),
entry(
AuthenticationSequenceModuleType.class,
() -> new GenericItemMerger(marker, DefaultNaturalKeyImpl.of(AuthenticationSequenceModuleType.F_IDENTIFIER))),
entry(
CredentialPolicyType.class,
() -> new GenericItemMerger(marker, DefaultNaturalKeyImpl.of(CredentialPolicyType.F_NAME))),
entry(
SecurityQuestionDefinitionType.class,
() -> new GenericItemMerger(marker, DefaultNaturalKeyImpl.of(SecurityQuestionDefinitionType.F_IDENTIFIER))),
entry(
GuiObjectListViewType.class,
() -> new GenericItemMerger(marker, DefaultNaturalKeyImpl.of(
GuiObjectListViewType.F_IDENTIFIER,
GuiObjectListViewType.F_TYPE))),
entry(
GuiShadowListViewType.class,
() -> new GenericItemMerger(marker, DefaultNaturalKeyImpl.of(
GuiShadowListViewType.F_IDENTIFIER,
GuiShadowListViewType.F_TYPE,
GuiShadowListViewType.F_RESOURCE_REF,
GuiShadowListViewType.F_KIND,
GuiShadowListViewType.F_INTENT))),
entry(
AbstractObjectTypeConfigurationType.class,
() -> new GenericItemMerger(marker, DefaultNaturalKeyImpl.of(AbstractObjectTypeConfigurationType.F_TYPE))),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7666,6 +7666,7 @@
</xsd:documentation>
<xsd:appinfo>
<a:container/>
<a:naturalKey>name</a:naturalKey>
</xsd:appinfo>
</xsd:annotation>
<xsd:sequence>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2050,6 +2050,7 @@
<xsd:appinfo>
<a:container/>
<a:since>4.1</a:since>
<a:naturalKey>identifier</a:naturalKey>
</xsd:appinfo>
</xsd:annotation>
<xsd:sequence>
Expand Down Expand Up @@ -2564,6 +2565,7 @@
</xsd:documentation>
<xsd:appinfo>
<a:container/>
<a:naturalKey>name</a:naturalKey>
</xsd:appinfo>
</xsd:annotation>
<xsd:sequence>
Expand Down Expand Up @@ -3150,6 +3152,7 @@
</xsd:documentation>
<xsd:appinfo>
<a:container/>
<a:naturalKey>identifier</a:naturalKey>
</xsd:appinfo>
</xsd:annotation>
<xsd:sequence>
Expand Down

0 comments on commit ea81e42

Please sign in to comment.