Skip to content

Commit

Permalink
Add draft item-level simulation report
Browse files Browse the repository at this point in the history
This commit provides a simple (unfinished) simulation report on the
level of individual modified items.

Other changes:

1. Added <?> to ItemDefinition is various places
(see 64aa3962b70b4364bd6ad1f5fdf7ce8be4687ff4 in prism).

2. Added support for multivalued report parameters.
  • Loading branch information
mederly committed Feb 24, 2023
1 parent 5949978 commit 2dfc624
Show file tree
Hide file tree
Showing 42 changed files with 660 additions and 213 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3353,7 +3353,7 @@ public void onClick(AjaxRequestTarget target) {
.collect(Collectors.toSet());
}
if (!oids.isEmpty()) {
@NotNull Item<PrismValue, ItemDefinition> extensionQuery = prepareExtensionValues(oids);
@NotNull Item<PrismValue, ItemDefinition<?>> extensionQuery = prepareExtensionValues(oids);

MidPointPrincipal principal = pageBase.getPrincipal();
if (principal == null) {
Expand Down Expand Up @@ -3410,21 +3410,21 @@ public void onClick(AjaxRequestTarget target) {
*/

@NotNull
private Item<PrismValue, ItemDefinition> prepareExtensionValues(Collection<String> oids) throws SchemaException {
private Item<PrismValue, ItemDefinition<?>> prepareExtensionValues(Collection<String> oids) throws SchemaException {
PrismContext prismContext = pageBase.getPrismContext();
ObjectQuery objectQuery = prismContext.queryFor(ObjectType.class)
.id(oids.toArray(new String[0]))
.build();
QueryType queryBean = pageBase.getQueryConverter().createQueryType(objectQuery);
PrismContainerDefinition<?> extDef = PrismContext.get().getSchemaRegistry()
.findObjectDefinitionByCompileTimeClass(TaskType.class).findContainerDefinition(TaskType.F_EXTENSION);
ItemDefinition<Item<PrismValue, ItemDefinition>> def = extDef != null
ItemDefinition<Item<PrismValue, ItemDefinition<?>>> def = extDef != null
? extDef.findItemDefinition(SchemaConstants.MODEL_EXTENSION_OBJECT_QUERY)
: null;
if (def == null) {
throw new SchemaException("No definition of " + SchemaConstants.MODEL_EXTENSION_OBJECT_QUERY + " in the extension");
}
Item<PrismValue, ItemDefinition> extensionItem = def.instantiate();
Item<PrismValue, ItemDefinition<?>> extensionItem = def.instantiate();
extensionItem.add(prismContext.itemFactory().createValue(queryBean));
return extensionItem;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ public static boolean isValueFromResourceTemplate(PrismValue valueFromDelta, Pri
if (hasValueMetadata(valueFromDelta)) {
return true;
}
Item<PrismValue, ItemDefinition> item = parent.findItem(valueFromDelta.getParent().getPath());
Item<PrismValue, ItemDefinition<?>> item = parent.findItem(valueFromDelta.getParent().getPath());
PrismContainerValue<?> value = item.getParent();
while (!(value instanceof PrismObjectValue)) {
if (hasValueMetadata(value)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public int getOrder() {
public PrismReferenceWrapper<R> createWrapper(PrismContainerValueWrapper<?> parent, ItemDefinition<?> def, WrapperContext context) throws SchemaException {
ItemName name = def.getItemName();

Item<PrismValue, ItemDefinition> childItem = parent.getNewValue().findItem(name);
Item<?, ?> childItem = parent.getNewValue().findItem(name);

if ((skipCreateWrapper(def, ItemStatus.NOT_CHANGED, context, childItem == null || CollectionUtils.isEmpty(childItem.getValues())))
|| !(childItem.getRealValue() instanceof RawType)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ public ObjectDelta<ResourceType> getObjectDelta() throws SchemaException {
ObjectDelta<ResourceType> objectDelta = getPrismContext().deltaFor(getObject().getCompileTimeClass())
.asObjectDelta(getObject().getOid());

Collection<ItemDelta<PrismValue, ItemDefinition>> deltas = new ArrayList<>();
Collection<ItemDelta<PrismValue, ItemDefinition<?>>> deltas = new ArrayList<>();
for (ItemWrapper<?, ?> itemWrapper : getValue().getItems()) {
Collection<ItemDelta<PrismValue, ItemDefinition>> delta = itemWrapper.getDelta();
Collection<ItemDelta<PrismValue, ItemDefinition<?>>> delta = itemWrapper.getDelta();
if (delta == null || delta.isEmpty()) {
continue;
}
Expand Down Expand Up @@ -121,12 +121,12 @@ private void removeIdFromContainerValue(PrismValue value) {
}
}

private Collection<ItemDelta<PrismValue, ItemDefinition>> processModifyDeltas(
Collection<ItemDelta<PrismValue, ItemDefinition>> deltas) throws SchemaException {
private Collection<ItemDelta<PrismValue, ItemDefinition<?>>> processModifyDeltas(
Collection<ItemDelta<PrismValue, ItemDefinition<?>>> deltas) throws SchemaException {

Collection<ItemDelta<PrismValue, ItemDefinition>> processedDeltas = new ArrayList<>();
Collection<ItemDelta<PrismValue, ItemDefinition<?>>> processedDeltas = new ArrayList<>();

for (ItemDelta<PrismValue, ItemDefinition> delta : deltas) {
for (ItemDelta<PrismValue, ItemDefinition<?>> delta : deltas) {
if (delta.isDelete()) {
List<PrismValue> valuesFromTemplate = new ArrayList<>();
delta.getValuesToDelete().forEach(v -> {
Expand All @@ -138,7 +138,7 @@ private Collection<ItemDelta<PrismValue, ItemDefinition>> processModifyDeltas(
});
delta.getValuesToDelete().removeAll(valuesFromTemplate);
if (delta.isDelete()) {
ItemDelta<PrismValue, ItemDefinition> deleteDelta = delta.clone();
ItemDelta<PrismValue, ItemDefinition<?>> deleteDelta = delta.clone();
deleteDelta.clearValuesToAdd();
deleteDelta.clearValuesToReplace();
processedDeltas.add(deleteDelta);
Expand All @@ -159,7 +159,7 @@ private Collection<ItemDelta<PrismValue, ItemDefinition>> processModifyDeltas(
processedValues.addAll(delta.getValuesToReplace());
}

Item<PrismValue, ItemDefinition> parentItem = getItem().findItem(delta.getPath());
Item<PrismValue, ItemDefinition<?>> parentItem = getItem().findItem(delta.getPath());

PrismContainerValue<?> parentContainerValue = parentItem.getParent();

Expand All @@ -169,7 +169,7 @@ private Collection<ItemDelta<PrismValue, ItemDefinition>> processModifyDeltas(
}

PrismContainerValue foundValue = null;
for (ItemDelta<PrismValue, ItemDefinition> processedDelta : processedDeltas) {
for (ItemDelta<PrismValue, ItemDefinition<?>> processedDelta : processedDeltas) {
if (processedDelta.isAdd()
&& processedDelta.getValuesToAdd().iterator().next() instanceof PrismContainerValue
&& processedDelta.getPath().isSubPath(delta.getPath())) {
Expand All @@ -180,7 +180,7 @@ private Collection<ItemDelta<PrismValue, ItemDefinition>> processModifyDeltas(
}
}
}
ItemDelta<PrismValue, ItemDefinition> newDelta =
ItemDelta<PrismValue, ItemDefinition<?>> newDelta =
processAddOrModifyDelta(parentContainerValue, processedValues, foundValue);
if (newDelta != null) {
processedDeltas.add(newDelta);
Expand All @@ -189,7 +189,7 @@ private Collection<ItemDelta<PrismValue, ItemDefinition>> processModifyDeltas(
return processedDeltas;
}

private ItemDelta<PrismValue, ItemDefinition> processAddOrModifyDelta(
private ItemDelta<PrismValue, ItemDefinition<?>> processAddOrModifyDelta(
PrismContainerValue<?> parentContainerValue, Collection<PrismValue> processedValues, PrismContainerValue<?> valueOfExistingDelta) throws SchemaException {
PrismValue value = processedValues.iterator().next();
Itemable parent = value.getParent();
Expand Down Expand Up @@ -241,7 +241,7 @@ private PrismContainerValue<?> createParentValueForAddDelta(
}
if (MERGE_IDENTIFIERS.containsKey(typeClass)) {
for (ItemName path : MERGE_IDENTIFIERS.get(typeClass)) {
Item<PrismValue, ItemDefinition> item = origParentValue.findItem(path);
Item<PrismValue, ItemDefinition<?>> item = origParentValue.findItem(path);
if (item != null && !item.isEmpty() && item.valuesStream().anyMatch(v -> !v.isEmpty())) {
Item newItem = newValue.findOrCreateItem(path);
for (PrismValue value : item.getValues()) {
Expand Down Expand Up @@ -272,11 +272,11 @@ private PrismContainerValue<?> createParentValueForAddDelta(
return newValue;
}

private void removingMetadataForSuperOrigin(Collection<ItemDelta<PrismValue, ItemDefinition>> deltas) {
private void removingMetadataForSuperOrigin(Collection<ItemDelta<PrismValue, ItemDefinition<?>>> deltas) {
deltas.forEach(delta -> removingMetadataForSuperOrigin(delta));
}

private void removingMetadataForSuperOrigin(ItemDelta<PrismValue, ItemDefinition> delta) {
private void removingMetadataForSuperOrigin(ItemDelta<PrismValue, ItemDefinition<?>> delta) {
removingMetadataFromValues(delta.getValuesToAdd());
removingMetadataFromValues(delta.getValuesToReplace());
removingMetadataFromValues(delta.getValuesToDelete());
Expand All @@ -295,7 +295,7 @@ private void removingMetadataFromValues(Collection<PrismValue> values) {

private void removingMetadataForSuperOrigin(PrismObject<ResourceType> clone) {
clone.getDefinition().getDefinitions().forEach(def -> {
Item<PrismValue, ItemDefinition> item = clone.findItem(def.getItemName());
Item<?, ?> item = clone.findItem(def.getItemName());
removingMetadataForSuperOrigin(item);
if (item != null && item.isEmpty()) {
clone.remove(item);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public static ItemDefinition<?> deriveOutputDefinitionFromValueElements(QName el
return prismContext.getSchemaRegistry().createAdHocDefinition(elementName, overallType, 0, maxOccurs);
}

public static <IV extends PrismValue, ID extends ItemDefinition> Item<IV, ID> parseValueElements(
public static <IV extends PrismValue, ID extends ItemDefinition<?>> Item<IV, ID> parseValueElements(
Collection<?> valueElements, ID outputDefinition, String contextDescription) throws SchemaException {
Item<IV, ID> output = null;
for (Object valueElement : valueElements) {
Expand Down Expand Up @@ -156,7 +156,7 @@ private static RawType getRawType(Object valueElement, String contextDescription
return (RawType) jaxbElement.getValue();
}

public static <IV extends PrismValue, ID extends ItemDefinition> List<JAXBElement<RawType>> serializeValueElements(Item<IV, ID> item) throws SchemaException {
public static <IV extends PrismValue, ID extends ItemDefinition<?>> List<JAXBElement<RawType>> serializeValueElements(Item<IV, ID> item) throws SchemaException {
if (item == null) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ public String toString() {

@NotNull
public ResourceObjectIdentityType asBean() throws SchemaException {
ResourceObjectIdentityType bean = new ResourceObjectIdentityType(PrismContext.get());
ResourceObjectIdentityType bean = new ResourceObjectIdentityType();
if (resourceObjectDefinition != null) {
bean.setObjectClass(resourceObjectDefinition.getTypeName());
}
Expand All @@ -189,7 +189,7 @@ private ResourceObjectIdentifiersType getIdentifiersAsBean(Collection<? extends
if (identifiers.isEmpty()) {
return null;
}
ResourceObjectIdentifiersType identifiersBean = new ResourceObjectIdentifiersType(PrismContext.get());
ResourceObjectIdentifiersType identifiersBean = new ResourceObjectIdentifiersType();
for (ResourceAttribute<?> identifier : identifiers) {
//noinspection unchecked
identifiersBean.asPrismContainerValue().add(identifier.clone());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -875,7 +875,7 @@ public static <O extends ObjectType> XMLGregorianCalendar getLastTouchTimestamp(
PrismContext prismContext) throws SchemaException {
List<Item<?, ?>> extensionItems = new ArrayList<>();
for (Map.Entry<QName, Object> entry : values.entrySet()) {
ItemDefinition<Item<PrismValue, ItemDefinition>> def = extensionDefinition != null
ItemDefinition<Item<PrismValue, ItemDefinition<?>>> def = extensionDefinition != null
? extensionDefinition.findItemDefinition(ItemName.fromQName(entry.getKey()))
: null;
if (def == null) {
Expand All @@ -885,7 +885,7 @@ public static <O extends ObjectType> XMLGregorianCalendar getLastTouchTimestamp(
throw new SchemaException("No definition of " + entry.getKey() + " in the extension");
}
}
Item<PrismValue, ItemDefinition> extensionItem = def.instantiate();
Item<PrismValue, ItemDefinition<?>> extensionItem = def.instantiate();
if (entry.getValue() != null) {
if (entry.getValue() instanceof Collection) {
for (Object value : (Collection) entry.getValue()) {
Expand All @@ -900,7 +900,7 @@ public static <O extends ObjectType> XMLGregorianCalendar getLastTouchTimestamp(
return extensionItems;
}

private static void addRealValue(Item<PrismValue, ItemDefinition> extensionItem, Object value,
private static void addRealValue(Item<PrismValue, ItemDefinition<?>> extensionItem, Object value,
PrismContext prismContext) throws SchemaException {
if (value != null) {
extensionItem.add(prismContext.itemFactory().createValue(value).clone());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,25 @@ public static ReportParameterType createParameters(@NotNull String paramName, @N
return parameters;
}

public static ReportParameterType createParameters(List<String> names, List<Object> realValues) throws SchemaException {
ReportParameterType parameters = new ReportParameterType();
public static void addParameters(ReportParameterType parameters, List<String> names, List<Object> realValues)
throws SchemaException {
argCheck(
names.size() == realValues.size(),
"Parameter names and values do not match: %s vs %s", names, realValues);
for (int i = 0; i < names.size(); i++) {
addParameter(parameters, names.get(i), realValues.get(i));
}
return parameters;
}

private static void addParameter(
@NotNull ReportParameterType parameters, @NotNull String paramName, @Nullable Object realValue)
public static void addParameter(
@NotNull ReportParameterType parameters, @NotNull String paramName, Object... realValues)
throws SchemaException {
if (realValue == null) {
if (realValues.length == 0) {
return;
}

QName typeName = PrismContext.get().getSchemaRegistry().determineTypeForClass(realValue.getClass());
Object firstValue = realValues[0];
QName typeName = PrismContext.get().getSchemaRegistry().determineTypeForClass(firstValue.getClass());
MutablePrismPropertyDefinition<Object> paramPropDef =
PrismContext.get().definitionFactory().createPropertyDefinition(
new QName(SchemaConstants.NS_REPORT_EXTENSION, paramName), typeName);
Expand All @@ -59,7 +59,7 @@ private static void addParameter(
paramPropDef.toMutable().setMaxOccurs(1);

PrismProperty<Object> paramProperty = paramPropDef.instantiate();
paramProperty.addRealValue(realValue);
paramProperty.addRealValues(realValues);
//noinspection unchecked
((PrismContainerValue<ReportParameterType>) parameters.asPrismContainerValue()).add(paramProperty);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright (C) 2010-2023 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.schema.util.delta;

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

import org.jetbrains.annotations.NotNull;

import com.evolveum.midpoint.prism.delta.ItemDelta;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.path.PathSet;
import com.evolveum.prism.xml.ns._public.types_3.ItemPathType;

/**
* Filters item deltas according to specified criteria.
*
* Currently in `schema` module (not in `prism` one), because I am not sure if it will be midPoint-specific or not.
*/
public class ItemDeltaFilter {

@NotNull private final PathSet pathsToInclude = new PathSet();
@NotNull private final PathSet pathsToExclude = new PathSet();
private boolean includeOperationalItems = false;

public static ItemDeltaFilter create(Object pathsToInclude, Object pathsToExclude, Boolean includeOperationalItems) {
ItemDeltaFilter filter = new ItemDeltaFilter();
filter.pathsToInclude.addAll(toPaths(pathsToInclude));
filter.pathsToExclude.addAll(toPaths(pathsToExclude));
if (includeOperationalItems != null) {
filter.includeOperationalItems = includeOperationalItems;
}
return filter;
}

private static Collection<? extends ItemPath> toPaths(Object object) {
if (object == null) {
return List.of();
} else if (object instanceof Collection) {
return ((Collection<?>) object).stream()
.map(o -> toPath(o))
.collect(Collectors.toList());
} else {
return List.of(toPath(object));
}
}

private static ItemPath toPath(Object object) {
if (object instanceof ItemPath) {
return (ItemPath) object;
} else if (object instanceof ItemPathType) {
return ((ItemPathType) object).getItemPath();
} else if (object instanceof String) {
return ItemPath.fromString((String) object);
} else {
throw new IllegalArgumentException("Not a path: " + object);
}
}

/**
* TODO describe the algorithm
*/
public boolean matches(ItemDelta<?, ?> itemDelta) {
ItemPath path = itemDelta.getPath().namedSegmentsOnly();
Boolean match = getExactMatch(path);
if (match != null) {
return match; // Ignoring "operational" flag for exact match
}
if (itemDelta.isOperational() && !includeOperationalItems) {
return false;
}
ItemPath reduced = path.allExceptLast();
for (;;) {
Boolean matchReduced = getExactMatch(reduced);
if (matchReduced != null) {
return matchReduced;
}
if (reduced.isEmpty()) {
// If we specified anything to include, the the default is assumed to be "NOT INCLUDED".
return pathsToInclude.isEmpty();
}
reduced = reduced.allExceptLast();
}
}

private Boolean getExactMatch(ItemPath path) {
if (pathsToInclude.contains(path)) {
return true;
} else if (pathsToExclude.contains(path)) {
return false;
} else {
return null;
}
}
}

0 comments on commit 2dfc624

Please sign in to comment.