Skip to content

Commit

Permalink
Support new associations
Browse files Browse the repository at this point in the history
Fixed story tests (hopefully). Work in progress.
  • Loading branch information
mederly committed Feb 24, 2024
1 parent 3d55f66 commit 76441ee
Show file tree
Hide file tree
Showing 13 changed files with 62 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ public static PrismObjectDefinition<ShadowType> constructObjectDefinition(
PrismObjectDefinition<ShadowType> shadowDefinition =
PrismContext.get().getSchemaRegistry().findObjectDefinitionByCompileTimeClass(ShadowType.class);
// FIXME eliminate double cloning!
var clone1 = shadowDefinition.cloneWithReplacedDefinition(ShadowType.F_ATTRIBUTES, rACD);
return clone1.cloneWithReplacedDefinition(ShadowType.F_ASSOCIATIONS, rAsCD);
return shadowDefinition
.cloneWithReplacedDefinition(ShadowType.F_ATTRIBUTES, rACD)
.cloneWithReplacedDefinition(ShadowType.F_ASSOCIATIONS, rAsCD);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,4 @@ public interface ResourceAttributeContainerDefinition extends PrismContainerDefi
@Override
@NotNull
List<? extends ResourceAttributeDefinition<?>> getDefinitions();

@NotNull <T extends ShadowType> PrismObjectDefinition<T> toShadowDefinition();
}
Original file line number Diff line number Diff line change
Expand Up @@ -207,14 +207,6 @@ public List<? extends ResourceAttributeDefinition<?>> getAttributeDefinitions()
return attrs;
}

@Override
public @NotNull <T extends ShadowType> PrismObjectDefinition<T> toShadowDefinition() {
//noinspection unchecked
PrismObjectDefinition<T> origShadowDef = (PrismObjectDefinition<T>) getPrismContext().getSchemaRegistry().
findObjectDefinitionByCompileTimeClass(ShadowType.class);
return origShadowDef.cloneWithReplacedDefinition(ShadowType.F_ATTRIBUTES, this);
}

