Skip to content

Commit

Permalink
Assignment deletion approval.
Browse files Browse the repository at this point in the history
  • Loading branch information
mederly committed Jan 30, 2017
1 parent ace8b04 commit 5dcc330
Show file tree
Hide file tree
Showing 15 changed files with 537 additions and 117 deletions.
Expand Up @@ -426,6 +426,7 @@ public boolean remove(V newValue) {
Iterator<V> iterator = values.iterator();
while (iterator.hasNext()) {
V val = iterator.next();
// the same algorithm as when deleting the item value from delete delta
if (val.representsSameValue(newValue, false) || val.equalsRealValue(newValue)) {
iterator.remove();
changed = true;
Expand Down
Expand Up @@ -335,26 +335,27 @@ public void addValueToAdd(V newValue) {
}

public boolean removeValueToAdd(PrismValue valueToRemove) {
return removeValue(valueToRemove, valuesToAdd);
return removeValue(valueToRemove, valuesToAdd, false);
}

public boolean removeValueToDelete(PrismValue valueToRemove) {
return removeValue(valueToRemove, valuesToDelete);
return removeValue(valueToRemove, valuesToDelete, true);
}

public boolean removeValueToReplace(PrismValue valueToRemove) {
return removeValue(valueToRemove, valuesToReplace);
return removeValue(valueToRemove, valuesToReplace, false);
}

private boolean removeValue(PrismValue valueToRemove, Collection<V> set) {
private boolean removeValue(PrismValue valueToRemove, Collection<V> set, boolean toDelete) {
boolean removed = false;
if (set == null) {
return removed;
return false;
}
Iterator<V> valuesIterator = set.iterator();
while (valuesIterator.hasNext()) {
V valueToReplace = valuesIterator.next();
if (valueToReplace.equalsRealValue(valueToRemove)) {
V existingValue = valuesIterator.next();
if (existingValue.equalsRealValue(valueToRemove)
|| toDelete && existingValue.representsSameValue(valueToRemove, false)) { // the same algorithm as when deleting the item value
valuesIterator.remove();
removed = true;
}
Expand Down Expand Up @@ -1574,11 +1575,11 @@ public boolean equivalent(ItemDelta other) {
return false;
} else if (!parentPath.equivalent(other.parentPath))
return false;
if (!equivalentSetRealValue(this.valuesToAdd, other.valuesToAdd))
if (!equivalentSetRealValue(this.valuesToAdd, other.valuesToAdd, false))
return false;
if (!equivalentSetRealValue(this.valuesToDelete, other.valuesToDelete))
if (!equivalentSetRealValue(this.valuesToDelete, other.valuesToDelete, true))
return false;
if (!equivalentSetRealValue(this.valuesToReplace, other.valuesToReplace))
if (!equivalentSetRealValue(this.valuesToReplace, other.valuesToReplace, false))
return false;
return true;
}
Expand Down Expand Up @@ -1616,30 +1617,46 @@ public boolean equals(Object obj) {
return false;
} else if (!parentPath.equivalent(other.parentPath)) // or "equals" ?
return false;
if (!equivalentSetRealValue(this.valuesToAdd, other.valuesToAdd))
if (!equivalentSetRealValue(this.valuesToAdd, other.valuesToAdd, false))
return false;
if (!equivalentSetRealValue(this.valuesToDelete, other.valuesToDelete))
if (!equivalentSetRealValue(this.valuesToDelete, other.valuesToDelete, true)) // TODO ok?
return false;
if (!equivalentSetRealValue(this.valuesToReplace, other.valuesToReplace))
if (!equivalentSetRealValue(this.valuesToReplace, other.valuesToReplace, false))
return false;
if (!equivalentSetRealValue(this.estimatedOldValues, other.estimatedOldValues))
if (!equivalentSetRealValue(this.estimatedOldValues, other.estimatedOldValues, false))
return false;
return true;
}

private boolean equivalentSetRealValue(Collection<V> thisValue, Collection<V> otherValues) {
private boolean equivalentSetRealValue(Collection<V> thisValue, Collection<V> otherValues, boolean isDelete) {
return MiscUtil.unorderedCollectionEquals(thisValue, otherValues,
(o1,o2) -> {
if (o1 instanceof PrismValue && o2 instanceof PrismValue) {
PrismValue v1 = (PrismValue)o1;
PrismValue v2 = (PrismValue)o2;
return v1.equalsRealValue(v2);
(v1, v2) -> {
if (v1 != null && v2 != null) {
if (!isDelete || !(v1 instanceof PrismContainerValue) || !(v2 instanceof PrismContainerValue)) {
// Here it is questionable if we should consider adding "assignment id=1 (A)" and "assignment id=2 (A)"
// - i.e. assignments with the same real value but different identifiers - the same delta.
// Historically, we considered it as such. But the question is if it's correct.
return v1.equalsRealValue(v2);
} else {
// But for container values to be deleted, they can be referred to either using IDs or values.
// If content is used - but no IDs - the content must be equal.
// If IDs are used - and are the same - the content is irrelevant.
// The problem is if one side has content with ID, and the other has the same content without ID.
// This might have the same or different effect, depending on the content it is applied to.
return (v1.equalsRealValue(v2) && !differentIds(v1, v2)) || v1.representsSameValue(v2, false);
}
} else {
return false;
}
});
}

private boolean differentIds(PrismValue v1, PrismValue v2) {
Long id1 = v1 instanceof PrismContainerValue ? ((PrismContainerValue) v1).getId() : null;
Long id2 = v2 instanceof PrismContainerValue ? ((PrismContainerValue) v2).getId() : null;
return id1 != null && id2 != null && id1.longValue() != id2.longValue();
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
Expand Down
Expand Up @@ -29,7 +29,6 @@
import com.evolveum.prism.xml.ns._public.types_3.ChangeTypeType;
import com.evolveum.prism.xml.ns._public.types_3.ItemDeltaType;
import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType;
import com.evolveum.prism.xml.ns._public.types_3.ObjectReferenceType;

import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -1597,16 +1596,20 @@ public ObjectDelta<T> subtract(@NotNull Collection<ItemPath> paths) {
* @param value
* @return true if the delta originally contained an instruction to add (or set) 'itemPath' to 'value'.
*/
public boolean subtract(@NotNull ItemPath itemPath, @NotNull PrismValue value) {
public boolean subtract(@NotNull ItemPath itemPath, @NotNull PrismValue value, boolean fromMinusSet) {
if (isAdd()) {
return subtractFromObject(objectToAdd, itemPath, value);
if (!fromMinusSet) {
return subtractFromObject(objectToAdd, itemPath, value);
} else {
return false;
}
} else {
return subtractFromModifications(modifications, itemPath, value);
return subtractFromModifications(modifications, itemPath, value, fromMinusSet);
}
}

public static boolean subtractFromModifications(Collection<? extends ItemDelta<?, ?>> modifications, @NotNull ItemPath itemPath,
@NotNull PrismValue value) {
public static boolean subtractFromModifications(Collection<? extends ItemDelta<?, ?>> modifications,
@NotNull ItemPath itemPath, @NotNull PrismValue value, boolean fromMinusSet) {
if (modifications == null) {
return false;
}
Expand All @@ -1615,9 +1618,16 @@ public static boolean subtractFromModifications(Collection<? extends ItemDelta<?
while (itemDeltaIterator.hasNext()) {
ItemDelta<?, ?> itemDelta = itemDeltaIterator.next();
if (itemPath.equivalent(itemDelta.getPath())) {
boolean removed1 = itemDelta.removeValueToAdd(value);
boolean removed2 = itemDelta.removeValueToReplace(value);
removed = removed || removed1 || removed2;
if (!fromMinusSet) {
boolean removed1 = itemDelta.removeValueToAdd(value);
boolean removed2 = itemDelta.removeValueToReplace(value);
removed = removed || removed1 || removed2;
} else {
if (itemDelta.getValuesToReplace() != null) {
throw new UnsupportedOperationException("Couldn't subtract 'value to be deleted' from REPLACE itemDelta: " + itemDelta);
}
removed = removed || itemDelta.removeValueToDelete(value);
}
if (itemDelta.isInFactEmpty()) {
itemDeltaIterator.remove();
}
Expand Down
Expand Up @@ -184,11 +184,11 @@ public List<ObjectDelta<?>> getDeltaList() {
return rv;
}

public boolean subtractFromFocusDelta(@NotNull ItemPath itemPath, @NotNull PrismValue value) {
public boolean subtractFromFocusDelta(@NotNull ItemPath itemPath, @NotNull PrismValue value, boolean fromMinus) {
if (focusChange == null) {
return false;
} else {
return focusChange.subtract(itemPath, value);
return focusChange.subtract(itemPath, value, fromMinus);
}
}

Expand Down
Expand Up @@ -255,6 +255,9 @@
This defines the object modification operation (add/replace/delete of the specific assignment).
In case that new object is added then all assignments in the object are considered to
be added. The case of object deletion does not make sense here.

Currently supported are ADD and DELETE operations.
REPLACE (meaning MODIFY?) is not supported yet.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
Expand Down
Expand Up @@ -19,6 +19,7 @@
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.delta.PropertyDelta;

import com.evolveum.midpoint.prism.delta.builder.DeltaBuilder;
import com.evolveum.midpoint.schema.constants.SchemaConstants;
import com.evolveum.midpoint.schema.util.ObjectTypeUtil;
import org.testng.annotations.Test;
Expand All @@ -38,6 +39,7 @@
import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;

import static com.evolveum.midpoint.prism.util.PrismTestUtil.getPrismContext;
import static org.testng.AssertJUnit.*;

/**
Expand All @@ -57,12 +59,12 @@ public void testAssignmentSameNullIdApplyToObject() throws Exception {
PrismObject<UserType> user = PrismTestUtil.parseObject(USER_JACK_FILE);

//Delta
PrismContainerValue<AssignmentType> assignmentValue = new PrismContainerValue<AssignmentType>(PrismTestUtil.getPrismContext());
PrismContainerValue<AssignmentType> assignmentValue = new PrismContainerValue<AssignmentType>(getPrismContext());
// The value id is null
assignmentValue.setPropertyRealValue(AssignmentType.F_DESCRIPTION, "jamalalicha patlama paprtala", PrismTestUtil.getPrismContext());
assignmentValue.setPropertyRealValue(AssignmentType.F_DESCRIPTION, "jamalalicha patlama paprtala", getPrismContext());

ObjectDelta<UserType> userDelta = ObjectDelta.createModificationAddContainer(UserType.class, USER_JACK_OID,
UserType.F_ASSIGNMENT, PrismTestUtil.getPrismContext(), assignmentValue);
UserType.F_ASSIGNMENT, getPrismContext(), assignmentValue);

// WHEN
userDelta.applyTo(user);
Expand All @@ -86,12 +88,12 @@ public void testAddInducementConstructionSameNullIdApplyToObject() throws Except
PrismObject<RoleType> role = PrismTestUtil.parseObject(ROLE_CONSTRUCTION_FILE);

//Delta
PrismContainerValue<AssignmentType> inducementValue = new PrismContainerValue<AssignmentType>(PrismTestUtil.getPrismContext());
PrismContainerValue<AssignmentType> inducementValue = new PrismContainerValue<AssignmentType>(getPrismContext());
// The value id is null
inducementValue.setPropertyRealValue(AssignmentType.F_DESCRIPTION, "jamalalicha patlama paprtala", PrismTestUtil.getPrismContext());
inducementValue.setPropertyRealValue(AssignmentType.F_DESCRIPTION, "jamalalicha patlama paprtala", getPrismContext());

ObjectDelta<RoleType> roleDelta = ObjectDelta.createModificationAddContainer(RoleType.class, ROLE_CONSTRUCTION_OID,
RoleType.F_INDUCEMENT, PrismTestUtil.getPrismContext(), inducementValue);
RoleType.F_INDUCEMENT, getPrismContext(), inducementValue);

// WHEN
roleDelta.applyTo(role);
Expand Down Expand Up @@ -123,7 +125,7 @@ public void testDeleteInducementValidIdSameValueApplyToObject() throws Exception
inducement.setConstruction(construction);
inducement.setId(ROLE_CONSTRUCTION_INDUCEMENT_ID);
ObjectDelta<RoleType> roleDelta = ObjectDelta.createModificationDeleteContainer(RoleType.class, ROLE_CONSTRUCTION_OID,
RoleType.F_INDUCEMENT, PrismTestUtil.getPrismContext(), inducement);
RoleType.F_INDUCEMENT, getPrismContext(), inducement);

// WHEN
roleDelta.applyTo(role);
Expand All @@ -149,7 +151,7 @@ public void testDeleteInducementValidIdEmptyValueApplyToObject() throws Exceptio
AssignmentType inducement = new AssignmentType();
inducement.setId(ROLE_CONSTRUCTION_INDUCEMENT_ID);
ObjectDelta<RoleType> roleDelta = ObjectDelta.createModificationDeleteContainer(RoleType.class, ROLE_CONSTRUCTION_OID,
RoleType.F_INDUCEMENT, PrismTestUtil.getPrismContext(), inducement);
RoleType.F_INDUCEMENT, getPrismContext(), inducement);

// WHEN
roleDelta.applyTo(role);
Expand Down Expand Up @@ -177,7 +179,7 @@ public void testDeleteInducementValidIdEmptyValueApplyToObjectStatic() throws Ex
AssignmentType inducement = new AssignmentType();
inducement.setId(ROLE_CONSTRUCTION_INDUCEMENT_ID);
ObjectDelta<RoleType> roleDelta = ObjectDelta.createModificationDeleteContainer(RoleType.class, ROLE_CONSTRUCTION_OID,
RoleType.F_INDUCEMENT, PrismTestUtil.getPrismContext(), inducement);
RoleType.F_INDUCEMENT, getPrismContext(), inducement);

// WHEN
PropertyDelta.applyTo(roleDelta.getModifications(), role);
Expand Down Expand Up @@ -211,7 +213,7 @@ public void testDeleteInducementConstructionSameNullIdApplyToObject() throws Exc
new NameItemPathSegment(RoleType.F_INDUCEMENT),
new IdItemPathSegment(ROLE_CONSTRUCTION_INDUCEMENT_ID),
new NameItemPathSegment(AssignmentType.F_CONSTRUCTION)),
PrismTestUtil.getPrismContext(), construction);
getPrismContext(), construction);

// WHEN
roleDelta.applyTo(role);
Expand Down Expand Up @@ -249,7 +251,7 @@ public void testDeleteInducementActivationSameNullIdApplyToObject() throws Excep
new NameItemPathSegment(RoleType.F_INDUCEMENT),
new IdItemPathSegment(ROLE_CONSTRUCTION_INDUCEMENT_ID),
new NameItemPathSegment(AssignmentType.F_ACTIVATION)),
PrismTestUtil.getPrismContext(), activationType);
getPrismContext(), activationType);

// WHEN
roleDelta.applyTo(role);
Expand Down Expand Up @@ -286,7 +288,7 @@ public void testDeleteUserAssignmentActivationSameNullIdApplyToObject() throws E
new NameItemPathSegment(UserType.F_ASSIGNMENT),
new IdItemPathSegment(USER_JACK_ASSIGNMENT_ID),
new NameItemPathSegment(AssignmentType.F_ACTIVATION)),
PrismTestUtil.getPrismContext(), activationType);
getPrismContext(), activationType);

// WHEN
userDelta.applyTo(user);
Expand Down Expand Up @@ -328,13 +330,13 @@ public void testSubtractAssignmentFromAddDelta() throws Exception {

PrismContainerValue<AssignmentType> assignmentValue =
ObjectTypeUtil.createAssignmentTo("00000001-d34d-b33f-f00d-000000000002", ObjectTypes.ROLE,
PrismTestUtil.getPrismContext())
getPrismContext())
.asPrismContainerValue();
assignmentContainer.add(assignmentValue);

System.out.println("Delta before operation:\n" + addDelta.debugDump() + "\n");
System.out.println("Assignment to subtract:\n" + assignmentValue.debugDump() + "\n");
boolean removed = addDelta.subtract(SchemaConstants.PATH_ASSIGNMENT, assignmentValue);
boolean removed = addDelta.subtract(SchemaConstants.PATH_ASSIGNMENT, assignmentValue, false);

// THEN
System.out.println("Delta after operation:\n" + addDelta.debugDump() + "\n");
Expand All @@ -344,4 +346,44 @@ public void testSubtractAssignmentFromAddDelta() throws Exception {
assertTrue("Remaining delta is not an ADD delta", addDelta.isAdd());
assertEquals("Wrong # of remaining assignments", 2, addDelta.getObjectToAdd().asObjectable().getAssignment().size());
}

@Test
public void testSubtractAssignmentFromModifyDelta() throws Exception {
final String TEST_NAME = "testSubtractAssignmentFromModifyDelta";
displayTestTile(TEST_NAME);

// GIVEN
PrismObject<UserType> user = PrismTestUtil.parseObject(USER_BILL_FILE);
user.asObjectable().getAssignment().get(0).setId(9999L);
AssignmentType assignment9999 = new AssignmentType();
assignment9999.setId(9999L);
ObjectDelta<UserType> delta = (ObjectDelta<UserType>) DeltaBuilder.deltaFor(UserType.class, getPrismContext())
.item(UserType.F_ASSIGNMENT).delete(assignment9999)
.asObjectDelta(user.getOid());

// WHEN
PrismContainerDefinition<AssignmentType> assignmentDef = PrismTestUtil.getSchemaRegistry()
.findContainerDefinitionByCompileTimeClass(AssignmentType.class).clone();
((PrismContainerDefinitionImpl) assignmentDef).setMaxOccurs(1);
PrismContainer<AssignmentType> assignmentContainer = assignmentDef.instantiate();

PrismContainerValue<AssignmentType> assignmentValue =
ObjectTypeUtil.createAssignmentTo("00000001-d34d-b33f-f00d-000000000002", ObjectTypes.ROLE,
getPrismContext())
.asPrismContainerValue();
assignmentValue.setId(9999L);
assignmentContainer.add(assignmentValue);

System.out.println("Delta before operation:\n" + delta.debugDump() + "\n");
System.out.println("Assignment to subtract:\n" + assignmentValue.debugDump() + "\n");
boolean removed = delta.subtract(SchemaConstants.PATH_ASSIGNMENT, assignmentValue, true);

// THEN
System.out.println("Delta after operation:\n" + delta.debugDump() + "\n");
System.out.println("Removed: " + removed + "\n");

assertTrue("Not removed", removed);
assertTrue("Remaining delta is not a MODIFY delta", delta.isModify());
assertEquals("Wrong # of remaining modifications", 0, delta.getModifications().size());
}
}

0 comments on commit 5dcc330

Please sign in to comment.