Skip to content

Commit

Permalink
Unify types for attributes and associations
Browse files Browse the repository at this point in the history
To avoid massive code duplication, (experimental) ShadowItemXXX types
were introduced: ShadowItem, ShadowItemDefinition, ShadowItemsContainer.
Hopefully they will be useful.

Currently, it seems they cannot naturally inherit from (e.g.) Item,
because there is a lot of conflicts on specific methods.
  • Loading branch information
mederly committed Mar 11, 2024
1 parent e2a8f1f commit 9239a14
Show file tree
Hide file tree
Showing 15 changed files with 204 additions and 112 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,18 @@

import static com.evolveum.midpoint.util.MiscUtil.stateCheck;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.delta.PropertyDelta;

import com.evolveum.midpoint.prism.util.CloneUtil;

import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowAttributesType;

import org.jetbrains.annotations.NotNull;

import com.evolveum.midpoint.prism.Item;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.prism.PrismProperty;
import com.evolveum.midpoint.prism.PrismPropertyValue;
import com.evolveum.midpoint.prism.delta.PropertyDelta;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.query.ObjectFilter;
import com.evolveum.midpoint.prism.util.CloneUtil;
import com.evolveum.midpoint.util.MiscUtil;
import com.evolveum.midpoint.util.QNameUtil;
import com.evolveum.midpoint.util.exception.SchemaException;
Expand All @@ -47,7 +44,8 @@
*
* @author Radovan Semancik
*/
public interface ResourceAttribute<T> extends PrismProperty<T> {
public interface ResourceAttribute<T>
extends ShadowItem<PrismPropertyValue<T>, T>, PrismProperty<T> {

/** Converts the {@link PrismProperty} into {@link ResourceAttribute}, if needed. */
static <T> ResourceAttribute<T> of(@NotNull Item<?, ?> item) {
Expand Down Expand Up @@ -165,7 +163,7 @@ void addNormalizedValues(@NotNull Collection<?> realValues, @NotNull ResourceAtt
* Creates normalization-aware "eq" filter (i.e., suitable for the execution against the repository) for the current
* value of this attribute. It must have a definition and exactly one value.
*/
default <N> @NotNull ObjectFilter normalizationAwareEqFilter() throws SchemaException {
default @NotNull ObjectFilter normalizationAwareEqFilter() throws SchemaException {
var normAwareDef = getDefinitionRequired().toNormalizationAware();
var normAwareRealValue = MiscUtil.extractSingletonRequired(normAwareDef.adoptRealValues(getRealValues()));
return PrismContext.get().queryFor(ShadowType.class)
Expand Down Expand Up @@ -205,4 +203,9 @@ default void checkDefinitionConsistence(@NotNull ResourceObjectDefinition object
"Definition of %s is %s, expected %s",
this, actualDefinition, expectedDefinition);
}

@Override
default boolean hasNoValues() {
return PrismProperty.super.hasNoValues();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
* TODO
*/
@SuppressWarnings("rawtypes")
public interface ResourceAttributeContainer extends PrismContainer<ShadowAttributesType> {
public interface ResourceAttributeContainer extends ShadowItemsContainer, PrismContainer<ShadowAttributesType> {

static ResourceAttributeContainer convertFromPrismContainer(
@NotNull PrismContainer<?> origPrismContainer, @NotNull ResourceObjectDefinition resourceObjectDefinition) throws SchemaException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@
* @see ResourceAttribute
*/
public interface ResourceAttributeDefinition<T>
extends ResourceItemUcfDefinition, PrismPropertyDefinition<T>, LayeredDefinition {
extends ShadowItemDefinition<ResourceAttribute<T>>,
ResourceItemUcfDefinition,
PrismPropertyDefinition<T>,
LayeredDefinition {

/**
* Returns limitations (cardinality, access rights, processing) for given layer.
Expand Down Expand Up @@ -232,7 +235,6 @@ default boolean isEffectivelyCached(@NotNull ResourceObjectDefinition objectDefi
return PrismUtil.convertPropertyValue(srcValue, this);
}

@Override
@NotNull ResourceAttributeDefinition<T> clone();

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,4 +220,9 @@ public void checkConsistenceInternal(
}
}
}

@Override
public void addValueSkipUniquenessCheck(PrismPropertyValue<T> value) throws SchemaException {
addIgnoringEquivalents(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -590,4 +590,23 @@ default void assertAttached() {
return CompositeObjectDefinition.of(this, auxiliaryDefinitions);
}
}

/** TODO ... ignoreCase will be part of the schema, soon ... */
default ShadowItemDefinition<?> findShadowItemDefinitionRequired(
@NotNull ItemName itemName, boolean ignoreCase, Object errorCtx) throws SchemaException {

var attributeDefinition = findAttributeDefinition(itemName, ignoreCase);
var associationDefinition = findAssociationDefinition(itemName);

stateCheck(attributeDefinition == null || associationDefinition == null,
"'%s' is both an attribute and an association in '%s' (should be checked already)",
itemName, this);
if (attributeDefinition != null) {
return attributeDefinition;
} else if (associationDefinition != null) {
return associationDefinition;
} else {
throw new SchemaException("Unknown attribute/association '%s' in '%s'; %s".formatted(itemName, this, errorCtx));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@
* Contained in {@link ShadowAssociationsContainer}.
*/
@Experimental
public class ShadowAssociation extends PrismContainerImpl<ShadowAssociationValueType> {
public class ShadowAssociation
extends PrismContainerImpl<ShadowAssociationValueType>
implements ShadowItem<ShadowAssociationValue, ShadowAssociationValueType> {

@Serial private static final long serialVersionUID = 0L;

Expand All @@ -52,6 +54,11 @@ public ShadowAssociationDefinition getDefinition() {
getDefinition(), "No definition in %s", this);
}

@Override
public ShadowAssociation clone() {
return (ShadowAssociation) super.clone();
}

@Override
public ShadowAssociation cloneComplex(CloneStrategy strategy) {
ShadowAssociation clone = new ShadowAssociation(getElementName(), getDefinition());
Expand Down Expand Up @@ -153,4 +160,13 @@ protected String getDebugDumpClassName() {
return Collections.unmodifiableList(
(List<? extends ShadowAssociationValue>) (List) getValues());
}

@Override
public void addValueSkipUniquenessCheck(ShadowAssociationValue value) throws SchemaException {
addIgnoringEquivalents(value);
}

public boolean hasNoValues() {
return getValues().isEmpty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
public class ShadowAssociationDefinition extends AbstractFreezable
implements Serializable, Visitable<Definition>, Freezable, DebugDumpable,
PrismContainerDefinition<ShadowAssociationValueType>,
ShadowItemDefinition<ShadowAssociation>,
MutablePrismContainerDefinition.Unsupported<ShadowAssociationValueType> {

@Serial private static final long serialVersionUID = 1L;
Expand Down Expand Up @@ -491,7 +492,7 @@ public boolean canRepresent(@NotNull QName type) {
}

@Override
public ShadowAssociationDefinition toMutable() {
public @NotNull ShadowAssociationDefinition toMutable() {
checkMutableOnExposing();
return this;
}
Expand All @@ -502,7 +503,7 @@ public Class<ShadowAssociationValueType> getTypeClass() {
}

@Override
public ItemDefinition<PrismContainer<ShadowAssociationValueType>> deepClone(@NotNull DeepCloneOperation operation) {
public ShadowAssociationDefinition deepClone(@NotNull DeepCloneOperation operation) {
return this; // TODO ???
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
*
* @see ResourceAttributeContainer
*/
public interface ShadowAssociationsContainer extends PrismContainer<ShadowAssociationsType> {
public interface ShadowAssociationsContainer extends ShadowItemsContainer, PrismContainer<ShadowAssociationsType> {

static ShadowAssociationsContainer convertFromPrismContainer(
@NotNull PrismContainer<?> origPrismContainer, @NotNull ResourceObjectDefinition resourceObjectDefinition)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@
import java.util.List;
import javax.xml.namespace.QName;

import com.evolveum.midpoint.prism.ComplexTypeDefinition;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowAssociationsType;

import org.jetbrains.annotations.NotNull;

import com.evolveum.midpoint.prism.ComplexTypeDefinition;
import com.evolveum.midpoint.prism.PrismContainerDefinition;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowAssociationsType;

/**
* Definition of a {@link ShadowAssociationsContainer}.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* 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.schema.processor;

import com.evolveum.midpoint.prism.Item;
import com.evolveum.midpoint.prism.PrismValue;
import com.evolveum.midpoint.util.annotation.Experimental;
import com.evolveum.midpoint.util.exception.SchemaException;

/**
* Access to both {@link ResourceAttribute} and {@link ShadowAssociation}.
*
* Currently, it cannot extend {@link Item} because of the clash on many methods, like {@link Item#getValue()}.
* (To be researched further.)
*/
@Experimental
public interface ShadowItem<PV, RV> {

ShadowItem<PV, RV> clone();

void setIncomplete(boolean incomplete);

boolean isIncomplete();

boolean hasNoValues();

void addValueSkipUniquenessCheck(PV value) throws SchemaException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* 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.schema.processor;

import org.jetbrains.annotations.NotNull;

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

/**
* Access to both {@link ResourceAttributeDefinition} and {@link ShadowAssociationDefinition}.
* For the time being, it does not extend {@link ItemDefinition} because of typing complications.
*/
public interface ShadowItemDefinition<I extends ShadowItem> {

@NotNull I instantiate() throws SchemaException;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* 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.schema.processor;

/** Supertype for {@link ResourceAttributeContainer} and {@link ShadowAssociationsContainer}. */
public interface ShadowItemsContainer {

ShadowItemsContainer clone();
}
Original file line number Diff line number Diff line change
Expand Up @@ -1169,4 +1169,18 @@ public static ShadowAssociation getAssociation(PrismObject<ShadowType> shadow, Q
public static void addAttribute(ShadowType shadow, ResourceAttribute<?> attribute) throws SchemaException {
getOrCreateAttributesContainer(shadow).add(attribute);
}

public static void addAssociation(ShadowType shadow, ShadowAssociation association) throws SchemaException {
getOrCreateAssociationsContainer(shadow).add(association);
}

public static void addShadowItem(ShadowType shadow, ShadowItem item) throws SchemaException {
if (item instanceof ResourceAttribute<?> attribute) {
addAttribute(shadow, attribute);
} else if (item instanceof ShadowAssociation association) {
addAssociation(shadow, association);
} else {
throw new IllegalArgumentException("Neither attribute nor association: " + item);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class ConnIdObjectConvertor {
if (ucfErrorReportingMethod == UcfFetchErrorReportingMethod.UCF_OBJECT) {
Throwable wrappedException = MiscUtil.createSame(t, createMessage(co, t));
result.recordException(wrappedException);
return conversion.getPartialUcfResourceObject(UcfErrorState.error(wrappedException));
return conversion.getPartiallyConvertedUcfResourceObject(wrappedException);
} else {
throw t; // handled just below
}
Expand Down

0 comments on commit 9239a14

Please sign in to comment.