Skip to content

Commit

Permalink
natural key and mergers moved to prism
Browse files Browse the repository at this point in the history
  • Loading branch information
1azyman committed Apr 16, 2024
1 parent 3de50c7 commit a08701a
Show file tree
Hide file tree
Showing 23 changed files with 1,233 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,18 @@
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;

import javax.xml.namespace.QName;

import com.evolveum.midpoint.prism.annotation.ItemDiagramSpecification;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import com.evolveum.midpoint.prism.annotation.ItemDiagramSpecification;
import com.evolveum.midpoint.prism.delta.ItemMerger;
import com.evolveum.midpoint.prism.key.NaturalKey;
import com.evolveum.midpoint.prism.schema.SchemaRegistry;
import com.evolveum.midpoint.util.DebugDumpable;
import com.evolveum.midpoint.util.annotation.Experimental;

import org.jetbrains.annotations.Nullable;

/**
* Common interface to access all definitions.
*/
Expand Down Expand Up @@ -57,7 +56,8 @@ public interface Definition
*
* @return the type name
*/
@NotNull QName getTypeName();
@NotNull
QName getTypeName();

/**
* This means that this particular definition (of an item or of a type) is part of the runtime schema, e.g.
Expand Down Expand Up @@ -211,23 +211,31 @@ default SchemaRegistry getSchemaRegistry() {
*
* Nullable by design, to avoid creating lots of empty maps.
*/
@Nullable Map<QName, Object> getAnnotations();
@Nullable
Map<QName, Object> getAnnotations();

@Nullable List<SchemaMigration> getSchemaMigrations();
@Nullable
List<SchemaMigration> getSchemaMigrations();

@Experimental
List<ItemDiagramSpecification> getDiagrams();

@Nullable
String getMerger();
String getMergerIdentifier();

@Nullable
ItemMerger getMergerInstance(@NotNull MergeStrategy strategy, @Nullable OriginMarker originMarker);

@Nullable
List<QName> getNaturalKeyConstituents();

@Nullable
List<QName> getNaturalKey();
NaturalKey getNaturalKeyInstance();

@NotNull
Definition clone();

