Skip to content

Commit

Permalink
Improve ID Match correlator + others
Browse files Browse the repository at this point in the history
1. ID Match correlator now obeys explicitly specified correlation
properties.
2. CorrelationCaseManager now re-imports the shadow after manual
correlation is done. (This will be probably changed later.)
3. Cleaned-up correlator instantiation code a bit.
4. Minor GUI improvements: clickable links for candidate owners,
slightly changed labels.
5. Fixed correlation-related tests.
  • Loading branch information
mederly committed Jan 28, 2022
1 parent 88fe014 commit 8f09b51
Show file tree
Hide file tree
Showing 33 changed files with 510 additions and 521 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import org.jetbrains.annotations.Nullable;

import com.evolveum.midpoint.gui.api.page.PageBase;
import com.evolveum.midpoint.model.api.correlator.CorrelatorInstantiationContext;
import com.evolveum.midpoint.model.api.correlator.FullCorrelationContext;
import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.result.OperationResult;
Expand All @@ -36,11 +36,12 @@ public class CorrelationContextDto implements Serializable {
static final String F_CORRELATION_OPTIONS = "correlationOptions";
static final String F_CORRELATION_PROPERTIES = "correlationProperties";

private static final String HEADER_NEW_OWNER = "New owner";
private static final String HEADER_SUGGESTION = "Suggestion %d";
// TODO move into properties
private static final String TEXT_BEING_CORRELATED = "Object being correlated";
private static final String TEXT_CANDIDATE = "Candidate owner %d";

/**
* Headers for individual options: "New owner", "Suggestion 1", "Suggestion 2", ...
* Headers for individual options.
*/
private final List<String> optionHeaders = new ArrayList<>();

Expand Down Expand Up @@ -104,11 +105,11 @@ private void createCorrelationOptions(CorrelationContextType context) {
int suggestionNumber = 1;
for (PotentialOwnerType potentialOwner : context.getPotentialOwners().getPotentialOwner()) {
if (SchemaConstants.CORRELATION_NONE_URI.equals(potentialOwner.getUri())) {
optionHeaders.add(0, HEADER_NEW_OWNER);
optionHeaders.add(0, TEXT_BEING_CORRELATED);
correlationOptions.add(0,
new CorrelationOptionDto(context.getPreFocusRef()));
} else {
optionHeaders.add(String.format(HEADER_SUGGESTION, suggestionNumber));
optionHeaders.add(String.format(TEXT_CANDIDATE, suggestionNumber));
correlationOptions.add(
new CorrelationOptionDto(potentialOwner));
suggestionNumber++;
Expand All @@ -118,8 +119,8 @@ private void createCorrelationOptions(CorrelationContextType context) {

private void createCorrelationPropertiesDefinitions(CaseType aCase, PageBase pageBase, Task task, OperationResult result)
throws CommonException {
CorrelatorInstantiationContext instantiationContext =
pageBase.getCorrelationService().getInstantiationContext(aCase.asPrismObject(), task, result);
FullCorrelationContext instantiationContext =
pageBase.getCorrelationService().getFullCorrelationContext(aCase.asPrismObject(), task, result);
CorrelationPropertiesDefinitionType propertiesBean = instantiationContext.synchronizationBean.getCorrelationProperties();
CorrelationOptionDto newOwnerOption = getNewOwnerOption();
if (propertiesBean != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@
package com.evolveum.midpoint.gui.impl.page.admin.cases.component;

import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.ObjectTypeUtil;
import com.evolveum.midpoint.schema.util.WorkItemId;
import com.evolveum.midpoint.task.api.Task;
import com.evolveum.midpoint.util.logging.LoggingUtils;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.web.component.AjaxButton;

import com.evolveum.midpoint.web.component.data.LinkedReferencePanel;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.behavior.AttributeAppender;
import org.apache.wicket.markup.html.basic.Label;
Expand Down Expand Up @@ -54,6 +57,10 @@ public class CorrelationContextPanel extends AbstractObjectMainPanel<CaseType, C

private static final String OP_LOAD = CorrelationContextPanel.class.getName() + ".load";

// Move into properties
private static final String TEXT_CREATE_NEW = "Create new";
private static final String TEXT_CORRELATE = "Correlate";

@SuppressWarnings("unused") // called by the framework
public CorrelationContextPanel(String id, CaseDetailsModels model, ContainerPanelConfigurationType config) {
super(id, model, config);
Expand Down Expand Up @@ -101,7 +108,7 @@ public void onClick(AjaxRequestTarget target) {

actionButton.add(
new Label(ID_ACTION_LABEL,
item.getModelObject().isNewOwner() ? "Create new owner" : "Use this owner"));
item.getModelObject().isNewOwner() ? TEXT_CREATE_NEW : TEXT_CORRELATE));

item.add(actionButton);
}
Expand All @@ -113,7 +120,21 @@ public void onClick(AjaxRequestTarget target) {

@Override
protected void populateItem(ListItem<CorrelationOptionDto> item) {
item.add(new Label(ID_NAME, item.getModelObject().getReferenceId()));
// A full-object reference to the candidate owner
ReadOnlyModel<ObjectReferenceType> referenceModel = new ReadOnlyModel<>(
() -> {
CorrelationOptionDto optionDto = item.getModelObject();
if (!optionDto.isNewOwner()) {
return ObjectTypeUtil.createObjectRefWithFullObject(
optionDto.getObject());
} else {
// GUI cannot currently open object that does not exist in the repository.
return null;
}
}
);
item.add(
new LinkedReferencePanel<>(ID_NAME, referenceModel));
}
};
add(referenceIds);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,14 @@
package com.evolveum.midpoint.gui.impl.page.admin.cases.component;

import java.io.Serializable;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import org.jetbrains.annotations.NotNull;

import com.evolveum.midpoint.prism.PrismObject;
import com.evolveum.midpoint.prism.PrismValue;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.util.MatchingUtil;
import com.evolveum.midpoint.schema.util.ObjectTypeUtil;
import com.evolveum.midpoint.util.MiscUtil;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType;
Expand Down Expand Up @@ -85,11 +83,7 @@ public CorrelationPropertyValues getPropertyValues(CorrelationPropertyDefinition
}

private @NotNull Set<String> getValuesForPath(ItemPath path) {
return object.getAllValues(path).stream()
.filter(Objects::nonNull)
.map(PrismValue::getRealValue)
.map(String::valueOf)
.collect(Collectors.toSet());
return MatchingUtil.getValuesForPath(object, path);
}

public @NotNull PrismObject<?> getObject() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,31 @@

package com.evolveum.midpoint.schema.util;

import java.util.ArrayList;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;

import com.evolveum.midpoint.prism.*;

import com.evolveum.midpoint.prism.path.ItemName;
import com.evolveum.midpoint.prism.path.ItemPath;

import com.evolveum.midpoint.prism.util.CloneUtil;
import com.evolveum.midpoint.prism.util.JavaTypeConverter;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowAttributesType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType;

import org.jetbrains.annotations.NotNull;

import com.evolveum.midpoint.prism.PrismProperty;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;

import org.jetbrains.annotations.Nullable;

/**
* TEMPORARY implementation!
* TEMPORARY implementation! This class contains various hacking util methods helping during development of ID Match correlation.
*/
public class MatchingUtil {

Expand All @@ -43,4 +56,106 @@ public static List<PrismProperty<?>> getSingleValuedProperties(@NotNull ObjectTy
});
return properties;
}

public static Set<String> getValuesForPath(PrismObject<?> object, ItemPath path) {
return object.getAllValues(path).stream()
.filter(Objects::nonNull)
.map(PrismValue::getRealValue)
.map(String::valueOf)
.collect(Collectors.toSet());
}

/**
* Finds a property even if the path was reduced by removing all container IDs.
*
* Returns the first property found. (Later we may combine all properties into single one.)
*/
public static @Nullable PrismProperty<?> findProperty(ObjectType object, ItemPath path) {
List<PrismProperty<?>> matching = new ArrayList<>();
//noinspection unchecked
object.asPrismObject().accept(visitable -> {
if (visitable instanceof PrismProperty<?>) {
PrismProperty<?> property = (PrismProperty<?>) visitable;
if (property.getPath().namedSegmentsOnly().equivalent(path)) {
matching.add(property);
}
}
});
if (matching.isEmpty()) {
return null;
} else {
return matching.get(0);
}
}

/**
* Copies attributes into focus object. Candidate items are looked for in the root container
* and in the extension. They are matched using the item name. Type conversion (e.g. polystring <-> string)
* is attempted as well.
*/
public static void copyAttributes(FocusType preFocus, ShadowType resourceObject) throws SchemaException {
ShadowAttributesType attributes = resourceObject.getAttributes();
if (attributes != null) {
//noinspection unchecked
for (Item<?, ?> attribute : (Collection<Item<?, ?>>) attributes.asPrismContainerValue().getItems()) {
putIntoFocus(preFocus, attribute);
}
}
}

private static void putIntoFocus(FocusType preFocus, Item<?, ?> attributeItem) throws SchemaException {
LOGGER.debug("Converting {}", attributeItem);
if (!(attributeItem instanceof PrismProperty<?>)) {
LOGGER.trace("Not a property: {}", attributeItem);
return;
}
PrismProperty<?> attribute = (PrismProperty<?>) attributeItem;

PrismObject<? extends FocusType> preFocusObject = preFocus.asPrismObject();

PrismObjectDefinition<? extends FocusType> def =
Objects.requireNonNull(
preFocusObject.getDefinition(),
() -> "no definition for pre-focus: " + preFocus);

String localName = attribute.getElementName().getLocalPart();
ItemName directPath = new ItemName("", localName);
PrismPropertyDefinition<?> directDef = def.findPropertyDefinition(directPath);
if (directDef != null) {
if (preFocusObject.findItem(directPath) == null) {
preFocusObject.add(
createPropertyClone(attribute, directDef));
}
return;
}

ItemPath extensionPath = ItemPath.create(ObjectType.F_EXTENSION, directPath);
PrismPropertyDefinition<Object> extensionDef = def.findPropertyDefinition(extensionPath);
if (extensionDef != null) {
if (preFocusObject.findItem(extensionPath) == null) {
preFocusObject.getOrCreateExtension().getValue()
.add(createPropertyClone(attribute, extensionDef));
}
return;
}

LOGGER.trace("{} has no definition in focus", localName);
}

@SuppressWarnings("unchecked")
@NotNull private static PrismProperty<?> createPropertyClone(
PrismProperty<?> attribute, PrismPropertyDefinition<?> directDef) throws SchemaException {
PrismProperty<Object> property = (PrismProperty<Object>) directDef.instantiate();
Class<?> targetType = directDef.getTypeClassIfKnown();
if (targetType == null) {
//noinspection unchecked,rawtypes
property.addAll((Collection) CloneUtil.cloneCollectionMembers(attribute.getValues()));
} else {
for (Object realValue : attribute.getRealValues()) {
property.addRealValue(
JavaTypeConverter.convert(targetType, realValue, false));
}
}
return property;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -341,15 +341,15 @@ public static ObjectReferenceType createObjectRef(PrismObject<?> object, QName r
return ref;
}

public static <T extends ObjectType> ObjectReferenceType createObjectRefWithFullObject(PrismObject<T> object) {
public static ObjectReferenceType createObjectRefWithFullObject(PrismObject<?> object) {
return createObjectRefWithFullObject(object, PrismContext.get());
}

public static <T extends ObjectType> ObjectReferenceType createObjectRefWithFullObject(T object) {
public static ObjectReferenceType createObjectRefWithFullObject(ObjectType object) {
return createObjectRefWithFullObject(object, PrismContext.get());
}

public static <T extends ObjectType> ObjectReferenceType createObjectRefWithFullObject(PrismObject<T> object,
public static ObjectReferenceType createObjectRefWithFullObject(PrismObject<?> object,
PrismContext prismContext) {
if (object == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Correlator instantiateCorrelator(
/**
* TODO
*/
@NotNull CorrelatorInstantiationContext getInstantiationContext(
@NotNull FullCorrelationContext getFullCorrelationContext(
@NotNull PrismObject<CaseType> aCase,
@NotNull Task task,
@NotNull OperationResult result)
Expand Down

0 comments on commit 8f09b51

Please sign in to comment.