package com.sap.runlet.expressionpad.tests; import java.util.Iterator; import junit.framework.TestCase; import com.sap.ap.metamodel.utils.MetamodelUtils; import com.sap.runlet.abstractinterpreter.Side; import com.sap.runlet.abstractinterpreter.objects.ClassTypedObject; import com.sap.runlet.abstractinterpreter.objects.Link; import com.sap.runlet.abstractinterpreter.objects.RunletObject; import com.sap.runlet.abstractinterpreter.operationaltransformation.Change; import com.sap.runlet.abstractinterpreter.operationaltransformation.Transformer; import com.sap.runlet.abstractinterpreter.repository.ChangeSetImpl; import com.sap.runlet.abstractinterpreter.repository.EntityCreation; import com.sap.runlet.abstractinterpreter.repository.EntityDeletion; import com.sap.runlet.abstractinterpreter.repository.LinkChange; import com.sap.runlet.abstractinterpreter.repository.LinkCreation; import com.sap.runlet.abstractinterpreter.repository.LinkDeletion; import com.sap.runlet.abstractinterpreter.repository.RepositoryChange; import com.sap.runlet.abstractinterpreter.util.Fraction; import com.sap.runlet.expressionpad.RunletEvaluator; import com.sap.runlet.interpreter.Activator; import com.sap.runlet.interpreter.RunletInterpreter; import com.sap.runlet.interpreter.objects.NativeObject; import com.sap.runlet.interpreter.objects.ValueObject; import com.sap.runlet.interpreter.repository.simpleimpl.RunletInMemoryRepository; import com.sap.tc.moin.repository.Connection; import com.sap.tc.moin.repository.ModelPartition; import com.sap.tc.moin.repository.shared.util.Tuple.Pair; import com.sap.tc.moin.repository.shared.util.Tuple.Triple; import data.classes.Association; import data.classes.AssociationEnd; import data.classes.ClassTypeDefinition; import data.classes.SapClass; import data.classes.TypeDefinition; public class OperationalTransformationTest extends TestCase { protected RunletEvaluator main1; protected RunletEvaluator main2; private ClassTypeDefinition stringClassTypeDefinitionExactlyOneForMain1; private ClassTypeDefinition stringClassTypeDefinitionExactlyOneForMain2; private ClassTypeDefinition numberClassTypeDefinitionExactlyOneForMain1; private ClassTypeDefinition numberClassTypeDefinitionExactlyOneForMain2; protected void setUp() throws Exception { super.setUp(); RunletInMemoryRepository r = new RunletInMemoryRepository(Activator.getDefault().getModelAdapter()); main1 = new RunletEvaluator("ngpm.stdlib", r); main2 = new RunletEvaluator("ngpm.stdlib", r); stringClassTypeDefinitionExactlyOneForMain1 = MetamodelUtils.createClassTypeDefinitionExactlyOne(main1.getConnection(), MetamodelUtils.findClass(main1.getConnection(), "String")); stringClassTypeDefinitionExactlyOneForMain1.assign___PartitionIncludingChildren(getTransientPartition(main1 .getConnection())); stringClassTypeDefinitionExactlyOneForMain2 = MetamodelUtils.createClassTypeDefinitionExactlyOne(main2.getConnection(), MetamodelUtils.findClass(main1.getConnection(), "String")); stringClassTypeDefinitionExactlyOneForMain2.assign___PartitionIncludingChildren(getTransientPartition(main2 .getConnection())); numberClassTypeDefinitionExactlyOneForMain1 = MetamodelUtils.createClassTypeDefinitionExactlyOne(main1.getConnection(), MetamodelUtils.findClass(main1.getConnection(), "Number")); numberClassTypeDefinitionExactlyOneForMain1.assign___PartitionIncludingChildren(getTransientPartition(main1.getConnection())); numberClassTypeDefinitionExactlyOneForMain2 = MetamodelUtils.createClassTypeDefinitionExactlyOne(main2.getConnection(), MetamodelUtils.findClass(main2.getConnection(), "Number")); numberClassTypeDefinitionExactlyOneForMain2.assign___PartitionIncludingChildren(getTransientPartition(main2.getConnection())); } public void testNoChangesFromServerOrClient() { ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> cs1 = main1.getInterpreter().getTransactionBuffer().getChangeSetImpl(); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> cs2 = main2.getInterpreter().getTransactionBuffer().getChangeSetImpl(); Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> t = new Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(); Pair<Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>, Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>> p = t.transform(cs1, cs2); assertEquals(p.getA().totalSize(), 0); assertEquals(p.getB().totalSize(), 0); } public void testRedundantEntityDelete() throws Exception { RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>[] result1 = main1.execute("var p=new Person()", "store p", "commit").getResult(); assertEquals(3, result1.length); // delete person result1 = main1.execute("delete p").getResult(); assertEquals(1, result1.length); // redundant delete RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>[] result2 = main2.execute("var p = all Person", "delete p").getResult(); assertEquals(2, result2.length); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> cs1 = main1.getInterpreter().getTransactionBuffer().getChangeSetImpl(); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> cs2 = main2.getInterpreter().getTransactionBuffer().getChangeSetImpl(); Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> t = new Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(); Pair<Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>, Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>> p = t.transform(cs1, cs2); // both change lists should be empty as the delete is redundant assertEquals(p.getA().totalSize(), 0); assertEquals(p.getB().totalSize(), 0); } @SuppressWarnings("unchecked") public void testCreateTwoEntities() throws Exception { RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>[] result1 = main1.execute("var p=new Person()", "store p").getResult(); RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>[] result2 = main2.execute("var p=new Person()", "store p").getResult(); assertEquals(2, result1.length); assertEquals(2, result2.length); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> cs1 = main1.getInterpreter().getTransactionBuffer().getChangeSetImpl(); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> cs2 = main2.getInterpreter().getTransactionBuffer().getChangeSetImpl(); Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> t = new Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(); Pair<Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>, Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>> p = t.transform(cs1, cs2); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> serverResult = p.getB(); Triple<Class<?>, Integer, String>[] expectedServerResult = new Triple[] { new Triple<Class<?>, Integer, String>(EntityCreation.class, null, null) }; assertChanges(expectedServerResult, serverResult, Side.LEFT); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientResult = p.getA(); Triple<Class<?>, Integer, String>[] expectedClientResult = new Triple[] { new Triple<Class<?>, Integer, String>(EntityCreation.class, null, null) }; assertChanges(expectedClientResult, clientResult, Side.LEFT); } @SuppressWarnings("unchecked") public void testCreateLinkDeleteEntity() throws Exception { // create, store and commit a Person entity RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>[] result1 = main1.execute("var p=new Person()", "store p", "commit").getResult(); assertEquals(3, result1.length); // delete but do not commit Person entity result1 = main1.execute("delete p").getResult(); assertEquals(1, result1.length); // Create and store Organization Entity with new link created to Person entity RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>[] result2 = main2.execute("var o=new Organization()", "o.persons += all Person", "store o").getResult(); assertEquals(3, result2.length); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> cs1 = main1.getInterpreter().getTransactionBuffer().getChangeSetImpl(); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> cs2 = main2.getInterpreter().getTransactionBuffer().getChangeSetImpl(); Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> t = new Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(); Pair<Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>, Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>> p = t.transform(cs1, cs2); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> serverResult = p.getB(); Triple<Class<?>, Integer, String>[] expectedServerResult = new Triple[] { new Triple<Class<?>, Integer, String>(LinkDeletion.class, null, null), new Triple<Class<?>, Integer, String>(EntityDeletion.class, null, null) }; assertChanges(expectedServerResult, serverResult, Side.LEFT); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientResult = p.getA(); Triple<Class<?>, Integer, String>[] expectedClientResult = new Triple[] { new Triple<Class<?>, Integer, String>(EntityCreation.class, null, null) }; assertChanges(expectedClientResult, clientResult, Side.LEFT); } /** * In two separate change sets creates a link each to be added to an ordered association on the * same entity object on the unordered end. We expect that for client and server we get the same * ordering of links eventually. The server link should precede the client link consistently. */ @SuppressWarnings("unchecked") public void testCreateCompetingOrderedLinks() throws Exception { RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>[] result1 = main1.execute("var o=new OrderedAssocTest()", "store o", "commit").getResult(); assertEquals(3, result1.length); result1 = main1.execute("var p=new Person()", "p.name=\"name1\"", "store p", "all OrderedAssocTest.orderedPersons += p").getResult(); assertEquals(4, result1.length); // Create and store Organization Entity with new link created to Person entity // TODO: I assume that I see the changes commited by main1 (the Person). Not sure if this is the case. // The resulting changeSet for main2 only contains an Entity Creation but no link creation. Time is running out // need to check this after vacation ;) RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>[] result2 = main2.execute("var p=new Person()", "p.name=\"name2\"", "store p", "all OrderedAssocTest.orderedPersons += p").getResult(); assertEquals(4, result2.length); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> cs1 = main1.getInterpreter().getTransactionBuffer().getChangeSetImpl(); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> cs2 = main2.getInterpreter().getTransactionBuffer().getChangeSetImpl(); Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> t = new Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(); Pair<Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>, Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>> p = t.transform(cs1, cs2); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> serverResult = p.getB(); Triple<Class<?>, Integer, String>[] expectedServerResult = new Triple[] { new Triple<Class<?>, Integer, String>(EntityCreation.class, null, null), new Triple<Class<?>, Integer, String>(LinkCreation.class, null, null), new Triple<Class<?>, Integer, String>(LinkCreation.class, 1, null) }; assertChanges(expectedServerResult, serverResult, Side.LEFT); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientResult = p.getA(); Triple<Class<?>, Integer, String>[] expectedClientResult = new Triple[] { new Triple<Class<?>, Integer, String>(EntityCreation.class, null, null), new Triple<Class<?>, Integer, String>(LinkCreation.class, null, null), new Triple<Class<?>, Integer, String>(LinkCreation.class, 0, null) }; assertChanges(expectedClientResult, clientResult, Side.LEFT); } @SuppressWarnings("unchecked") public void testDeleteEntityAndAddOrderedLinks() throws Exception { // create, store and commit a Person and an OrderedAssocTest entity with ordered link between RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>[] result1 = main1.execute("var o=new OrderedAssocTest()", "store o", "var p=new Person()", "p.name=\"name1\"", "store p", "o.orderedPersons += p", "commit").getResult(); assertEquals(7, result1.length); result1 = main1.execute("delete p").getResult(); assertEquals(1, result1.length); // Create and store a second OrderedAssocTest and add a link to the first person being // deleted by the second change set on main1 (above). Then add a link to another new person p2. // This link creation should initially be recorded to be at second position (index 1) // but should then get re-numbered because the first link creation will be canceled. RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>[] result2 = main2.execute("var o=all OrderedAssocTest->iterate(i|i)", "var p=o.orderedPersons->iterate(j|j)", "var o2=new OrderedAssocTest()", "store o2", "o2.orderedPersons += p", "var p2=new Person()", "p2.name=\"name2\"", "store p2", "o2.orderedPersons += p2").getResult(); assertEquals(9, result2.length); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> cs1 = main1.getInterpreter().getTransactionBuffer().getChangeSetImpl(); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> cs2 = main2.getInterpreter().getTransactionBuffer().getChangeSetImpl(); Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> t = new Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(); Pair<Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>, Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>> p = t.transform(cs1, cs2); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> serverResult = p.getB(); Triple<Class<?>, Integer, String>[] expectedServerResult = new Triple[] { new Triple<Class<?>, Integer, String>(LinkDeletion.class, null, null), // p.name new Triple<Class<?>, Integer, String>(LinkDeletion.class, 0, null), // o.orderedPersons += p new Triple<Class<?>, Integer, String>(LinkDeletion.class, 0, null), // o2.orderedPersons += p new Triple<Class<?>, Integer, String>(EntityDeletion.class, null, null) }; assertChanges(expectedServerResult, serverResult, Side.LEFT); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientResult = p.getA(); Triple<Class<?>, Integer, String>[] expectedClientResult = new Triple[] { new Triple<Class<?>, Integer, String>(EntityCreation.class, null, null), // o2 new Triple<Class<?>, Integer, String>(EntityCreation.class, null, null), // p2 new Triple<Class<?>, Integer, String>(LinkCreation.class, null, null), // name2 new Triple<Class<?>, Integer, String>(LinkCreation.class, 0, null) // += p2 }; assertChanges(expectedClientResult, clientResult, Side.LEFT); } @SuppressWarnings("unchecked") // need array of generic Triple class public void testSpecificConcurrentChangesToOrderedAssociation() throws Exception { // create, store and commit a Person and an OrderedAssocTest entity with ordered link between RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>[] result1 = main1.execute("var o=new OrderedAssocTest()", "store o", "o.orderedStrings += \"a\"", "o.orderedStrings += \"b\"", "o.orderedStrings += \"c\"", "commit").getResult(); assertEquals(6, result1.length); RunletInterpreter i = (RunletInterpreter) main1.getInterpreter(); ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> o = (ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>) main1.getStackFrame().getAllVisibleVariableValues().get("o"); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientChanges = new ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(Activator.getDefault().getModelAdapter()); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, clientChanges, o, 1, "d"); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, clientChanges, o, 1, "e"); deleteOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, clientChanges, o, 3, "b"); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, clientChanges, o, 4, "f"); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> serverChanges = new ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(Activator.getDefault().getModelAdapter()); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, serverChanges, o, 3, "g"); deleteOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, serverChanges, o, 2, "c"); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, serverChanges, o, 2, "h"); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, serverChanges, o, 1, "i"); Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> t = new Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(); Pair<Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>, Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>> p = t.transform(clientChanges, serverChanges); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> serverResult = p.getB(); Triple<Class<?>, Integer, String>[] expectedServerResult = new Triple[] { new Triple<Class<?>, Integer, String>(LinkCreation.class, 2, "d"), new Triple<Class<?>, Integer, String>(LinkCreation.class, 2, "e"), new Triple<Class<?>, Integer, String>(LinkDeletion.class, 4, "b"), new Triple<Class<?>, Integer, String>(LinkCreation.class, 6, "f") }; assertChanges(expectedServerResult, serverResult, Side.LEFT); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientResult = p.getA(); Triple<Class<?>, Integer, String>[] expectedClientResult = new Triple[] { new Triple<Class<?>, Integer, String>(LinkCreation.class, 4, "g"), new Triple<Class<?>, Integer, String>(LinkDeletion.class, 3, "c"), new Triple<Class<?>, Integer, String>(LinkCreation.class, 3, "h"), new Triple<Class<?>, Integer, String>(LinkCreation.class, 1, "i") }; assertChanges(expectedClientResult, clientResult, Side.LEFT); } @SuppressWarnings("unchecked") // need array of generic Triple class public void testOrderedLinkCreationAndDeletion() throws Exception { // create, store and commit a Person and an OrderedAssocTest entity with ordered link between RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>[] result1 = main1.execute("var o=new OrderedAssocTest()", "store o", "o.orderedStrings += \"a\"", "o.orderedStrings += \"b\"", "o.orderedStrings += \"c\"", "commit").getResult(); assertEquals(6, result1.length); RunletInterpreter i = (RunletInterpreter) main1.getInterpreter(); ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> o = (ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>) main1.getStackFrame().getAllVisibleVariableValues().get("o"); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientChanges = new ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(Activator.getDefault().getModelAdapter()); deleteOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, clientChanges, o, 0, "a"); deleteOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, clientChanges, o, 0, "b"); deleteOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, clientChanges, o, 0, "c"); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> serverChanges = new ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(Activator.getDefault().getModelAdapter()); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, serverChanges, o, 0, "h"); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, serverChanges, o, 2, "o"); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, serverChanges, o, 2, "l"); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, serverChanges, o, 2, "l"); Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> t = new Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(); Pair<Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>, Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>> p = t.transform(clientChanges, serverChanges); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> serverResult = p.getB(); Triple<Class<?>, Integer, String>[] expectedServerResult = new Triple[] { new Triple<Class<?>, Integer, String>(LinkDeletion.class, 1, "a"), new Triple<Class<?>, Integer, String>(LinkDeletion.class, 4, "b"), new Triple<Class<?>, Integer, String>(LinkDeletion.class, 4, "c") }; assertChanges(expectedServerResult, serverResult, Side.LEFT); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientResult = p.getA(); Triple<Class<?>, Integer, String>[] expectedClientResult = new Triple[] { new Triple<Class<?>, Integer, String>(LinkCreation.class, 0, "h"), new Triple<Class<?>, Integer, String>(LinkCreation.class, 1, "o"), new Triple<Class<?>, Integer, String>(LinkCreation.class, 1, "l"), new Triple<Class<?>, Integer, String>(LinkCreation.class, 1, "l") }; assertChanges(expectedClientResult, clientResult, Side.LEFT); } @SuppressWarnings("unchecked") // need array of generic Triple class public void testOrderedLinkCreationAndDeletion2() throws Exception { // create, store and commit a Person and an OrderedAssocTest entity with ordered link between RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>[] result1 = main1.execute("var o=new OrderedAssocTest()", "store o", "o.orderedStrings += \"a\"", "commit").getResult(); assertEquals(4, result1.length); RunletInterpreter i = (RunletInterpreter) main1.getInterpreter(); ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> o = (ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>) main1.getStackFrame().getAllVisibleVariableValues().get("o"); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientChanges = new ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(Activator.getDefault().getModelAdapter()); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, clientChanges, o, 0, "b"); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, clientChanges, o, 1, "c"); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, clientChanges, o, 3, "d"); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, clientChanges, o, 4, "e"); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> serverChanges = new ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(Activator.getDefault().getModelAdapter()); deleteOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, serverChanges, o, 0, "a"); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, serverChanges, o, 0, "f"); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, serverChanges, o, 1, "g"); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, serverChanges, o, 2, "h"); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, serverChanges, o, 3, "i"); Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> t = new Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(); Pair<Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>, Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>> p = t.transform(clientChanges, serverChanges); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> serverResult = p.getB(); Triple<Class<?>, Integer, String>[] expectedServerResult = new Triple[] { new Triple<Class<?>, Integer, String>(LinkCreation.class, 4, "b"), new Triple<Class<?>, Integer, String>(LinkCreation.class, 5, "c"), new Triple<Class<?>, Integer, String>(LinkCreation.class, 6, "d"), new Triple<Class<?>, Integer, String>(LinkCreation.class, 7, "e") }; assertChanges(expectedServerResult, serverResult, Side.LEFT); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientResult = p.getA(); Triple<Class<?>, Integer, String>[] expectedClientResult = new Triple[] { new Triple<Class<?>, Integer, String>(LinkDeletion.class, 2, "a"), new Triple<Class<?>, Integer, String>(LinkCreation.class, 0, "f"), new Triple<Class<?>, Integer, String>(LinkCreation.class, 1, "g"), new Triple<Class<?>, Integer, String>(LinkCreation.class, 2, "h"), new Triple<Class<?>, Integer, String>(LinkCreation.class, 3, "i") }; assertChanges(expectedClientResult, clientResult, Side.LEFT); } @SuppressWarnings("unchecked") // need array of generic Triple class public void testOrderedLinkCreationAndDeletion3() throws Exception { // create, store and commit a Person and an OrderedAssocTest entity with ordered link between RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>[] result1 = main1.execute("var o=new OrderedAssocTest()", "store o", "o.orderedStrings += \"a\"", "commit").getResult(); assertEquals(4, result1.length); RunletInterpreter i = (RunletInterpreter) main1.getInterpreter(); ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> o = (ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>) main1.getStackFrame().getAllVisibleVariableValues().get("o"); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientChanges = new ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(Activator.getDefault().getModelAdapter()); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, clientChanges, o, 0, "b"); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, clientChanges, o, 1, "c"); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, clientChanges, o, 3, "d"); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, clientChanges, o, 4, "e"); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> serverChanges = new ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(Activator.getDefault().getModelAdapter()); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, serverChanges, o, 0, "f"); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, serverChanges, o, 1, "g"); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, serverChanges, o, 3, "h"); addOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, serverChanges, o, 4, "i"); deleteOrderedLinkToString(i, stringClassTypeDefinitionExactlyOneForMain1, serverChanges, o, 2, "a"); Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> t = new Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(); Pair<Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>, Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>> p = t.transform(clientChanges, serverChanges); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> serverResult = p.getB(); Triple<Class<?>, Integer, String>[] expectedServerResult = new Triple[] { new Triple<Class<?>, Integer, String>(LinkCreation.class, 2, "b"), new Triple<Class<?>, Integer, String>(LinkCreation.class, 3, "c"), new Triple<Class<?>, Integer, String>(LinkCreation.class, 6, "d"), new Triple<Class<?>, Integer, String>(LinkCreation.class, 7, "e") }; assertChanges(expectedServerResult, serverResult, Side.LEFT); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientResult = p.getA(); Triple<Class<?>, Integer, String>[] expectedClientResult = new Triple[] { new Triple<Class<?>, Integer, String>(LinkCreation.class, 0, "f"), new Triple<Class<?>, Integer, String>(LinkCreation.class, 1, "g"), new Triple<Class<?>, Integer, String>(LinkCreation.class, 5, "h"), new Triple<Class<?>, Integer, String>(LinkCreation.class, 6, "i"), new Triple<Class<?>, Integer, String>(LinkDeletion.class, 4, "a") }; assertChanges(expectedClientResult, clientResult, Side.LEFT); } @SuppressWarnings("unchecked") // need array of generic Triple class public void testUniqueLinkCreation() throws Exception { // create, store and commit a Person and an UniquenessTest entity with ordered link between RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>[] result = main1.execute("var u=new UniquenessTest()", "store u", "u.numbers += 1", "u.numbers += 2", "u.numbers += 3", "commit").getResult(); assertEquals(6, result.length); RunletInterpreter i = (RunletInterpreter) main1.getInterpreter(); ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> u = (ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>) main1.getStackFrame().getAllVisibleVariableValues().get("u"); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientChanges = new ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(Activator.getDefault().getModelAdapter()); addUniqueLinkToNumber(i, numberClassTypeDefinitionExactlyOneForMain1, clientChanges, u, new Fraction(4)); addUniqueLinkToNumber(i, numberClassTypeDefinitionExactlyOneForMain1, clientChanges, u, new Fraction(5)); addUniqueLinkToNumber(i, numberClassTypeDefinitionExactlyOneForMain1, clientChanges, u, new Fraction(6)); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> serverChanges = new ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(Activator.getDefault().getModelAdapter()); addUniqueLinkToNumber(i, numberClassTypeDefinitionExactlyOneForMain2, serverChanges, u, new Fraction(7)); addUniqueLinkToNumber(i, numberClassTypeDefinitionExactlyOneForMain2, serverChanges, u, new Fraction(8)); addUniqueLinkToNumber(i, numberClassTypeDefinitionExactlyOneForMain2, serverChanges, u, new Fraction(9)); Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> t = new Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(); Pair<Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>, Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>> p = t.transform(clientChanges, serverChanges); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> serverResult = p.getB(); Triple<Class<?>, Integer, String>[] expectedServerResult = new Triple[] { new Triple<Class<?>, Fraction, Fraction>(LinkCreation.class, null, new Fraction(4)), new Triple<Class<?>, Fraction, Fraction>(LinkCreation.class, null, new Fraction(5)), new Triple<Class<?>, Fraction, Fraction>(LinkCreation.class, null, new Fraction(6)) }; assertChanges(expectedServerResult, serverResult, Side.LEFT); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientResult = p.getA(); Triple<Class<?>, Integer, String>[] expectedClientResult = new Triple[] { new Triple<Class<?>, Fraction, Fraction>(LinkCreation.class, null, new Fraction(7)), new Triple<Class<?>, Fraction, Fraction>(LinkCreation.class, null, new Fraction(8)), new Triple<Class<?>, Fraction, Fraction>(LinkCreation.class, null, new Fraction(9)) }; assertChanges(expectedClientResult, clientResult, Side.LEFT); } @SuppressWarnings("unchecked") // need array of generic Triple class public void testRedundantUniqueLinkCreation() throws Exception { // create, store and commit a Person and an UniquenessTest entity with ordered link between RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>[] result = main1.execute("var u=new UniquenessTest()", "store u", "u.numbers += 1", "u.numbers += 2", "u.numbers += 3", "commit").getResult(); assertEquals(6, result.length); RunletInterpreter i = (RunletInterpreter) main1.getInterpreter(); ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> u = (ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>) main1.getStackFrame().getAllVisibleVariableValues().get("u"); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientChanges = new ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(Activator.getDefault().getModelAdapter()); addUniqueLinkToNumber(i, numberClassTypeDefinitionExactlyOneForMain1, clientChanges, u, new Fraction(4)); addUniqueLinkToNumber(i, numberClassTypeDefinitionExactlyOneForMain1, clientChanges, u, new Fraction(5)); addUniqueLinkToNumber(i, numberClassTypeDefinitionExactlyOneForMain1, clientChanges, u, new Fraction(6)); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> serverChanges = new ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(Activator.getDefault().getModelAdapter()); addUniqueLinkToNumber(i, numberClassTypeDefinitionExactlyOneForMain2, serverChanges, u, new Fraction(4)); addUniqueLinkToNumber(i, numberClassTypeDefinitionExactlyOneForMain2, serverChanges, u, new Fraction(8)); addUniqueLinkToNumber(i, numberClassTypeDefinitionExactlyOneForMain2, serverChanges, u, new Fraction(9)); Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> t = new Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(); Pair<Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>, Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>> p = t.transform(clientChanges, serverChanges); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> serverResult = p.getB(); Triple<Class<?>, Integer, String>[] expectedServerResult = new Triple[] { new Triple<Class<?>, Fraction, Fraction>(LinkCreation.class, null, new Fraction(5)), new Triple<Class<?>, Fraction, Fraction>(LinkCreation.class, null, new Fraction(6)) }; assertChanges(expectedServerResult, serverResult, Side.LEFT); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientResult = p.getA(); Triple<Class<?>, Integer, String>[] expectedClientResult = new Triple[] { new Triple<Class<?>, Fraction, Fraction>(LinkCreation.class, null, new Fraction(8)), new Triple<Class<?>, Fraction, Fraction>(LinkCreation.class, null, new Fraction(9)) }; assertChanges(expectedClientResult, clientResult, Side.LEFT); } @SuppressWarnings("unchecked") // need array of generic Triple class public void testRedundantUniqueLinkDeletion() throws Exception { // create, store and commit a Person and an UniquenessTest entity with ordered link between RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>[] result = main1.execute("var u=new UniquenessTest()", "store u", "u.numbers += 1", "u.numbers += 2", "u.numbers += 3", "commit").getResult(); assertEquals(6, result.length); RunletInterpreter i = (RunletInterpreter) main1.getInterpreter(); ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> u = (ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>) main1.getStackFrame().getAllVisibleVariableValues().get("u"); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientChanges = new ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(Activator.getDefault().getModelAdapter()); deleteUniqueLinkToNumber(i, numberClassTypeDefinitionExactlyOneForMain1, clientChanges, u, new Fraction(3)); addUniqueLinkToNumber(i, numberClassTypeDefinitionExactlyOneForMain1, clientChanges, u, new Fraction(4)); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> serverChanges = new ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(Activator.getDefault().getModelAdapter()); deleteUniqueLinkToNumber(i, numberClassTypeDefinitionExactlyOneForMain2, serverChanges, u, new Fraction(3)); addUniqueLinkToNumber(i, numberClassTypeDefinitionExactlyOneForMain2, serverChanges, u, new Fraction(5)); Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> t = new Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(); Pair<Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>, Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>> p = t.transform(clientChanges, serverChanges); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> serverResult = p.getB(); Triple<Class<?>, Integer, String>[] expectedServerResult = new Triple[] { new Triple<Class<?>, Fraction, Fraction>(LinkCreation.class, null, new Fraction(4)) }; assertChanges(expectedServerResult, serverResult, Side.LEFT); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientResult = p.getA(); Triple<Class<?>, Integer, String>[] expectedClientResult = new Triple[] { new Triple<Class<?>, Fraction, Fraction>(LinkCreation.class, null, new Fraction(5)) }; assertChanges(expectedClientResult, clientResult, Side.LEFT); } @SuppressWarnings("unchecked") // need array of generic Triple class public void testRedundantLinkDeletion() throws Exception { // create, store and commit a Person and an OrderedAssocTest entity with ordered link between RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>[] result1 = main1.execute("var o=new Organization()", "store o", "o.persons += new Person()", "commit").getResult(); assertEquals(4, result1.length); result1 = main1.execute("var p=all Person->iterate(i|i)", "delete p").getResult(); assertEquals(2, result1.length); // Create and store a second OrderedAssocTest and add a link to the first person being // deleted by the second change set on main1 (above). Then add a link to another new person p2. // This link creation should initially be recorded to be at second position (index 1) // but should then get re-numbered because the first link creation will be canceled. RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>[] result2 = main2.execute("var o=all Organization->iterate(i|i)", "delete o").getResult(); assertEquals(2, result2.length); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> cs1 = main1.getInterpreter().getTransactionBuffer().getChangeSetImpl(); ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> cs2 = main2.getInterpreter().getTransactionBuffer().getChangeSetImpl(); Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> t = new Transformer<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(); Pair<Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>, Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>> p = t.transform(cs1, cs2); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> serverResult = p.getB(); Triple<Class<?>, Integer, String>[] expectedServerResult = new Triple[] { new Triple<Class<?>, Integer, String>(EntityDeletion.class, null, null) }; assertChanges(expectedServerResult, serverResult, Side.LEFT); Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientResult = p.getA(); Triple<Class<?>, Integer, String>[] expectedClientResult = new Triple[] { new Triple<Class<?>, Integer, String>(EntityDeletion.class, null, null) }; assertChanges(expectedClientResult, clientResult, Side.LEFT); } public void testSnapshortMerge() throws Exception { RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>[] serverResult = null; RunletObject<AssociationEnd, TypeDefinition, ClassTypeDefinition>[] clientResult = null; // create a Person entity in server session and commit creation serverResult = main1.execute("var p1=new Person()", "store p1", "commit").getResult(); assertEquals(3, serverResult.length); // create a 2nd Person entity in server session, no commit yet serverResult = main1.execute("var p2=new Person()", "store p2").getResult(); assertEquals(2, serverResult.length); // create a 3rd Person entity in client session, no commit yet clientResult = main2.execute("var p3=new Person()", "store p3").getResult(); assertEquals(2, clientResult.length); // commit server session serverResult = main1.execute("commit").getResult(); assertEquals(1, serverResult.length); // commit client session clientResult = main2.execute("commit").getResult(); assertEquals(1, clientResult.length); // server session should see three person entities serverResult = main1.execute("all Person.count").getResult(); assertEquals(1, serverResult.length); // client session should see three person entities clientResult = main2.execute("all Person.count").getResult(); assertEquals(1, clientResult.length); } /** * If a link change is expected and a non-<tt>null</tt> String is provided in the expected * results, that string is compared with the value on the ordered end of the link. */ private void assertChanges(Triple<Class<?>, Integer, String>[] expectedClientResult, Change<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> changeSetToCheck, Side side) { Iterator<RepositoryChange<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>> iter = changeSetToCheck.iterator(); for (int i=0; i<expectedClientResult.length; i++) { if (!iter.hasNext()) { fail("change set "+changeSetToCheck+" contains fewer (only "+i+") than the expected "+ expectedClientResult.length+" changes"); } RepositoryChange<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> change = iter.next(); assertEquals("Class " + change.getClass().getName() + " for " + (i + 1) + getOrdinalSuffix(i + 1) + " change does not match expected class " + expectedClientResult[i].getA().getName(), expectedClientResult[i].getA(), change.getClass()); // further checks for link creation if (change instanceof LinkCreation<?, ?, ?, ?, ?>) { // do check for value if (expectedClientResult[i].getC() != null) { Object objectOnLink = ((NativeObject) ((LinkChange<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>) change).getObject().get(side)).getNativeObject(); assertEquals("value mismatch for " + (i + 1) + getOrdinalSuffix(i + 1) + " change", expectedClientResult[i].getC(), objectOnLink); } // do check for position if (expectedClientResult[i].getB() != null) { assertEquals("position mismatch for " + (i + 1) + getOrdinalSuffix(i + 1) + " change", expectedClientResult[i].getB(), ((LinkChange<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>) change).getPosition()); } } } } private String getOrdinalSuffix(int i) { if (i==1) { return "st"; } else if (i==2) { return "nd"; } else if (i==3) { return "rd"; } else { return "th"; } } private void deleteOrderedLinkToString(RunletInterpreter interpreter, ClassTypeDefinition stringClassTypeDefinition, ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientChanges, ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> o, int at, String string) { ValueObject stringAsValueObject = new NativeObject(stringClassTypeDefinition, string, interpreter.getDefaultSnapshot(), interpreter); SapClass oat = MetamodelUtils.findClass(interpreter.getConnection(), "OrderedAssocTest"); Association a = null; for (AssociationEnd ae : oat.getAssociationEnds()) { if (ae.otherEnd().getName().equals("orderedStrings")) { a = ae.getAssociation(); } } if (a == null) { throw new RuntimeException("Couldn't find association for association end \"orderedStrings\" on class OrderedAssocTest"); } Link<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> l = new Link<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(stringAsValueObject, o, a, interpreter.getDefaultSnapshot(), interpreter.getModelAdapter()); clientChanges.linkDeleted(l, at); } private void addOrderedLinkToString(RunletInterpreter interpreter, ClassTypeDefinition stringClassTypeDefinition, ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientChanges, ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> o, int at, String string) { ValueObject stringAsValueObject = new NativeObject(stringClassTypeDefinition, string, interpreter.getDefaultSnapshot(), interpreter); SapClass oat = MetamodelUtils.findClass(interpreter.getConnection(), "OrderedAssocTest"); Association a = null; for (AssociationEnd ae : oat.getAssociationEnds()) { if (ae.otherEnd().getName().equals("orderedStrings")) { a = ae.getAssociation(); } } if (a == null) { throw new RuntimeException("Couldn't find association for association end \"orderedStrings\" on class OrderedAssocTest"); } Link<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> l = new Link<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(stringAsValueObject, o, a, interpreter.getDefaultSnapshot(), interpreter.getModelAdapter()); clientChanges.linkCreated(l, at); } private void addUniqueLinkToNumber(RunletInterpreter interpreter, ClassTypeDefinition numberClassTypeDefinition, ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientChanges, ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> o, Fraction number) { ValueObject numberAsValueObject = new NativeObject(numberClassTypeDefinition, number, interpreter.getDefaultSnapshot(), interpreter); SapClass ut = MetamodelUtils.findClass(interpreter.getConnection(), "UniquenessTest"); Association a = null; for (AssociationEnd ae : ut.getAssociationEnds()) { if (ae.otherEnd().getName().equals("numbers")) { a = ae.getAssociation(); } } if (a == null) { throw new RuntimeException("Couldn't find association for association end \"numbers\" on class UniquenessTest"); } Link<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> l = new Link<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(numberAsValueObject, o, a, interpreter.getDefaultSnapshot(), interpreter.getModelAdapter()); clientChanges.linkCreated(l, null); } private void deleteUniqueLinkToNumber(RunletInterpreter interpreter, ClassTypeDefinition numberClassTypeDefinition, ChangeSetImpl<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> clientChanges, ClassTypedObject<AssociationEnd, TypeDefinition, ClassTypeDefinition> o, Fraction n) { ValueObject numberAsValueObject = new NativeObject(numberClassTypeDefinition, n, interpreter.getDefaultSnapshot(), interpreter); SapClass oat = MetamodelUtils.findClass(interpreter.getConnection(), "UniquenessTest"); Association a = null; for (AssociationEnd ae : oat.getAssociationEnds()) { if (ae.otherEnd().getName().equals("numbers")) { a = ae.getAssociation(); } } if (a == null) { throw new RuntimeException("Couldn't find association for association end \"numbers\" on class UniquenessTest"); } Link<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition> l = new Link<Association, AssociationEnd, SapClass, TypeDefinition, ClassTypeDefinition>(numberAsValueObject, o, a, interpreter.getDefaultSnapshot(), interpreter.getModelAdapter()); clientChanges.linkDeleted(l, null); } private ModelPartition getTransientPartition(Connection conn) { return conn.getOrCreateTransientPartition("OperationalTransformationTest_"+Thread.currentThread().getId()); } }