default String debugDump(int indent, IdentityHashMap<Definition,Object> seen) {
default String debugDump(int indent, IdentityHashMap<Definition, Object> seen) {
return debugDump(indent);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright (C) 2010-2024 Evolveum and contributors
*
* This work is dual-licensed under the Apache License 2.0
* and European Union Public License. See LICENSE file for details.
*/

package com.evolveum.midpoint.prism;

import com.evolveum.midpoint.prism.delta.ItemMerger;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public interface ItemMergerFactory {

@Nullable
ItemMerger createMerger(@NotNull ItemDefinition<?> definition, @NotNull MergeStrategy strategy, @Nullable OriginMarker originMarker);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (C) 2010-2024 Evolveum and contributors
*
* This work is dual-licensed under the Apache License 2.0
* and European Union Public License. See LICENSE file for details.
*/

package com.evolveum.midpoint.prism;

public enum MergeStrategy {

/**
* Merge the values from the source item to the target item.
*
* If the target item already contains a value:
* * for containers, the values are merged recursively
* * for other items (property, reference), the value is *preserved*
*
* If the source item contains a value that is not present in the target item, it is added.
*
* If the source item doesn't contain value present in target, value is *not changed* in target.
*
* Example scenario:
* Source: resource template
* Target: resource that uses the template
*
* The overlay strategy is used to merge the resource template to the resource to create the final resource object.
*/
OVERLAY,

/**
* Merge the values from the source item to the target item.
*
* If the target item already contains a value:
* * for containers, the values are merged recursively
* * for other items (property, reference), the value is *replaced*
*
* If the source item contains a value that is not present in the target item, it is added.
*
* If the source item doesn't contain value present in target, value is *removed* from target.
*
* Example scenario:
* Source: local object in studio project (file without PCV ids)
* Target: object in midPoint (with PCV ids)
*
* To create minimal diff we need to merge source object to target object and then with result and
* target object we can create proper diff (object delta) without phantom (add/remove containers).
*/
FULL
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ public interface MutableDefinition extends Definition {

void addDiagram(ItemDiagramSpecification diagram);

void setMerger(String merger);
void setMergerIdentifier(String mergerIdentifier);

void setNaturalKey(List<QName> naturalKey);
void setNaturalKeyConstituents(List<QName> naturalKeyConstituents);

/**
* A variant of {@link MutableDefinition} that does not allow any modifications. Useful for implementations that want
Expand Down Expand Up @@ -100,11 +100,12 @@ default void setDisplayHint(DisplayHint display) {
}

@Override
default void setMerger(String merger) {
default void setMergerIdentifier(String mergerIdentifier) {
throw new UnsupportedOperationException();
}

@Override
default void setNaturalKey(List<QName> naturalKey) {
default void setNaturalKeyConstituents(List<QName> naturalKeyConstituents) {
throw new UnsupportedOperationException();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2010-2024 Evolveum and contributors
*
* This work is dual-licensed under the Apache License 2.0
* and European Union Public License. See LICENSE file for details.
*/

package com.evolveum.midpoint.prism;

import com.evolveum.midpoint.util.exception.SchemaException;

/**
* Sets the origin information in prism values being merged.
*
* In order to track the origin of individual prism item values in the merged object, the mergers are obliged to fill-in
* this information on any values being processed. Specifically, when a prism value `V` is inherited from the source
* (super-)object `S`, this fact is recorded in the {@link com.evolveum.midpoint.xml.ns._public.common.common_3.ValueMetadataType}
* of `V` by setting `provenance/acquisition/originRef` to the reference to `S`.
*
* Notes:
*
* . When a composite value ({@link PrismContainerValue}) is inherited, only the root value gets the metadata. It's not necessary
* (and therefore it's avoided) to set the metadata on each of the contained ("inner") values.
* . When a value is passed through multiple layers of inheritance (e.g. inherited from `O1` to `O2` and finally to `O3`),
* only the "real" origin (i.e. `O1`) is recorded.
* . Origin for values not passing through the inheritance relation (i.e. values at the bottom of the inheritance hierarchy)
* are not marked - not even if the containing resource has an OID.
*
* For some examples please see `TestResourceTemplateMerge`.
*
* Important assumption:
*
* - The current implementation assumes that there is no value metadata stored in the (original) objects being merged; i.e.
* that all metadata come from this {@link OriginMarker}.
*/
public interface OriginMarker {

/** Imprints the origin into the value. */
void mark(PrismValue value) throws SchemaException;

}
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,9 @@ default PrismQueryLanguageParser createQueryParser() {

PrismQuerySerializer querySerializer();

@NotNull
ItemMergerFactory itemMergerFactory();

static PrismContext get() {
return PrismService.get().prismContext();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
import java.util.Map;
import javax.xml.namespace.QName;

import com.evolveum.midpoint.prism.delta.ItemMerger;
import com.evolveum.midpoint.prism.key.NaturalKey;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Expand Down Expand Up @@ -128,14 +131,14 @@ default DisplayHint getDisplayHint() {

@Override
@Nullable
default String getMerger() {
return delegate().getMerger();
default String getMergerIdentifier() {
return delegate().getMergerIdentifier();
}

@Override
@Nullable
default List<QName> getNaturalKey() {
return delegate().getNaturalKey();
default List<QName> getNaturalKeyConstituents() {
return delegate().getNaturalKeyConstituents();
}

@Override
Expand Down Expand Up @@ -207,4 +210,13 @@ default String debugDump(int indent, IdentityHashMap<Definition, Object> seen) {
default String getMutabilityFlag() {
return delegate().getMutabilityFlag();
}

@Override
default @Nullable ItemMerger getMergerInstance(@NotNull MergeStrategy strategy, @Nullable OriginMarker originMarker) {
return delegate().getMergerInstance(strategy, originMarker);
}
@Override
default @Nullable NaturalKey getNaturalKeyInstance() {
return delegate().getNaturalKeyInstance();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (C) 2010-2024 Evolveum and contributors
*
* This work is dual-licensed under the Apache License 2.0
* and European Union Public License. See LICENSE file for details.
*/

package com.evolveum.midpoint.prism.delta;

import org.jetbrains.annotations.NotNull;

import com.evolveum.midpoint.prism.PrismContainerValue;
import com.evolveum.midpoint.prism.key.NaturalKey;
import com.evolveum.midpoint.prism.path.ItemName;
import com.evolveum.midpoint.util.exception.ConfigurationException;
import com.evolveum.midpoint.util.exception.SchemaException;

public interface ItemMerger {

NaturalKey getNaturalKey();

/**
* Merges all data about specific item (named `itemName`) from `source` container value to `target` one, according
* to (its own) strategy.
*
* So, `source` is not modified; the `target` is.
*
* The implementation is responsible for setting origin information on all prism values copied from `source` to `target`.
*/
void merge(@NotNull ItemName itemName, @NotNull PrismContainerValue<?> target, @NotNull PrismContainerValue<?> source)
throws ConfigurationException, SchemaException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public interface EquivalenceStrategy {
/**
* As {@link #REAL_VALUE} but taking different PCV IDs into account (if both are present).
*
* Currently this is the default for delta application. See {@link ParameterizedEquivalenceStrategy#FOR_DELTA_ADD_APPLICATION}
* Currently, this is the default for delta application. See {@link ParameterizedEquivalenceStrategy#FOR_DELTA_ADD_APPLICATION}
* and {@link ParameterizedEquivalenceStrategy#FOR_DELTA_DELETE_APPLICATION}.
*
* It is not quite clear if this strategy is well-formed. Often we want to differentiate PCV IDs
Expand All @@ -68,6 +68,12 @@ public interface EquivalenceStrategy {
*/
ParameterizedEquivalenceStrategy REAL_VALUE_CONSIDER_DIFFERENT_IDS = ParameterizedEquivalenceStrategy.realValueConsiderDifferentIds();

/**
* Same as {@link #REAL_VALUE_CONSIDER_DIFFERENT_IDS} but also takes natural keys into account.
*/
ParameterizedEquivalenceStrategy REAL_VALUE_CONSIDER_DIFFERENT_IDS_NATURAL_KEYS = ParameterizedEquivalenceStrategy.realValueConsiderDifferentIds();


/**
* This is something between {@link #DATA} and {@link #REAL_VALUE}: ignores
* operational items and values, container IDs, value metadata (just like REAL_VALUE) but
Expand Down

0 comments on commit a08701a

Please sign in to comment.