@Override
public String debugDump(int indent) {
StringBuilder sb = new StringBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,13 @@ public void applyTo(@NotNull ShadowType bean) throws SchemaException {
boolean wrongAssocDef = !(origAssocContainerDef instanceof ShadowAssociationsContainerDefinition);

if (wrongAttrDef || wrongAssocDef) {
PrismObjectDefinition<ShadowType> clonedDefinition =
prismShadowDefinition.cloneWithReplacedDefinition(
ShadowType.F_ATTRIBUTES, definition.toResourceAttributeContainerDefinition());
// FIXME eliminate double cloning!
var clonedDefinition =
prismShadowDefinition
.cloneWithReplacedDefinition(
ShadowType.F_ATTRIBUTES, definition.toResourceAttributeContainerDefinition())
.cloneWithReplacedDefinition(
ShadowType.F_ASSOCIATIONS, definition.toResourceAssociationContainerDefinition());
shadowObject.setDefinition(clonedDefinition);
clonedDefinition.freeze();
}
Expand Down Expand Up @@ -214,7 +218,7 @@ public void applyToAssociationIdentifiers(ShadowType shadow) throws SchemaExcept
* The container can be a shadow or "identifiers" container for an association value.
* The definition can be the object definition or the association target (entitlement) definition.
*/
private void applyAttributesDefinitionToContainer(
private static void applyAttributesDefinitionToContainer(
@NotNull ResourceObjectDefinition objectDefinition,
@NotNull PrismContainer<ShadowAttributesType> attributesContainer,
@NotNull PrismContainerValue<?> parentPcv,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,6 @@ default List<? extends ResourceAttributeDefinition<?>> getAttributeDefinitions()
return delegate().getAttributeDefinitions();
}

@Override
default <T extends ShadowType> @NotNull PrismObjectDefinition<T> toShadowDefinition() {
return delegate().toShadowDefinition();
}

@Override
default @NotNull ResourceAttributeContainer instantiate() {
return delegate().instantiate();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public static ResourceAttributeContainer getAttributesContainer(ShadowType shado
}

public static ResourceAttributeContainer getAttributesContainer(PrismObject<? extends ShadowType> shadow) {
return getAttributesContainer(shadow, ShadowType.F_ATTRIBUTES);
return castShadowContainer(shadow.getValue(), ShadowType.F_ATTRIBUTES, ResourceAttributeContainer.class);
}

/** Similar to {@link #getAttributesContainer(ShadowType)}. */
Expand All @@ -148,40 +148,32 @@ public static ShadowAssociationsContainer getAssociationsContainer(@NotNull Shad

/** Similar to {@link #getAttributesContainer(ShadowType)}. */
public static ShadowAssociationsContainer getAssociationsContainer(@NotNull PrismObject<ShadowType> shadow) {
PrismContainer<?> associationsContainer = shadow.findContainer(ShadowType.F_ASSOCIATIONS);
if (associationsContainer == null) {
return castShadowContainer(
shadow.asObjectable().asPrismContainerValue(), ShadowType.F_ASSOCIATIONS, ShadowAssociationsContainer.class);
}

private static <T> T castShadowContainer(
@NotNull PrismContainerValue<?> parent, QName containerName, Class<T> expectedClass) {
PrismContainer<?> container = parent.findContainer(containerName);
if (container == null) {
return null;
} else if (associationsContainer instanceof ShadowAssociationsContainer shadowAssociationsContainer) {
return shadowAssociationsContainer;
} else if (expectedClass.isInstance(container)) {
//noinspection unchecked
return (T) container;
} else {
throw new IllegalStateException(
"Expected that <%s> will be ResourceAttributeContainer but it is %s; in %s".formatted(
ShadowType.F_ASSOCIATIONS, associationsContainer.getClass(), shadow));
"Expected that <%s> will be %s but it is %s; in %s".formatted(
containerName, expectedClass.getSimpleName(), container.getClass(), parent));
}
}


public static ResourceAttributeContainer getAttributesContainer(PrismObject<? extends ShadowType> shadow, QName containerName) {
return getAttributesContainer(shadow.getValue(), containerName);
}

public static boolean isAttributesContainerRaw(ShadowType shadow) {
PrismContainer<ShadowAttributesType> container = shadow.asPrismObject().findContainer(ShadowType.F_ATTRIBUTES);
return container != null && !(container instanceof ResourceAttributeContainer);
}

public static ResourceAttributeContainer getAttributesContainer(PrismContainerValue<?> cval, QName containerName) {
PrismContainer<?> attributesContainer = cval.findContainer(containerName);
if (attributesContainer == null) {
return null;
}
if (attributesContainer instanceof ResourceAttributeContainer resourceAttributeContainer) {
return resourceAttributeContainer;
} else {
throw new IllegalStateException(
"Expected that <%s> will be ResourceAttributeContainer but it is %s".formatted(
containerName.getLocalPart(), attributesContainer.getClass()));
}
public static ResourceAttributeContainer getIdentifiersContainer(PrismContainerValue<ShadowAssociationValueType> cval) {
return castShadowContainer(cval, ShadowAssociationValueType.F_IDENTIFIERS, ResourceAttributeContainer.class);
}

/** Assuming the shadow has the correct definition. */
Expand Down Expand Up @@ -377,9 +369,11 @@ private static void applyObjectDefinition(PrismObject<? extends ShadowType> shad
public static PrismObjectDefinition<ShadowType> applyObjectDefinition(
PrismObjectDefinition<ShadowType> shadowDefinition,
ResourceObjectDefinition objectClassDefinition) throws SchemaException {
// FIXME eliminate double cloning!
return shadowDefinition.cloneWithReplacedDefinition(
ShadowType.F_ATTRIBUTES,
objectClassDefinition.toResourceAttributeContainerDefinition());
ShadowType.F_ATTRIBUTES, objectClassDefinition.toResourceAttributeContainerDefinition())
.cloneWithReplacedDefinition(
ShadowType.F_ASSOCIATIONS, objectClassDefinition.toResourceAssociationContainerDefinition());
}

public static String getIntent(PrismObject<ShadowType> shadow) {
Expand Down Expand Up @@ -1037,7 +1031,7 @@ public static boolean isNonAttributeResourceModification(QName firstPathName) {
public static @NotNull ResourceAttributeContainer getIdentifiersContainerRequired(
@NotNull PrismContainerValue<ShadowAssociationValueType> associationValue) throws SchemaException {
return MiscUtil.requireNonNull(
getAttributesContainer(associationValue, ShadowAssociationValueType.F_IDENTIFIERS),
getIdentifiersContainer(associationValue),
() -> "No identifiers in " + associationValue);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ public class IvwoConsolidator<V extends PrismValue, D extends ItemDefinition<?>,
private final boolean itemDeltaExists;

/**
* Comparator used to compare values. Used if valueMatcher is null or cannot be used (because item is not a property).
* Comparator used to compare values.
* It should be forgivable enough to allow illegal values to be compared.
*/
private final EqualsChecker<V> equalsChecker;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ public boolean test(PrismPropertyValue<T> v1, PrismPropertyValue<T> v2) {
try {
return match(v1.getRealValue(), v2.getRealValue());
} catch (SchemaException e) {
throw new SystemException(e); // FIXME
// We do not want to throw exception from a comparison operation. That would make the system very fragile.
LOGGER.warn("Couldn't match values: {} and {}: {}", v1, v2, e.getMessage(), e);
return v1.equals(v2);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -743,10 +743,9 @@ private ResourceAttributeContainer getIdentifiersForAssociationTarget(
Task task, OperationResult result) throws CommunicationException,
SchemaException, ConfigurationException,
SecurityViolationException, ObjectNotFoundException, ExpressionEvaluationException {
ResourceAttributeContainer identifiersContainer =
ShadowUtil.getAttributesContainer(isCValue, ShadowAssociationValueType.F_IDENTIFIERS);
if (identifiersContainer != null) {
return identifiersContainer;
var identifiersInAssociation = ShadowUtil.getIdentifiersContainer(isCValue);
if (identifiersInAssociation != null) {
return identifiersInAssociation;
}
String oid = isCValue.asContainerable().getShadowRef() != null ? isCValue.asContainerable().getShadowRef().getOid() : null;
if (oid == null) {
Expand All @@ -767,13 +766,14 @@ private ResourceAttributeContainer getIdentifiersForAssociationTarget(
throw e.wrap("Couldn't evaluate tolerant/intolerant values for association " + isCValue
+ ", because the association target object does not exist");
}
identifiersContainer = ShadowUtil.getAttributesContainer(target);
if (identifiersContainer == null) {
// TODO maybe warn/error log would suffice?
throw new IllegalStateException("Couldn't evaluate tolerant/intolerant values for association " + isCValue
+ ", because there are no identifiers present, even in the repository object for association target");
var identifiersInTarget = ShadowUtil.getAttributesContainer(target);
if (identifiersInTarget != null) {
return identifiersInTarget;
}
return identifiersContainer;

// TODO maybe warn/error log would suffice?
throw new IllegalStateException("Couldn't evaluate tolerant/intolerant values for association " + isCValue
+ ", because there are no identifiers present, even in the repository object for association target");
}

private <T> void recordDelta(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import javax.xml.datatype.Duration;
import javax.xml.datatype.XMLGregorianCalendar;

import com.evolveum.midpoint.prism.util.CloneUtil;
import com.evolveum.midpoint.schema.processor.ShadowDefinitionApplicator;

import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -138,19 +139,22 @@ private ResourceObjectFuturizer(
ObjectDelta<ShadowType> pendingDelta = DeltaConvertor.createObjectDelta(pendingOperation.getDelta());
shadowDefinitionApplicator.applyTo(pendingDelta);
if (pendingDelta.isAdd()) {
if (originalResourceObject == null) {
// In case that we have resourceShadow then we need to ignore the ADD operation.
// In that case the object was obviously already created. The data that we have from the
// resource are going to be more precise than the pending ADD delta (which might not have been applied completely)
if (originalResourceObject != null) {
// If we have the resource object, we need to ignore the ADD operation.
// In that case the object was obviously already created. The data that we have from the resource
// are going to be more precise than the pending ADD delta (which might not have been applied completely).
} else {
// But if we have no resource object, we need to take the data from the ADD operation.
ShadowType newBean = pendingDelta.getObjectToAdd().clone().asObjectable();
newBean.setOid(repoShadow.getOid());
newBean.setName(repoShadow.getName());
newBean.setShadowLifecycleState(repoShadow.getShadowLifecycleState());
List<PendingOperationType> newPendingOperations = newBean.getPendingOperation();
for (PendingOperationType pendingOperation2 : repoShadow.getBean().getPendingOperation()) {
newPendingOperations.add(pendingOperation2.clone());
}
shadowCtx.applyDefinitionInNewCtx(newBean);
// Here we transfer pending operations from repo shadow to the new bean, so that they will be returned
// to the caller as part of that object.
newBean.getPendingOperation().addAll(
CloneUtil.cloneCollectionMembers(
repoShadow.getBean().getPendingOperation()));
shadowCtx.applyDefinition(newBean);
currentResourceObject = ResourceObject.fromBean(newBean, true, shadowCtx.getObjectDefinitionRequired());
// We also ignore the fact that there may be multiple pending ADD operations. We just take the last one.
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -440,8 +440,8 @@ private void invokeErrorHandler(Exception cause, OperationResult failedOpResult,
*/
private @NotNull Shadow returnCached(String reason) throws SchemaException, ConfigurationException {
LOGGER.trace("Returning cached (repository) version of shadow {} because of: {}", repoShadow, reason);
ctx.applyDefinition(repoShadow.getBean());
var futurized = futurizeRepoShadow(ctx, repoShadow, false, options, now);
ctx.applyDefinitionInNewCtx(futurized.getBean());
LOGGER.trace("Futurized shadow:\n{}", DebugUtil.debugDumpLazily(futurized));
return createShadow(ctx, futurized);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1374,7 +1374,7 @@ public void test260OutboundUsernamesWrong() throws CommonException, IOException
then("the operation should result in failure");
display("result", result1);
assertThatOperationResult(result1)
.isPartialError()
.isFatalError() // partial error would be OK as well
.hasMessageContaining("String 'jsmith1' is not a DN");

and("there should be no processed objects");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,6 @@ public void test102AssignRoleStats() throws Exception{

OperationResult result = task.getResult();


assumeAssignmentPolicy(AssignmentPolicyEnforcementType.RELATIVE);
openDJController.stop();

Expand Down

0 comments on commit 76441ee

Please sign in to comment.