Skip to content

Commit

Permalink
Storing assignment metadata (MID-2234)
Browse files Browse the repository at this point in the history
  • Loading branch information
semancik committed Nov 17, 2016
1 parent 3c0c2d1 commit 5c0cdc7
Show file tree
Hide file tree
Showing 17 changed files with 312 additions and 60 deletions.
Expand Up @@ -114,4 +114,7 @@ public class PrismConstants {

// a bit of hack: by this local name we know if a object is a reference (c:ObjectReferenceType)
public static final String REFERENCE_TYPE_NAME = "ObjectReferenceType";

public static final boolean EQUALS_DEFAULT_IGNORE_METADATA = true;
public static final boolean EQUALS_DEFAULT_IS_LITERAL = false;
}
Expand Up @@ -1050,6 +1050,15 @@ void diffItems(PrismContainerValue<C> thisValue, PrismContainerValue<C> other,

if (thisValue.getItems() != null) {
for (Item<?,?> thisItem: thisValue.getItems()) {
if (!isLiteral) {
ItemDefinition itemDef = thisItem.getDefinition();
if (itemDef == null && other.getDefinition() != null) {
itemDef = other.getDefinition().findItemDefinition(thisItem.getElementName());
}
if (itemDef != null && itemDef.isOperational()) {
continue;
}
}
Item otherItem = other.findItem(thisItem.getElementName());
// The "delete" delta will also result from the following diff
thisItem.diffInternal(otherItem, deltas, ignoreMetadata, isLiteral);
Expand All @@ -1059,6 +1068,15 @@ void diffItems(PrismContainerValue<C> thisValue, PrismContainerValue<C> other,
if (other.getItems() != null) {
for (Item otherItem: other.getItems()) {
Item thisItem = thisValue.findItem(otherItem.getElementName());
if (!isLiteral) {
ItemDefinition itemDef = otherItem.getDefinition();
if (itemDef == null && thisValue.getDefinition() != null) {
itemDef = thisValue.getDefinition().findItemDefinition(otherItem.getElementName());
}
if (itemDef != null && itemDef.isOperational()) {
continue;
}
}
if (thisItem == null) {
// Other has an item that we don't have, this must be an add
ItemDelta itemDelta = otherItem.createDelta();
Expand Down
Expand Up @@ -252,6 +252,33 @@ public int compare(V v1, V v2) {
};
return MiscUtil.unorderedCollectionEquals(collection1, collection2, comparator);
}

public static <V extends PrismValue> boolean containsAll(Collection<V> thisSet, Collection<V> otherSet, boolean ignoreMetadata, boolean isLiteral) {
if (thisSet == null && otherSet == null) {
return true;
}
if (otherSet == null) {
return true;
}
if (thisSet == null) {
return false;
}
for (V otherValue: otherSet) {
if (!contains(thisSet, otherValue, ignoreMetadata, isLiteral)) {
return false;
}
}
return true;
}

public static <V extends PrismValue> boolean contains(Collection<V> thisSet, V otherValue, boolean ignoreMetadata, boolean isLiteral) {
for (V thisValue: thisSet) {
if (thisValue.equalsComplex(otherValue, ignoreMetadata, isLiteral)) {
return true;
}
}
return false;
}

@Override
public void normalize() {
Expand Down
Expand Up @@ -1299,34 +1299,30 @@ public Item<V,D> getItemNewMatchingPath(Item<V,D> itemOld) throws SchemaExceptio
* deltas are equal.
*/
public boolean contains(ItemDelta<V,D> other) {
return contains(other, PrismConstants.EQUALS_DEFAULT_IGNORE_METADATA, PrismConstants.EQUALS_DEFAULT_IS_LITERAL);
}
/**
* Returns true if the other delta is a complete subset of this delta.
* I.e. if all the statements of the other delta are already contained
* in this delta. As a consequence it also returns true if the two
* deltas are equal.
*/
public boolean contains(ItemDelta<V,D> other, boolean ignoreMetadata, boolean isLiteral) {
if (!this.getPath().equivalent(other.getPath())) {
return false;
}
if (!containsSet(this.valuesToAdd, other.valuesToAdd)) {
if (!PrismValue.containsAll(this.valuesToAdd, other.valuesToAdd, ignoreMetadata, isLiteral)) {
return false;
}
if (!containsSet(this.valuesToDelete, other.valuesToDelete)) {
if (!PrismValue.containsAll(this.valuesToDelete, other.valuesToDelete, ignoreMetadata, isLiteral)) {
return false;
}
if (!containsSet(this.valuesToReplace, other.valuesToReplace)) {
if (!PrismValue.containsAll(this.valuesToReplace, other.valuesToReplace, ignoreMetadata, isLiteral)) {
return false;
}
return true;
}

private boolean containsSet(Collection<V> thisSet, Collection<V> otherSet) {
if (thisSet == null && otherSet == null) {
return true;
}
if (otherSet == null) {
return true;
}
if (thisSet == null) {
return false;
}
return thisSet.containsAll(otherSet);
}

public abstract ItemDelta<V,D> clone();

protected void copyValues(ItemDelta<V,D> clone) {
Expand Down
Expand Up @@ -221,9 +221,13 @@ public <D extends ItemDelta> D addModification(D itemDelta) {
}
}

public boolean containsModification(ItemDelta itemDelta) {
public boolean containsModification(ItemDelta itemDelta) {
return containsModification(itemDelta, PrismConstants.EQUALS_DEFAULT_IGNORE_METADATA, PrismConstants.EQUALS_DEFAULT_IS_LITERAL);
}

public boolean containsModification(ItemDelta itemDelta, boolean ignoreMetadata, boolean isLiteral) {
for (ItemDelta modification: modifications) {
if (modification.contains(itemDelta)) {
if (modification.contains(itemDelta, ignoreMetadata, isLiteral)) {
return true;
}
}
Expand Down
Expand Up @@ -103,18 +103,14 @@ public void testCompareJack() throws SchemaException, SAXException, IOException
* delta is OK.
*/
@Test
public void testDiffJack() throws SchemaException, SAXException, IOException {
public void testDiffJack() throws Exception {
System.out.println("===[ testDiffJack ]===");

// GIVEN
PrismContext prismContext = constructInitializedPrismContext();

// Document document = DOMUtil.parseFile(USER_JACK_FILE_XML);
// Element userElement = DOMUtil.getFirstChildElement(document);
PrismObject<UserType> jackOriginal = prismContext.parseObject(getFile(USER_JACK_FILE_BASENAME));

// document = DOMUtil.parseFile(USER_JACK_MODIFIED_FILE);
// userElement = DOMUtil.getFirstChildElement(document);
PrismObject<UserType> jackModified = prismContext.parseObject(getFile(USER_JACK_MODIFIED_FILE_BASENAME));

// WHEN
Expand All @@ -127,6 +123,65 @@ public void testDiffJack() throws SchemaException, SAXException, IOException {
jackDelta.assertDefinitions();
jackDelta.checkConsistence(true, true, true);

assertEquals("Wrong delta type", ChangeType.MODIFY, jackDelta.getChangeType());
assertEquals("Wrong delta OID", USER_JACK_OID, jackDelta.getOid());
assertEquals("Wrong number of modificaitions", 8, jackDelta.getModifications().size());

PrismAsserts.assertPropertyReplace(jackDelta, USER_FULLNAME_QNAME, "Jack Sparrow");

PrismAsserts.assertPropertyDelete(jackDelta, new ItemPath(USER_EXTENSION_QNAME, EXTENSION_MULTI_ELEMENT), "dva");
PrismAsserts.assertPropertyAdd(jackDelta, new ItemPath(USER_EXTENSION_QNAME, EXTENSION_MULTI_ELEMENT), "osem");
// TODO: assert BAR

PrismAsserts.assertPropertyDelete(jackDelta, USER_ADDITIONALNAMES_QNAME, "Captain");

PrismAsserts.assertPropertyAdd(jackDelta, USER_LOCALITY_QNAME, "World's End");

// There won't be any activation deltas. Activation is operational.
PrismAsserts.assertNoItemDelta(jackDelta, USER_ENABLED_PATH);
PrismAsserts.assertNoItemDelta(jackDelta, USER_VALID_FROM_PATH);

PrismAsserts.assertPropertyReplace(jackDelta,
new ItemPath(
new NameItemPathSegment(USER_ASSIGNMENT_QNAME),
new IdItemPathSegment(USER_ASSIGNMENT_2_ID),
new NameItemPathSegment(USER_DESCRIPTION_QNAME)),
"Assignment II");

ContainerDelta<?> assignment3Delta = PrismAsserts.assertContainerAddGetContainerDelta(jackDelta, new ItemPath(USER_ASSIGNMENT_QNAME));
PrismContainerValue<?> assignment3DeltaAddValue = assignment3Delta.getValuesToAdd().iterator().next();
assertEquals("Assignment 3 wrong ID", USER_ASSIGNMENT_3_ID, assignment3DeltaAddValue.getId());

// TODO assert assignment[i1112]/accountConstruction
}


/**
* Parse original jack and modified Jack. Diff and assert if the resulting
* delta is OK.
* This is literal diff. All the changes should be part of the resulting delta.
*/
@Test
public void testDiffJackLiteral() throws Exception {
System.out.println("===[ testDiffJackLiteral ]===");

// GIVEN
PrismContext prismContext = constructInitializedPrismContext();

PrismObject<UserType> jackOriginal = prismContext.parseObject(getFile(USER_JACK_FILE_BASENAME));

PrismObject<UserType> jackModified = prismContext.parseObject(getFile(USER_JACK_MODIFIED_FILE_BASENAME));

// WHEN
ObjectDelta<UserType> jackDelta = jackOriginal.diff(jackModified, true, true);

// THEN
System.out.println("Jack delta:");
System.out.println(jackDelta.debugDump());

jackDelta.assertDefinitions();
jackDelta.checkConsistence(true, true, true);

assertEquals("Wrong delta type", ChangeType.MODIFY, jackDelta.getChangeType());
assertEquals("Wrong delta OID", USER_JACK_OID, jackDelta.getOid());
assertEquals("Wrong number of modificaitions", 10, jackDelta.getModifications().size());
Expand Down Expand Up @@ -165,12 +220,8 @@ public void testDiffPatchRoundTrip() throws SchemaException, SAXException, IOExc
// GIVEN
PrismContext prismContext = constructInitializedPrismContext();

// Document document = DOMUtil.parseFile(USER_JACK_FILE_XML);
// Element userElement = DOMUtil.getFirstChildElement(document);
PrismObject<UserType> jackOriginal = prismContext.parseObject(getFile(USER_JACK_FILE_BASENAME));

// document = DOMUtil.parseFile(USER_JACK_MODIFIED_FILE);
// userElement = DOMUtil.getFirstChildElement(document);
PrismObject<UserType> jackModified = prismContext.parseObject(getFile(USER_JACK_MODIFIED_FILE_BASENAME));

ObjectDelta<UserType> jackDelta = jackOriginal.diff(jackModified);
Expand Down
Expand Up @@ -207,6 +207,7 @@ public abstract class SchemaConstants {
public static final ItemPath PATH_OPERATIONAL_STATE_LAST_AVAILABILITY_STATUS = new ItemPath(
ResourceType.F_OPERATIONAL_STATE, OperationalStateType.F_LAST_AVAILABILITY_STATUS);
public static final ItemPath PATH_ATTRIBUTES = new ItemPath(C_ATTRIBUTES);
public static final ItemPath PATH_ASSIGNMENT = new ItemPath(FocusType.F_ASSIGNMENT);
public static final ItemPath PATH_ASSOCIATION = new ItemPath(C_ASSOCIATION);
public static final ItemPath PATH_TRIGGER = new ItemPath(ObjectType.F_TRIGGER);
public static final ItemPath PATH_CREDENTIALS_PASSWORD_FAILED_LOGINS = new ItemPath(
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2013 Evolveum
* Copyright (c) 2010-2016 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -20,10 +20,12 @@
import com.evolveum.midpoint.prism.delta.ChangeType;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.util.PrismTestUtil;
import com.evolveum.midpoint.prism.xml.XmlTypeConverter;
import com.evolveum.midpoint.schema.constants.MidPointConstants;
import com.evolveum.midpoint.util.PrettyPrinter;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.MetadataType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;

import org.testng.annotations.BeforeSuite;
Expand Down Expand Up @@ -90,7 +92,51 @@ public void testUserListSimpleDiff() throws SchemaException {
}

@Test
public void testContextlessEquals() throws Exception {
public void testAssignmentEquals() throws Exception {
PrismContext prismContext = PrismTestUtil.getPrismContext();

AssignmentType a1a = new AssignmentType();
prismContext.adopt(a1a);
a1a.setDescription("descr1");

AssignmentType a2 = new AssignmentType();
prismContext.adopt(a2);
a2.setDescription("descr2");

AssignmentType a1b = new AssignmentType();
prismContext.adopt(a1b);
a1b.setDescription("descr1");

AssignmentType a1m = new AssignmentType();
prismContext.adopt(a1m);
a1m.setDescription("descr1");
MetadataType metadata1m = new MetadataType();
metadata1m.setCreateTimestamp(XmlTypeConverter.createXMLGregorianCalendar(System.currentTimeMillis()));
a1m.setMetadata(metadata1m);

// WHEN
assertFalse(a1a.equals(a2));
assertFalse(a1b.equals(a2));
assertFalse(a1m.equals(a2));
assertFalse(a2.equals(a1a));
assertFalse(a2.equals(a1b));
assertFalse(a2.equals(a1m));

assertTrue(a1a.equals(a1a));
assertTrue(a1b.equals(a1b));
assertTrue(a1m.equals(a1m));
assertTrue(a2.equals(a2));

assertTrue(a1a.equals(a1b));
assertTrue(a1b.equals(a1a));
assertTrue(a1a.equals(a1m));
assertTrue(a1b.equals(a1m));
assertTrue(a1m.equals(a1a));
assertTrue(a1m.equals(a1b));
}

@Test
public void testContextlessAssignmentEquals() throws Exception {
AssignmentType a1 = new AssignmentType(); // no prismContext here
a1.setDescription("descr1");

Expand All @@ -112,7 +158,7 @@ public void testContextlessEquals() throws Exception {
}

@Test
public void testContextlessEquals2() throws Exception {
public void testContextlessAssignmentEquals2() throws Exception {

// (1) user without prismContext - the functionality is reduced

Expand Down
Expand Up @@ -48,19 +48,20 @@
*/
public class MidPointAsserts {

public static <F extends FocusType> void assertAssigned(PrismObject<F> user, String targetOid, QName refType) {
public static <F extends FocusType> AssignmentType assertAssigned(PrismObject<F> user, String targetOid, QName refType) {
F userType = user.asObjectable();
for (AssignmentType assignmentType: userType.getAssignment()) {
ObjectReferenceType targetRef = assignmentType.getTargetRef();
if (targetRef != null) {
if (refType.equals(targetRef.getType())) {
if (targetOid.equals(targetRef.getOid())) {
return;
return assignmentType;
}
}
}
}
AssertJUnit.fail(user + " does not have assigned "+refType.getLocalPart()+" "+targetOid);
return null; // not reachable
}

public static void assertAssigned(PrismObject<? extends FocusType> focus, String targetOid, QName refType, QName relation) {
Expand Down Expand Up @@ -123,8 +124,8 @@ public static <F extends FocusType> void assertNoAssignments(PrismObject<F> user
assertTrue(user + " does have assignments "+assignments+" while not expecting it", assignments.isEmpty());
}

public static <F extends FocusType> void assertAssignedRole(PrismObject<F> user, String roleOid) {
assertAssigned(user, roleOid, RoleType.COMPLEX_TYPE);
public static <F extends FocusType> AssignmentType assertAssignedRole(PrismObject<F> user, String roleOid) {
return assertAssigned(user, roleOid, RoleType.COMPLEX_TYPE);
}

public static <F extends FocusType> void assertNotAssignedRole(PrismObject<F> user, String roleOid) {
Expand Down
Expand Up @@ -35,13 +35,15 @@
import com.evolveum.midpoint.prism.delta.PropertyDelta;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.path.ItemPath.CompareResult;
import com.evolveum.midpoint.util.DebugDumpable;
import com.evolveum.midpoint.util.DebugUtil;
import com.evolveum.midpoint.util.exception.SchemaException;

/**
* @author semancik
*
*/
public class ItemDeltaItem<V extends PrismValue,D extends ItemDefinition> {
public class ItemDeltaItem<V extends PrismValue,D extends ItemDefinition> implements DebugDumpable {

Item<V,D> itemOld;
ItemDelta<V,D> delta;
Expand Down Expand Up @@ -416,6 +418,18 @@ public boolean equals(Object obj) {
public String toString() {
return "IDI(old=" + itemOld + ", delta=" + delta + ", new=" + itemNew + ")";
}

@Override
public String debugDump(int indent) {
StringBuilder sb = new StringBuilder();
DebugUtil.debugDumpLabelLn(sb, "ItemDeltaItem", indent);
DebugUtil.debugDumpWithLabelLn(sb, "itemOld", itemOld, indent + 1);
DebugUtil.debugDumpWithLabelLn(sb, "delta", delta, indent + 1);
DebugUtil.debugDumpWithLabelLn(sb, "itemNew", itemNew, indent + 1);
DebugUtil.debugDumpWithLabelToStringLn(sb, "resolvePath", resolvePath, indent + 1);
DebugUtil.debugDumpWithLabelToString(sb, "residualPath", residualPath, indent + 1);
return sb.toString();
}



Expand Down

0 comments on commit 5c0cdc7

Please sign in to comment.