/*
* Copyright (c) 2010-2013 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.evolveum.midpoint.schema;
import static com.evolveum.midpoint.prism.util.PrismTestUtil.getPrismContext;
import static com.evolveum.midpoint.schema.DeltaConvertor.toObjectDeltaType;
import static org.testng.AssertJUnit.assertNull;
import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertTrue;
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.delta.ContainerDelta;
import com.evolveum.midpoint.prism.delta.ItemDelta;
import com.evolveum.midpoint.prism.delta.ObjectDelta;
import com.evolveum.midpoint.prism.delta.PropertyDelta;
import com.evolveum.midpoint.prism.delta.ReferenceDelta;
import com.evolveum.midpoint.prism.delta.builder.DeltaBuilder;
import com.evolveum.midpoint.prism.path.IdItemPathSegment;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.prism.path.NameItemPathSegment;
import com.evolveum.midpoint.prism.polystring.PolyString;
import com.evolveum.midpoint.prism.util.PrismAsserts;
import com.evolveum.midpoint.prism.util.PrismTestUtil;
import com.evolveum.midpoint.prism.xnode.MapXNode;
import com.evolveum.midpoint.prism.xnode.PrimitiveXNode;
import com.evolveum.midpoint.util.DOMUtil;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.xml.ns._public.common.api_types_3.ObjectModificationType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.*;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType;
import com.evolveum.prism.xml.ns._public.types_3.*;
import org.testng.annotations.Test;
import java.io.File;
import java.io.IOException;
import java.util.*;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertNotNull;
/**
* @author Radovan Semancik
*/
public class TestDeltaConverter extends AbstractSchemaTest {
private static final File TEST_DIR = new File("src/test/resources/deltaconverter");
private static final ItemPath CREDENTIALS_PASSWORD_VALUE_PATH =
new ItemPath(UserType.F_CREDENTIALS, CredentialsType.F_PASSWORD, PasswordType.F_VALUE);
@Test
public void testRefWithObject() throws SchemaException, IOException, JAXBException {
System.out.println("===[ testRefWithObject ]====");
ObjectModificationType objectChange = PrismTestUtil.parseAtomicValue(new File(TEST_DIR, "user-modify-add-account.xml"),
ObjectModificationType.COMPLEX_TYPE);
ObjectDelta<UserType> objectDelta = DeltaConvertor.createObjectDelta(objectChange, UserType.class,
getPrismContext());
System.out.println("delta: " + objectDelta.debugDump());
assertNotNull("No object delta", objectDelta);
objectDelta.checkConsistence();
assertEquals("Wrong OID", "c0c010c0-d34d-b33f-f00d-111111111111", objectDelta.getOid());
ReferenceDelta accoutRefDelta = objectDelta.findReferenceModification(UserType.F_LINK_REF);
assertNotNull("No accountRef delta", accoutRefDelta);
Collection<PrismReferenceValue> valuesToAdd = accoutRefDelta.getValuesToAdd();
assertEquals("Wrong number of values to add", 1, valuesToAdd.size());
PrismReferenceValue accountRefVal = valuesToAdd.iterator().next();
assertNotNull("No object in accountRef value", accountRefVal.getObject());
objectDelta.assertDefinitions();
}
@Test
public void testPasswordChange() throws Exception {
System.out.println("===[ testPasswordChange ]====");
ObjectModificationType objectChange = PrismTestUtil.parseAtomicValue(new File(TEST_DIR, "user-modify-password.xml"),
ObjectModificationType.COMPLEX_TYPE);
// WHEN
ObjectDelta<UserType> objectDelta = DeltaConvertor.createObjectDelta(objectChange, UserType.class,
getPrismContext());
// THEN
assertNotNull("No object delta", objectDelta);
objectDelta.checkConsistence();
assertEquals("Wrong OID", "c0c010c0-d34d-b33f-f00d-111111111111", objectDelta.getOid());
PropertyDelta<ProtectedStringType> protectedStringDelta = objectDelta.findPropertyDelta(CREDENTIALS_PASSWORD_VALUE_PATH);
assertNotNull("No protectedString delta", protectedStringDelta);
Collection<PrismPropertyValue<ProtectedStringType>> valuesToReplace = protectedStringDelta.getValuesToReplace();
assertEquals("Wrong number of values to replace", 1, valuesToReplace.size());
PrismPropertyValue<ProtectedStringType> protectedStringVal = valuesToReplace.iterator().next();
assertNotNull("Null value in protectedStringDelta", protectedStringVal);
PrismObject<UserType> user = PrismTestUtil.parseObject(USER_JACK_FILE);
// apply to user
objectDelta.applyTo(user);
PrismProperty<ProtectedStringType> protectedStringProperty = user.findProperty(CREDENTIALS_PASSWORD_VALUE_PATH);
PrismPropertyValue<ProtectedStringType> protectedStringPropertyValue = protectedStringProperty.getValue();
assertTrue("protectedString not equivalent", protectedStringPropertyValue.equalsRealValue(protectedStringVal));
objectDelta.assertDefinitions();
}
@Test
public void testModifyGivenName() throws Exception {
System.out.println("===[ testModifyGivenName ]====");
ObjectModificationType objectChange = PrismTestUtil.parseAtomicValue(new File(TEST_DIR, "user-modify-givenname.xml"),
ObjectModificationType.COMPLEX_TYPE);
// WHEN
ObjectDelta<UserType> objectDelta = DeltaConvertor.createObjectDelta(objectChange, UserType.class,
getPrismContext());
// THEN
assertNotNull("No object delta", objectDelta);
objectDelta.checkConsistence();
assertEquals("Wrong OID", "c0c010c0-d34d-b33f-f00d-111111111111", objectDelta.getOid());
PropertyDelta<String> givenNameDelta = objectDelta.findPropertyDelta(UserType.F_GIVEN_NAME);
assertNotNull("No givenName delta", givenNameDelta);
Collection<PrismPropertyValue<String>> valuesToReplace = givenNameDelta.getValuesToReplace();
assertEquals("Wrong number of values to replace", 0, valuesToReplace.size());
PrismObject<UserType> user = PrismTestUtil.parseObject(USER_JACK_FILE);
// apply to user
objectDelta.applyTo(user);
PrismProperty<String> protectedStringProperty = user.findProperty(UserType.F_GIVEN_NAME);
assertNull("givenName porperty sneaked in after delta was applied", protectedStringProperty);
objectDelta.assertDefinitions();
}
@Test
public void testAddAssignment() throws Exception {
System.out.println("===[ testAddAssignment ]====");
ObjectModificationType objectChange = PrismTestUtil.parseAtomicValue(new File(TEST_DIR, "user-modify-add-role-pirate.xml"),
ObjectModificationType.COMPLEX_TYPE);
// WHEN
ObjectDelta<UserType> objectDelta = DeltaConvertor.createObjectDelta(objectChange, UserType.class,
getPrismContext());
System.out.println("Delta:");
System.out.println(objectDelta.debugDump());
// THEN
assertNotNull("No object delta", objectDelta);
objectDelta.checkConsistence();
assertEquals("Wrong OID", "c0c010c0-d34d-b33f-f00d-111111111111", objectDelta.getOid());
ContainerDelta<AssignmentType> assignmentDelta = objectDelta.findContainerDelta(UserType.F_ASSIGNMENT);
assertNotNull("No assignment delta", assignmentDelta);
Collection<PrismContainerValue<AssignmentType>> valuesToAdd = assignmentDelta.getValuesToAdd();
assertEquals("Wrong number of values to add", 1, valuesToAdd.size());
PrismContainerValue<AssignmentType> assignmentVal = valuesToAdd.iterator().next();
assertNotNull("Null value in protectedStringDelta", assignmentVal);
PrismReference targetRef = assignmentVal.findReference(AssignmentType.F_TARGET_REF);
assertNotNull("No targetRef in assignment", targetRef);
PrismReferenceValue targetRefVal = targetRef.getValue();
assertNotNull("No targetRef value in assignment", targetRefVal);
assertEquals("Wrong OID in targetRef value", "12345678-d34d-b33f-f00d-987987987988", targetRefVal.getOid());
assertEquals("Wrong type in targetRef value", RoleType.COMPLEX_TYPE, targetRefVal.getTargetType());
PrismObject<UserType> user = PrismTestUtil.parseObject(USER_JACK_FILE);
objectDelta.assertDefinitions("delta before test");
user.assertDefinitions("user before test");
// apply to user
objectDelta.applyTo(user);
objectDelta.assertDefinitions("delta after test");
user.assertDefinitions("user after test");
// TODO
}
@Test
public void testAccountRefDelta() throws Exception {
System.out.println("===[ testAccountRefDelta ]====");
// GIVEN
ObjectModificationType objectChange = new ObjectModificationType();
objectChange.setOid("12345");
ItemDeltaType modificationDeleteAccountRef = new ItemDeltaType();
modificationDeleteAccountRef.setModificationType(ModificationTypeType.DELETE);
ObjectReferenceType accountRefToDelete = new ObjectReferenceType();
accountRefToDelete.setOid("54321");
PrismContext prismContext = getPrismContext();
RawType modificationValue = new RawType(((PrismContextImpl) prismContext).getBeanMarshaller().marshall(accountRefToDelete), prismContext);
modificationDeleteAccountRef.getValue().add(modificationValue);
objectChange.getItemDelta().add(modificationDeleteAccountRef);
ItemPathType itemPathType = new ItemPathType(new ItemPath(UserType.F_LINK_REF));
modificationDeleteAccountRef.setPath(itemPathType);
PrismObjectDefinition<UserType> objDef = PrismTestUtil.getObjectDefinition(UserType.class);
// WHEN
Collection<? extends ItemDelta> modifications = DeltaConvertor.toModifications(objectChange, objDef);
// THEN
assertNotNull("Null modifications", modifications);
assertFalse("Empty modifications", modifications.isEmpty());
// TODO: more asserts
}
@Test
public void testProtectedStringObjectDelta() throws Exception {
System.out.println("===[ testProtectedStringObjectDelta ]====");
// GIVEN
ItemPath path = CREDENTIALS_PASSWORD_VALUE_PATH;
ProtectedStringType protectedString = new ProtectedStringType();
protectedString.setClearValue("abrakadabra");
ObjectDelta<UserType> objectDelta = ObjectDelta.createModificationReplaceProperty(UserType.class, "12345",
path, getPrismContext(), protectedString);
System.out.println("ObjectDelta");
System.out.println(objectDelta.debugDump());
// WHEN
ObjectDeltaType objectDeltaType = toObjectDeltaType(objectDelta);
// THEN
System.out.println("ObjectDeltaType (XML)");
System.out.println(PrismTestUtil.serializeAnyDataWrapped(objectDeltaType));
assertEquals("Wrong changetype", ChangeTypeType.MODIFY, objectDeltaType.getChangeType());
assertEquals("Wrong OID", "12345", objectDeltaType.getOid());
List<ItemDeltaType> modifications = objectDeltaType.getItemDelta();
assertNotNull("null modifications", modifications);
assertEquals("Wrong number of modifications", 1, modifications.size());
ItemDeltaType mod1 = modifications.iterator().next();
assertEquals("Wrong mod type", ModificationTypeType.REPLACE, mod1.getModificationType());
// XPathHolder xpath = new XPathHolder(mod1.getPath());
ItemPathType itemPathType = mod1.getPath();
assertNotNull("Wrong path (must not be null)", itemPathType);
assertEquals("Wrong path", path, itemPathType.getItemPath());
List<RawType> valueElements = mod1.getValue();
assertEquals("Wrong number of value elements", 1, valueElements.size());
RawType val = valueElements.get(0);
MapXNode valXNode = (MapXNode) val.serializeToXNode();
PrimitiveXNode clearValueNode = (PrimitiveXNode) valXNode.get(ProtectedStringType.F_CLEAR_VALUE);
val.getParsedValue(null, null);
// System.out.println("clear value " + clearValueNode);
assertEquals("Wrong element value", protectedString.getClearValue(), clearValueNode.getParsedValue(DOMUtil.XSD_STRING, String.class));
// List<Object> values = val.getContent();
// assertEquals("Wrong number of values", 1, values.size());
// JAXBElement<ProtectedStringType> valueElement = (JAXBElement<ProtectedStringType>)values.iterator().next();
//// assertEquals("Wrong element name", PasswordType.F_VALUE, valueElement.getName());
// assertEquals("Wrong element value", protectedString, valueElement.getValue());
}
@Test
public void testObjectDeltaRoundtrip() throws Exception {
System.out.println("===[ testObjectDeltaRoundtrip ]====");
// GIVEN
final String OID = "13235545";
final String VALUE = "Very Costly Center";
ObjectDelta<UserType> objectDelta = ObjectDelta.createModificationReplaceProperty(UserType.class, OID,
UserType.F_COST_CENTER, getPrismContext(), VALUE);
System.out.println("ObjectDelta");
System.out.println(objectDelta.debugDump());
// WHEN
ObjectDeltaType objectDeltaType = toObjectDeltaType(objectDelta);
// THEN
System.out.println("ObjectDeltaType (XML)");
// System.out.println(PrismTestUtil.marshalWrap(objectDeltaType));
assertEquals("Wrong changetype", ChangeTypeType.MODIFY, objectDeltaType.getChangeType());
assertEquals("Wrong OID", OID, objectDeltaType.getOid());
List<ItemDeltaType> modifications = objectDeltaType.getItemDelta();
assertNotNull("null modifications", modifications);
assertEquals("Wrong number of modifications", 1, modifications.size());
ItemDeltaType mod1 = modifications.iterator().next();
assertEquals("Wrong mod type", ModificationTypeType.REPLACE, mod1.getModificationType());
// XPathHolder xpath = new XPathHolder(mod1.getPath());
ItemPathType itemPathType = mod1.getPath();
assertNotNull("Wrong path (must not be null)", itemPathType);
// assertTrue("Wrong path: "+itemPathType, itemPathType.getItemPath().isEmpty());
PrismAsserts.assertPathEquivalent("Wrong path", itemPathType.getItemPath(), new ItemPath(UserType.F_COST_CENTER));
List<RawType> valueElements = mod1.getValue();
assertEquals("Wrong number of value elements", 1, valueElements.size());
RawType rawValue = valueElements.get(0);
// TODO check the raw value
// List<Object> values = rawValue.getContent();
// assertEquals("Wrong number of value elements", 1, values.size());
// System.out.println("value elements: " + valueElements);
// String valueElement = (String) values.iterator().next();
// assertEquals("Wrong element name", ItemDeltaType.F_VALUE, DOMUtil.getQName(valueElement));
// assertEquals("Wrong element value", VALUE, valueElement);
// WHEN
ObjectDelta<Objectable> objectDeltaRoundtrip = DeltaConvertor.createObjectDelta(objectDeltaType, getPrismContext());
// THEN
System.out.println("ObjectDelta (roundtrip)");
System.out.println(objectDelta.debugDump());
assertTrue("Roundtrip not equals", objectDelta.equals(objectDeltaRoundtrip));
// TODO: more checks
}
@Test(enabled = false)
public void testTaskExtensionDeleteDelta() throws Exception {
System.out.println("===[ testTaskExtensionDeleteDelta ]====");
// GIVEN
PrismObject oldTask = PrismTestUtil.parseObject(
new File(TEST_DIR, "task-old.xml"));
PrismObject newTask = PrismTestUtil.parseObject(
new File(TEST_DIR, "task-new.xml"));
ObjectDelta<TaskType> delta = oldTask.diff(newTask, true, true);
System.out.println("Delta:");
System.out.println(delta.debugDump());
final QName CUSTOM_OBJECT = new QName("http://delta.example.com", "object");
PrismContext context = getPrismContext();
// WHEN
ObjectDeltaType xmlDelta = toObjectDeltaType(delta);
// THEN
Map<String, Object> properties = new HashMap<String, Object>();
String result = PrismTestUtil.serializeJaxbElementToString(new JAXBElement<Object>(CUSTOM_OBJECT,
Object.class, xmlDelta));
assertNotNull(result);
}
@Test
public void testItemDeltaReplace() throws Exception {
System.out.println("===[ testItemDeltaReplace ]====");
// GIVEN
PrismObjectDefinition<UserType> userDef = getUserDefinition();
PropertyDelta<String> deltaBefore = PropertyDelta.createReplaceEmptyDelta(userDef, UserType.F_COST_CENTER);
deltaBefore.setValueToReplace(new PrismPropertyValue<String>("foo"));
// WHEN
Collection<ItemDeltaType> itemDeltaTypes = DeltaConvertor.toItemDeltaTypes(deltaBefore);
// THEN
System.out.println("Serialized");
System.out.println(itemDeltaTypes);
// WHEN
ItemDelta<?,?> deltaAfter = DeltaConvertor.createItemDelta(itemDeltaTypes.iterator().next(), userDef);
// THEN
System.out.println("Parsed");
System.out.println(deltaAfter.debugDump());
assertEquals("Deltas do not match", deltaBefore, deltaAfter);
assertNull(deltaAfter.getEstimatedOldValues());
}
@Test
public void testItemDeltaReplaceOldValue() throws Exception {
System.out.println("===[ testItemDeltaReplaceOldValue ]====");
// GIVEN
PrismObjectDefinition<UserType> userDef = getUserDefinition();
PropertyDelta<String> deltaBefore = PropertyDelta.createReplaceEmptyDelta(userDef, UserType.F_COST_CENTER);
deltaBefore.setValueToReplace(new PrismPropertyValue<String>("foo"));
deltaBefore.addEstimatedOldValue(new PrismPropertyValue<String>("BAR"));
// WHEN
Collection<ItemDeltaType> itemDeltaTypes = DeltaConvertor.toItemDeltaTypes(deltaBefore);
// THEN
System.out.println("Serialized");
System.out.println(itemDeltaTypes);
// WHEN
ItemDelta<?,?> deltaAfter = DeltaConvertor.createItemDelta(itemDeltaTypes.iterator().next(), userDef);
// THEN
System.out.println("Parsed");
System.out.println(deltaAfter.debugDump());
assertEquals("Deltas do not match", deltaBefore, deltaAfter);
PropertyDelta<String> propDeltaAfter = (PropertyDelta<String>)deltaAfter;
PrismAsserts.assertValues("Wrong old value", propDeltaAfter.getEstimatedOldValues(), "BAR");
}
@Test
public void testItemDeltaReplaceEmptyString() throws Exception {
System.out.println("===[ testItemDeltaReplaceEmptyString ]====");
// GIVEN
PrismObjectDefinition<UserType> userDef = getUserDefinition();
PropertyDelta<String> deltaBefore = PropertyDelta.createReplaceEmptyDelta(userDef, UserType.F_COST_CENTER);
// deltaBefore.setValueToReplace(new PrismPropertyValue<String>(""));
// WHEN
Collection<ItemDeltaType> itemDeltaTypes = DeltaConvertor.toItemDeltaTypes(deltaBefore);
// THEN
System.out.println("Serialized");
System.out.println(itemDeltaTypes);
// WHEN
ItemDelta<?,?> deltaAfter = DeltaConvertor.createItemDelta(itemDeltaTypes.iterator().next(), userDef);
// THEN
System.out.println("Parsed");
System.out.println(deltaAfter.debugDump());
assertEquals("Deltas do not match", deltaBefore, deltaAfter);
}
@Test
public void testItemDeltaReplaceNil() throws Exception {
System.out.println("===[ testItemDeltaReplaceNil ]====");
// GIVEN
PrismObjectDefinition<UserType> userDef = getUserDefinition();
PropertyDelta<String> deltaBefore = PropertyDelta.createReplaceEmptyDelta(userDef, UserType.F_COST_CENTER);
// The delta remains empty
// WHEN
Collection<ItemDeltaType> itemDeltaTypes = DeltaConvertor.toItemDeltaTypes(deltaBefore);
// THEN
System.out.println("Serialized");
System.out.println(itemDeltaTypes);
ItemDeltaType itemDeltaType = itemDeltaTypes.iterator().next();
String xml = PrismTestUtil.serializeAtomicValue(itemDeltaType, new QName("wherever","whatever"));
System.out.println(xml);
// WHEN
ItemDelta<?,?> deltaAfter = DeltaConvertor.createItemDelta(itemDeltaType, userDef);
// THEN
System.out.println("Parsed");
System.out.println(deltaAfter.debugDump());
assertEquals("Deltas do not match", deltaBefore, deltaAfter);
}
@Test
public void testModifyInducement() throws Exception {
System.out.println("===[ testModifyInducement ]====");
ObjectModificationType objectChange = PrismTestUtil.parseAtomicValue(new File(TEST_DIR, "role-modify-inducement.xml"),
ObjectModificationType.COMPLEX_TYPE);
// WHEN
ObjectDelta<RoleType> objectDelta = DeltaConvertor.createObjectDelta(objectChange, RoleType.class,
getPrismContext());
System.out.println("Delta:");
System.out.println(objectDelta.debugDump());
// THEN
assertNotNull("No object delta", objectDelta);
objectDelta.checkConsistence();
assertEquals("Wrong OID", "00000000-8888-6666-0000-100000000005", objectDelta.getOid());
ReferenceDelta targetRefDelta = objectDelta.findReferenceModification(new ItemPath(
new NameItemPathSegment(RoleType.F_INDUCEMENT),
new IdItemPathSegment(5L),
new NameItemPathSegment(AssignmentType.F_TARGET_REF)));
assertNotNull("No targetRef delta", targetRefDelta);
Collection<PrismReferenceValue> valuesToAdd = targetRefDelta.getValuesToAdd();
assertEquals("Wrong number of values to add", 1, valuesToAdd.size());
PrismReferenceValue targetRefVal = valuesToAdd.iterator().next();
assertNotNull("Null value in targetRef delta", targetRefVal);
assertEquals("wrong OID in targetRef", "12345678-d34d-b33f-f00d-987987987987", targetRefVal.getOid());
assertEquals("wrong target type in targetRef", RoleType.COMPLEX_TYPE, targetRefVal.getTargetType());
}
@Test
public void test100ObjectAdd() throws Exception {
System.out.println("===[ test100ObjectAdd ]====");
UserType user = new UserType(getPrismContext());
user.setName(PolyStringType.fromOrig("john"));
user.setOid("1234567890");
ObjectDelta delta = ObjectDelta.createAddDelta(user.asPrismObject());
roundTrip(delta);
}
@Test
public void test110ObjectModifyNone() throws Exception {
System.out.println("===[ test110ObjectModifyNone ]====");
ObjectDelta delta = DeltaBuilder.deltaFor(UserType.class, getPrismContext())
.asObjectDelta("123456");
roundTrip(delta);
}
@Test
public void test120ObjectModifyName() throws Exception {
System.out.println("===[ test120ObjectModifyName ]====");
ObjectDelta<?> delta = DeltaBuilder.deltaFor(UserType.class, getPrismContext())
.item(UserType.F_NAME).replace(PolyString.fromOrig("jack"))
.asObjectDelta("123456");
roundTrip(delta);
}
private void roundTrip(ObjectDelta delta) throws Exception {
ObjectDeltaType deltaType = DeltaConvertor.toObjectDeltaType(delta);
System.out.println("Serialized to bean");
System.out.println(deltaType);
String xml = getPrismContext().xmlSerializer().serializeRealValue(deltaType, new QName("aDelta"));
System.out.println("Serialized to XML");
System.out.println(xml);
ObjectDeltaType deltaTypeParsed = getPrismContext().parserFor(xml).parseRealValue();
System.out.println("Parsed from XML to bean");
System.out.println(deltaTypeParsed);
ObjectDelta deltaParsed = DeltaConvertor.createObjectDelta(deltaTypeParsed, getPrismContext());
System.out.println("Parsed from XML to bean to delta");
System.out.println(deltaParsed);
assertTrue("Deltas (native) do not match", delta.equivalent(deltaParsed));
// note: comparing beans is problematic because e.g. item paths are not equal ({common-3}name vs {c=common-3}c:name)
}
}