/** * GRANITE DATA SERVICES * Copyright (C) 2006-2015 GRANITE DATA SERVICES S.A.S. * * This file is part of the Granite Data Services Platform. * * *** * * Community License: GPL 3.0 * * This file is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * This file is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * *** * * Available Commercial License: GraniteDS SLA 1.0 * * This is the appropriate option if you are creating proprietary * applications and you are not prepared to distribute and share the * source code of your application under the GPL v3 license. * * Please visit http://www.granitedataservices.com/license for more * details. */ package org.granite.client.test.javafx.tide; import static org.granite.client.tide.data.EntityManager.UpdateKind.PERSIST; import static org.granite.client.tide.data.EntityManager.UpdateKind.REMOVE; import static org.granite.client.tide.data.EntityManager.UpdateKind.UPDATE; import static org.granite.client.tide.data.PersistenceManager.getEntityManager; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.granite.client.javafx.platform.JavaFXReflection; import org.granite.client.javafx.tide.JavaFXApplication; import org.granite.client.messaging.RemoteAlias; import org.granite.client.messaging.jmf.ClientSharedContext; import org.granite.client.messaging.jmf.DefaultClientSharedContext; import org.granite.client.messaging.jmf.ext.ClientEntityCodec; import org.granite.client.persistence.collection.PersistentCollection; import org.granite.client.test.tide.MockChannelFactory; import org.granite.client.test.tide.MockInstanceStoreFactory; import org.granite.client.tide.Context; import org.granite.client.tide.data.ChangeMerger; import org.granite.client.tide.data.ChangeSetBuilder; import org.granite.client.tide.data.Conflicts; import org.granite.client.tide.data.DataConflictListener; import org.granite.client.tide.data.EntityManager; import org.granite.client.tide.data.spi.DataManager; import org.granite.client.tide.data.spi.MergeContext; import org.granite.client.tide.impl.SimpleContextManager; import org.granite.client.tide.server.ServerSession; import org.granite.messaging.jmf.DefaultCodecRegistry; import org.granite.messaging.jmf.JMFDeserializer; import org.granite.messaging.jmf.JMFSerializer; import org.granite.messaging.jmf.codec.ExtendedObjectCodec; import org.granite.messaging.reflect.Reflection; import org.granite.tide.data.Change; import org.granite.tide.data.ChangeRef; import org.granite.tide.data.ChangeSet; import org.granite.tide.data.CollectionChange; import org.granite.tide.data.CollectionChanges; import org.granite.util.JMFAMFUtil; import org.junit.Assert; import org.junit.Before; import org.junit.Test; public class TestApplyRemoteChange { private SimpleContextManager contextManager; private Context ctx; private ServerSession serverSession; private DataManager dataManager; private EntityManager entityManager; private ClientSharedContext clientSharedContext; @Before public void setup() throws Exception { contextManager = new SimpleContextManager(new JavaFXApplication()); contextManager.setInstanceStoreFactory(new MockInstanceStoreFactory()); ctx = contextManager.getContext(""); serverSession = new ServerSession("/test", "localhost", 8080); serverSession.setChannelFactoryClass(MockChannelFactory.class); serverSession.setRemoteAliasPackages(Collections.singleton(Person.class.getPackage().getName())); ctx.set(serverSession); entityManager = ctx.getEntityManager(); dataManager = ctx.getDataManager(); ctx.set(new ChangeMerger()); serverSession.start(); List<ExtendedObjectCodec> clientExtendedCodecs = new ArrayList<ExtendedObjectCodec>(Arrays.asList(new ClientEntityCodec())); List<String> defaultStoredStrings = new ArrayList<String>(JMFAMFUtil.AMF_DEFAULT_STORED_STRINGS); Reflection clientReflection = new JavaFXReflection(getClass().getClassLoader()); clientSharedContext = new DefaultClientSharedContext(new DefaultCodecRegistry(clientExtendedCodecs), defaultStoredStrings, clientReflection, serverSession.getAliasRegistry()); } private static String personAlias = Person.class.getAnnotation(RemoteAlias.class).value(); private static String patientAlias = Patient3.class.getAnnotation(RemoteAlias.class).value(); private static String visitAlias = Visit.class.getAnnotation(RemoteAlias.class).value(); @SuppressWarnings("cast") @Test public void testApplyRemoteChange1() { Person person = new Person(1L, 0L, "P1", null, "Test"); person = (Person)entityManager.mergeExternalData(person); entityManager.clearCache(); Change change = new Change(personAlias, 1L, 1L, "P1"); change.getChanges().put("lastName", "Toto"); MergeContext mergeContext = entityManager.initMerge(serverSession); entityManager.handleUpdates(mergeContext, null, Collections.singletonList(UPDATE.of(new ChangeSet(change)))); Assert.assertEquals("Last name changed", "Toto", person.getLastName()); Assert.assertEquals("Version increased", Long.valueOf(1), person.getVersion()); Person person0 = new Person(1L, false, "__ds__"); Contact contact = new Contact(1L, 0L, "C1", person0, "toto@toto.net"); change = new Change(personAlias, 1L, 2L, "P1"); change.addCollectionChanges("contacts", new CollectionChange(1, null, contact)); entityManager.handleUpdates(mergeContext, null, Collections.singletonList(UPDATE.of(new ChangeSet(change)))); Assert.assertEquals("Contact added", 1, person.getContacts().size()); Assert.assertTrue("Contact", person.getContacts().get(0) instanceof Contact); Assert.assertSame("Contact em", entityManager, getEntityManager(person.getContact(0))); Assert.assertEquals("Version increased", Long.valueOf(2), person.getVersion()); Person person1 = new Person(1L, 3L, "P1", null, null); ((PersistentCollection<?>)person1.getContacts()).uninitialize(); Contact contact2 = new Contact(2L, 0L, "C2", person1, "tutu@tutu.net"); change = new Change(personAlias, 1L, 3L, "P1"); change.addCollectionChanges("contacts", new CollectionChange(1, null, contact2)); entityManager.handleUpdates(mergeContext, null, Collections.singletonList(UPDATE.of(new ChangeSet(change)))); Assert.assertEquals("Contact added", 2, person.getContacts().size()); Assert.assertSame("Contact attached", person, person.getContacts().get(1).getPerson()); Assert.assertSame("Person em", entityManager, getEntityManager(person)); Assert.assertSame("Contact em", entityManager, getEntityManager(person.getContacts().get(1))); } @SuppressWarnings("cast") @Test public void testApplyRemoteChange2() { Person person = new Person(1L, 0L, "P1", null, "Test"); Contact contact1 = new Contact(1L, 0L, "C1", person, "toto@toto.net"); person.getContacts().add(contact1); person = (Person)entityManager.mergeExternalData(person); entityManager.clearCache(); Contact contact2 = new Contact(null, null, "C2", person, "toto2@toto.net"); person.getContacts().add(contact2); Person personb = new Person(person.getId(), false, "__ds__"); Contact contact2b = new Contact(2L, 0L, "C2", personb, "toto2@toto.net"); Change change1 = new Change(personAlias, person.getId(), 0L, person.getUid()); change1.addCollectionChanges("contacts", new CollectionChange(1, null, contact2b)); Person personc = new Person(person.getId(), 0L, person.getUid(), null, "Test"); Contact contact1c = new Contact(1L, 0L, "C1", personc, "toto@toto.net"); personc.getContacts().add(contact1c); Contact contact2c = new Contact(2L, 0L, "C2", personc, "toto2@toto.net"); personc.getContacts().add(contact2c); Change change2 = new Change(personAlias, person.getId(), 0L, person.getUid()); change2.addCollectionChanges("contacts", new CollectionChange(1, null, contact2c)); MergeContext mergeContext = entityManager.initMerge(serverSession); entityManager.handleUpdates(mergeContext, null, Arrays.asList(UPDATE.of(new ChangeSet(change1)), UPDATE.of(new ChangeSet(change2)))); Assert.assertSame("Person em", entityManager, getEntityManager(person)); Assert.assertEquals("Contact added", 2, person.getContacts().size()); Assert.assertTrue("Contact", person.getContacts().get(0) instanceof Contact); Assert.assertFalse("Context not dirty", dataManager.isDirty()); person.getContacts().remove(1); Assert.assertTrue("Context dirty", dataManager.isDirty()); } @SuppressWarnings("cast") @Test public void testApplyRemoteChange3() { Person person = new Person(1L, 0L, "P1", null, "Test"); Contact contact1 = new Contact(1L, 0L, "C1", person, "toto@toto.net"); person.addContact(contact1); person = (Person)entityManager.mergeExternalData(person); entityManager.clearCache(); Contact contact2 = new Contact(null, null, "C2", person, "toto2@toto.net"); person.addContact(contact2); Person personb = new Person(person.getId(), person.getVersion(), person.getUid(), null, null); ((PersistentCollection<?>)personb.getContacts()).uninitialize(); Contact contact2b = new Contact(2L, 0L, "C2", personb, "toto2@toto.net"); Change change = new Change(personAlias, person.getId(), 0L, person.getUid()); change.addCollectionChanges("contacts", new CollectionChange(1, null, contact2b)); MergeContext mergeContext = entityManager.initMerge(serverSession); entityManager.handleUpdates(mergeContext, null, Collections.singletonList(UPDATE.of(new ChangeSet(change)))); Assert.assertSame("Person em", entityManager, getEntityManager(person)); Assert.assertEquals("Contact added", 2, person.getContacts().size()); Assert.assertTrue("Contact", person.getContacts().get(0) instanceof Contact); Assert.assertEquals("Contact id", contact2b.getId(), person.getContacts().get(1).getId()); } @Test public void testApplyRemoteChangeLazy() { Person person = new Person(1L, 0L, "P1", null, "Test"); ((PersistentCollection<?>)person.getContacts()).uninitialize(); person = (Person)entityManager.mergeExternalData(person); entityManager.clearCache(); Person personb = new Person(person.getId(), person.getVersion(), person.getUid(), null, "Test"); ((PersistentCollection<?>)personb.getContacts()).uninitialize(); Contact contact2b = new Contact(2L, 0L, "C2", personb, "toto2@toto.net"); Change change = new Change(personAlias, person.getId(), 0L, person.getUid()); change.addCollectionChanges("contacts", new CollectionChange(1, null, contact2b)); MergeContext mergeContext = entityManager.initMerge(serverSession); entityManager.handleUpdates(mergeContext, null, Collections.singletonList(UPDATE.of(new ChangeSet(change)))); Assert.assertSame("Person em", entityManager, getEntityManager(person)); Assert.assertFalse("Contacts uninitialized", ((PersistentCollection<?>)person.getContacts()).wasInitialized()); } @Test public void testApplyRemoteChangeSet() { Patient3 patient = new Patient3(1L, 0L, "P1", "Test"); Visit visit = new Visit(1L, 0L, "V1", patient, "Test"); patient.getVisits().add(visit); VisitTest test1 = new VisitTest(1L, 0L, "T1", patient, visit, "Test"); patient.getTests().add(test1); visit.getTests().add(test1); patient = (Patient3)entityManager.mergeExternalData(patient); entityManager.clearCache(); VisitTest test2 = new VisitTest(null, null, "T2", patient, visit, "Test2"); patient.getTests().add(test2); visit.getTests().add(test2); Patient3 patientb = new Patient3(patient.getId(), false, "__ds__"); Visit visitb = new Visit(visit.getId(), false, "__ds__"); VisitTest test2b = new VisitTest(2L, 0L, "T2", patientb, visitb, "Test2"); Change change1 = new Change(patientAlias, patient.getId(), 0L, patient.getUid()); change1.addCollectionChanges("tests", new CollectionChange(1, null, test2b)); Patient3 patientc = new Patient3(patient.getId(), false, "__ds__"); Visit visitc = new Visit(visit.getId(), false, "__ds__"); VisitTest test2c = new VisitTest(2L, 0L, "T2", patientc, visitc, "Test2"); Change change2 = new Change(visitAlias, visit.getId(), 0L, visit.getUid()); change2.addCollectionChanges("tests", new CollectionChange(1, null, test2c)); MergeContext mergeContext = entityManager.initMerge(serverSession); entityManager.handleUpdates(mergeContext, null, Arrays.asList(UPDATE.of(new ChangeSet(change1)), UPDATE.of(new ChangeSet(change2)))); Assert.assertSame("Patient em", entityManager, getEntityManager(patient)); Assert.assertEquals("Test added to patient", 2, patient.getTests().size()); Assert.assertEquals("Test added to patient (id)", Long.valueOf(2), patient.getTests().get(1).getId()); Assert.assertSame("Test added to patient (em)", entityManager, getEntityManager(patient.getTests().get(1))); Assert.assertEquals("Test added to visit", 2, visit.getTests().size()); Assert.assertEquals("Test added to visit (id)", Long.valueOf(2), visit.getTests().get(1).getId()); Assert.assertSame("Test added to visit (em)", entityManager, getEntityManager(visit.getTests().get(1))); Assert.assertFalse("Context not dirty", dataManager.isDirty()); } @Test public void testApplyRemoteChangeSet2() { Patient3 patient = new Patient3(1L, 0L, "P1", "Test"); Visit visit = new Visit(1L, 0L, "V1", patient, "Test"); patient.getVisits().add(visit); VisitTest test1 = new VisitTest(1L, 0L, "T1", patient, visit, "Test"); patient.getTests().add(test1); visit.getTests().add(test1); patient = (Patient3)entityManager.mergeExternalData(patient); entityManager.clearCache(); Assert.assertSame("Patient em", entityManager, getEntityManager(patient)); VisitTest test2 = new VisitTest(null, null, "T2", patient, visit, "Test2"); patient.getTests().add(test2); visit.getTests().add(test2); Patient3 patientc = new Patient3(patient.getId(), patient.getVersion(), patient.getUid(), "Test"); ((PersistentCollection<?>)patientc.getVisits()).uninitialize(); ((PersistentCollection<?>)patientc.getTests()).uninitialize(); Visit visitc = new Visit(visit.getId(), visit.getVersion(), visit.getUid(), patientc, "Test"); ((PersistentCollection<?>)visitc.getTests()).uninitialize(); VisitTest test2c = new VisitTest(2L, 0L, "T2", patientc, visitc, "Test2"); Change change1 = new Change(patientAlias, patient.getId(), 0L, patient.getUid()); change1.addCollectionChanges("tests", new CollectionChange(1, null, test2c)); Change change2 = new Change(visitAlias, visit.getId(), 0L, visit.getUid()); change2.addCollectionChanges("tests", new CollectionChange(1, null, test2c)); MergeContext mergeContext = entityManager.initMerge(serverSession); entityManager.handleUpdates(mergeContext, null, Arrays.asList(UPDATE.of(new ChangeSet(change1)), UPDATE.of(new ChangeSet(change2)))); Assert.assertSame("Patient em", entityManager, getEntityManager(patient)); Assert.assertEquals("Test added to patient", 2, patient.getTests().size()); Assert.assertEquals("Test added to patient (id)", Long.valueOf(2), patient.getTests().get(1).getId()); Assert.assertEquals("Test added to visit", 2, visit.getTests().size()); Assert.assertEquals("Test added to visit (id)", Long.valueOf(2), visit.getTests().get(1).getId()); Assert.assertFalse("Context not dirty", dataManager.isDirty()); } @Test public void testApplyRemoteChangeSet3() { Patient3 patient = new Patient3(1L, 0L, "P1", "Test"); Visit visit = new Visit(1L, 0L, "V1", patient, "Test"); patient.getVisits().add(visit); Visit visit2 = new Visit(2L, 0L, "V2", patient, "Test2"); patient.getVisits().add(visit2); patient = (Patient3)entityManager.mergeExternalData(patient); entityManager.clearCache(); Patient3 patientc = new Patient3(patient.getId(), patient.getVersion(), patient.getUid(), "Test"); ((PersistentCollection<?>)patientc.getVisits()).uninitialize(); Visit visitc = new Visit(3L, 0L, "V3", patientc, "Test3"); Visit visitd = new Visit(4L, 0L, "V4", patientc, "Test4"); Change change = new Change(patientAlias, patientc.getId(), patientc.getVersion(), patientc.getUid()); change.addCollectionChanges("visits", new CollectionChange(1, null, visitc), new CollectionChange(1, null, visitd), new CollectionChange(-1, null, new ChangeRef(visitAlias, visit.getUid(), visit.getId())), new CollectionChange(-1, null, new ChangeRef(visitAlias, visit2.getUid(), visit2.getId())) ); MergeContext mergeContext = entityManager.initMerge(serverSession); entityManager.handleUpdates(mergeContext, null, Arrays.asList( PERSIST.of(visitc), PERSIST.of(visitd), UPDATE.of(new ChangeSet(change)), REMOVE.of(new ChangeRef(visitAlias, visit.getUid(), visit.getId())), REMOVE.of(new ChangeRef(visitAlias, visit2.getUid(), visit2.getId())) )); Assert.assertSame("Patient em", entityManager, getEntityManager(patient)); Assert.assertEquals("Patient visits", 2, patient.getVisits().size()); Assert.assertEquals("Patient visit id", Long.valueOf(3), patient.getVisits().get(0).getId()); Assert.assertFalse("Context not dirty", dataManager.isDirty()); } @Test public void testApplyRemoteChangeList() { Patient3 patient = new Patient3(1L, 0L, "P1", "Test"); Visit visit = new Visit(1L, 0L, "V1", patient, "Test"); patient.getVisits().add(visit); VisitTest test1 = new VisitTest(1L, 0L, "T1", patient, visit, "Test"); patient.getTests().add(test1); visit.getTests().add(test1); patient = (Patient3)entityManager.mergeExternalData(patient); entityManager.clearCache(); VisitTest test2 = new VisitTest(null, null, "T2", patient, visit, "Test2"); patient.getTests().add(test2); // Don't add the item to the tests list of Visit so we check that both cases work // (with and without local change) // visit.getTests().add(test2); Patient3 patientb = new Patient3(patient.getId(), false, "__ds__"); Visit visitb = new Visit(visit.getId(), false, "__ds__"); VisitTest test2b = new VisitTest(2L, 0L, "T2", patientb, visitb, "Test2"); Change change1 = new Change(patientAlias, patient.getId(), 0L, patient.getUid()); change1.addCollectionChanges("tests", new CollectionChange(1, 1, test2b)); Patient3 patientc = new Patient3(patient.getId(), false, "__ds__"); Visit visitc = new Visit(visit.getId(), false, "__ds__"); VisitTest test2c = new VisitTest(2L, 0L, "T2", patientc, visitc, "Test2"); Change change2 = new Change(visitAlias, visit.getId(), 0L, visit.getUid()); change2.addCollectionChanges("tests", new CollectionChange(1, 1, test2c)); MergeContext mergeContext = entityManager.initMerge(serverSession); entityManager.handleUpdates(mergeContext, null, Arrays.asList( UPDATE.of(new ChangeSet(change1)), UPDATE.of(new ChangeSet(change2)) )); Assert.assertSame("Patient em", entityManager, getEntityManager(patient)); Assert.assertEquals("Test added to patient", 2, patient.getTests().size()); Assert.assertEquals("Test added to patient (id)", Long.valueOf(2), patient.getTests().get(1).getId()); Assert.assertEquals("Test added to visit", 2, visit.getTests().size()); Assert.assertEquals("Test added to visit (id)", Long.valueOf(2), visit.getTests().get(1).getId()); Assert.assertFalse("Context not dirty", dataManager.isDirty()); } @Test public void testApplyRemoteChangeList2() { Patient3 patient = new Patient3(1L, 0L, "P1", "Test"); Visit visit = new Visit(1L, 0L, "V1", patient, "Test"); patient.getVisits().add(visit); VisitTest test1 = new VisitTest(1L, 0L, "T1", patient, visit, "Test"); patient.getTests().add(test1); visit.getTests().add(test1); patient = (Patient3)entityManager.mergeExternalData(patient); entityManager.clearCache(); VisitTest test2 = new VisitTest(null, null, "T2", patient, visit, "Test2"); patient.getTests().add(test2); // Don't add the item to the tests list of Visit so we check that both cases work // (with and without local change) // visit.getTests().add(test2); VisitTest test3 = new VisitTest(null, null, "T3", patient, visit, "Test3"); patient.getTests().add(1, test3); Patient3 patientb = new Patient3(patient.getId(), false, "__ds__"); Visit visitb = new Visit(visit.getId(), false, "__ds__"); VisitTest test2b = new VisitTest(2L, 0L, "T2", patientb, visitb, "Test2"); Change change1 = new Change(patientAlias, patient.getId(), 0L, patient.getUid()); change1.addCollectionChanges("tests", new CollectionChange(1, 1, test2b)); Patient3 patientc = new Patient3(patient.getId(), false, "__ds__"); Visit visitc = new Visit(visit.getId(), false, "__ds__"); VisitTest test2c = new VisitTest(2L, 0L, "T2", patientc, visitc, "Test2"); Change change2 = new Change(visitAlias, visit.getId(), 0L, visit.getUid()); change2.addCollectionChanges("tests", new CollectionChange(1, 1, test2c)); MergeContext mergeContext = entityManager.initMerge(serverSession); entityManager.handleUpdates(mergeContext, null, Arrays.asList( UPDATE.of(new ChangeSet(change1)), UPDATE.of(new ChangeSet(change2)) )); Assert.assertSame("Patient em", entityManager, getEntityManager(patient)); Assert.assertEquals("Test added to patient", 3, patient.getTests().size()); Assert.assertEquals("Test added to patient (id)", Long.valueOf(2), patient.getTests().get(2).getId()); Assert.assertFalse("Context not dirty", dataManager.isDirty()); } @Test public void testApplyRemoteChangeList3() { Patient3 patient = new Patient3(1L, 0L, "P1", "Test"); Visit visit = new Visit(1L, 0L, "V1", patient, "Test"); patient.getVisits().add(visit); VisitTest test1 = new VisitTest(1L, 0L, "T1", patient, visit, "Test"); patient.getTests().add(test1); visit.getTests().add(test1); patient = (Patient3)entityManager.mergeExternalData(patient); entityManager.clearCache(); VisitTest test2 = new VisitTest(null, null, "T2", patient, visit, "Test2"); patient.getTests().add(test2); // Don't add the item to the tests list of Visit so we check that both cases work // (with and without local change) // visit.getTests().add(test2); VisitTest test3 = new VisitTest(null, null, "T3", patient, visit, "Test3"); patient.getTests().add(1, test3); Patient3 patientb = new Patient3(patient.getId(), false, "__ds__"); Visit visitb = new Visit(visit.getId(), false, "__ds__"); VisitTest test2b = new VisitTest(2L, 0L, "T2", patientb, visitb, "Test2"); Change change1 = new Change(patientAlias, patient.getId(), 0L, patient.getUid()); change1.addCollectionChanges("tests", new CollectionChange(1, 1, test2b)); Patient3 patientc = new Patient3(patient.getId(), false, "__ds__"); Visit visitc = new Visit(visit.getId(), false, "__ds__"); VisitTest test2c = new VisitTest(2L, 0L, "T2", patientc, visitc, "Test2"); Change change2 = new Change(visitAlias, visit.getId(), 0L, visit.getUid()); change2.addCollectionChanges("tests", new CollectionChange(1, 1, test2c)); MergeContext mergeContext = entityManager.initMerge(serverSession); entityManager.handleUpdates(mergeContext, null, Arrays.asList( UPDATE.of(new ChangeSet(change1)), UPDATE.of(new ChangeSet(change2)) )); Assert.assertSame("Patient em", entityManager, getEntityManager(patient)); Assert.assertEquals("Test added to patient", 3, patient.getTests().size()); Assert.assertEquals("Test added to patient (id)", Long.valueOf(2), patient.getTests().get(2).getId()); Assert.assertSame("Test em", entityManager, getEntityManager(patient.getTests().get(2))); Assert.assertFalse("Context not dirty", dataManager.isDirty()); } private static String patient4Alias = Patient4.class.getAnnotation(RemoteAlias.class).value(); private static String statusAlias = PatientStatus.class.getAnnotation(RemoteAlias.class).value(); @Test public void testApplyRemoteChangeList4() { Patient4 patient = new Patient4(1L, 0L, "P1", "Test"); PatientStatus status = new PatientStatus(1L, 0L, "S1", patient, "Test"); patient.setStatus(status); Diagnosis diagnosis = new Diagnosis(1L, 0L, "D1", patient, null, "Test"); patient.getDiagnosis().add(diagnosis); patient.getStatus().getDeathCauses().add(diagnosis); patient = (Patient4)entityManager.mergeExternalData(patient); entityManager.clearCache(); Diagnosis diagnosis2 = new Diagnosis(null, null, "D2", patient, null, "Test2"); patient.getStatus().getDeathCauses().add(diagnosis2); // Simulate remote call with local merge of arguments ChangeSet changeSet = new ChangeSetBuilder(entityManager, serverSession).buildChangeSet(); entityManager.mergeExternalData(changeSet); entityManager.clearCache(); Patient4 patientb = new Patient4(patient.getId(), patient.getVersion(), patient.getUid(), "Test"); ((PersistentCollection<?>)patientb.getDiagnosis()).uninitialize(); PatientStatus statusb = new PatientStatus(status.getId(), status.getVersion()+1, status.getUid(), patientb, status.getName()); ((PersistentCollection<?>)statusb.getDeathCauses()).uninitialize(); patientb.setStatus(statusb); Diagnosis diagnosis2b = new Diagnosis(2L, 0L, "D2", patientb, null, "Test2"); Change change1 = new Change(patient4Alias, patientb.getId(), patientb.getVersion(), patientb.getUid()); change1.addCollectionChanges("diagnosis", new CollectionChange(1, null, diagnosis2b)); Change change3 = new Change(statusAlias, statusb.getId(), statusb.getVersion(), statusb.getUid()); change3.addCollectionChanges("deathCauses", new CollectionChange(1, 1, diagnosis2b)); MergeContext mergeContext = entityManager.initMerge(serverSession); entityManager.handleUpdates(mergeContext, null, Arrays.asList( UPDATE.of(new ChangeSet(change1)), PERSIST.of(diagnosis2b), UPDATE.of(new ChangeSet(change3)) )); Assert.assertSame("Patient em", entityManager, getEntityManager(patient)); Assert.assertTrue("Diagnosis patient", patient.getDiagnosis().contains(diagnosis)); Assert.assertTrue("Diagnosis patient", patient.getStatus().getDeathCauses().contains(diagnosis)); for (Diagnosis d : patient.getDiagnosis()) Assert.assertSame("Diagnosis em", entityManager, getEntityManager(d)); for (Diagnosis d : patient.getStatus().getDeathCauses()) Assert.assertSame("Diagnosis em", entityManager, getEntityManager(d)); Assert.assertEquals("Diagnosis added to patient", 2, patient.getDiagnosis().size()); boolean found = false; for (Diagnosis d : patient.getDiagnosis()) { if (d.getId().equals(2L)) found = true; } Assert.assertTrue("Diagnosis added to patient (id)", found); found = false; for (Diagnosis d : patient.getStatus().getDeathCauses()) { if (d.getId().equals(2L)) found = true; } Assert.assertTrue("Diagnosis added to status (id)", found); Assert.assertFalse("Context not dirty", dataManager.isDirty()); } @Test public void testApplyRemoteChangeList5() { Patient4 patient = new Patient4(1L, 0L, "P1", "Test"); PatientStatus status = new PatientStatus(1L, 0L, "S1", patient, "Test"); patient.setStatus(status); Visit2 visit = new Visit2(1L, 0L, "V1", patient, "Test"); patient.getVisits().add(visit); Diagnosis diagnosis = new Diagnosis(1L, 0L, "D1", patient, visit, "Test"); patient.getDiagnosis().add(diagnosis); patient.getStatus().getDeathCauses().add(diagnosis); visit.getAssessments().add(diagnosis); patient = (Patient4)entityManager.mergeExternalData(patient); entityManager.clearCache(); Diagnosis diagnosis2 = new Diagnosis(null, null, "D2", patient, null, null); patient.getStatus().getDeathCauses().add(diagnosis2); diagnosis2.setName("Test2"); // Simulate remote call with local merge of arguments ChangeSet changeSet = new ChangeSetBuilder(entityManager, serverSession).buildChangeSet(); entityManager.mergeExternalData(changeSet); entityManager.clearCache(); Patient4 patientb = new Patient4(patient.getId(), patient.getVersion(), patient.getUid(), "Test"); ((PersistentCollection<?>)patientb.getDiagnosis()).uninitialize(); ((PersistentCollection<?>)patientb.getVisits()).uninitialize(); PatientStatus statusb = new PatientStatus(status.getId(), status.getVersion()+1, status.getUid(), patientb, "Test"); ((PersistentCollection<?>)statusb.getDeathCauses()).uninitialize(); patientb.setStatus(statusb); Visit2 visitb = new Visit2(visit.getId(), visit.getVersion(), visit.getUid(), patientb, "Test"); ((PersistentCollection<?>)visitb.getAssessments()).uninitialize(); Diagnosis diagnosis2b = new Diagnosis(2L, 0L, "D2", patientb, visitb, "Test2"); Change change1 = new Change(patient4Alias, patientb.getId(), patientb.getVersion(), patientb.getUid()); change1.addCollectionChanges("diagnosis", new CollectionChange(1, null, diagnosis2b)); Change change3 = new Change(statusAlias, statusb.getId(), statusb.getVersion(), statusb.getUid()); change3.addCollectionChanges("deathCauses", new CollectionChange(1, 1, diagnosis2b)); MergeContext mergeContext = entityManager.initMerge(serverSession); entityManager.handleUpdates(mergeContext, null, Arrays.asList( UPDATE.of(new ChangeSet(change1)), PERSIST.of(diagnosis2b), UPDATE.of(new ChangeSet(change3)) )); Assert.assertSame("Patient em", entityManager, getEntityManager(patient)); Assert.assertTrue("Diagnosis patient", patient.getDiagnosis().contains(diagnosis)); Assert.assertTrue("Diagnosis patient", patient.getStatus().getDeathCauses().contains(diagnosis)); for (Diagnosis d : patient.getDiagnosis()) Assert.assertSame("Diagnosis em", entityManager, getEntityManager(d)); for (Diagnosis d : patient.getStatus().getDeathCauses()) Assert.assertSame("Diagnosis em", entityManager, getEntityManager(d)); Assert.assertEquals("Diagnosis added to patient", 2, patient.getDiagnosis().size()); boolean found = false; for (Diagnosis d : patient.getDiagnosis()) { if (d.getId().equals(2L)) found = true; } Assert.assertTrue("Diagnosis added to patient (id)", found); found = false; for (Diagnosis d : patient.getStatus().getDeathCauses()) { if (d.getId().equals(2L)) found = true; } Assert.assertTrue("Diagnosis added to status (id)", found); Assert.assertFalse("Context not dirty", dataManager.isDirty()); } private static String classificationAlias = Classification.class.getAnnotation(RemoteAlias.class).value(); @Test public void testApplyRemoteChangeList6() { Classification list = new Classification(1L, 0L, "P1", "List"); Classification c1 = new Classification(1L, 0L, "C1", "1"); Classification c2 = new Classification(2L, 0L, "C2", "2"); Classification c3 = new Classification(3L, 0L, "C3", "3"); Classification c4 = new Classification(4L, 0L, "C4", "4"); list.getSubclasses().addAll(c1, c2, c3, c4); c1.getSuperclasses().add(list); c2.getSuperclasses().add(list); c3.getSuperclasses().add(list); c4.getSuperclasses().add(list); list = (Classification)entityManager.mergeExternalData(list); entityManager.clearCache(); Classification c = list.getSubclasses().remove(3); list.getSubclasses().add(2, c); // Case where the server does not build the changes in the same order than the client // Ex. Client: A B C => A C B : remove C (2) => add C (1) // Server: A B C => A C B : add C (1) => remove C (3) Classification c4b = new Classification(4L, 0L, "C4", "4"); ((PersistentCollection<?>)c4b.getSubclasses()).uninitialize(); ((PersistentCollection<?>)c4b.getSuperclasses()).uninitialize(); Change change = new Change(classificationAlias, list.getId(), list.getVersion()+1, list.getUid()); change.addCollectionChanges("subclasses", new CollectionChange(1, 2, c4b), new CollectionChange(-1, 4, c4b)); MergeContext mergeContext = entityManager.initMerge(serverSession); entityManager.handleUpdates(mergeContext, null, Arrays.asList(UPDATE.of(new ChangeSet(change)))); Assert.assertEquals("List size", 4, list.getSubclasses().size()); Assert.assertEquals("List elt 3", "C4", list.getSubclasses().get(2).getUid()); Assert.assertEquals("List elt 4", "C3", list.getSubclasses().get(3).getUid()); Assert.assertFalse("Context not dirty", dataManager.isDirty()); } @Test public void testApplyRemoteChangeList6b() { Classification list = new Classification(1L, 0L, "P1", "List"); Classification c1 = new Classification(1L, 0L, "C1", "1"); Classification c2 = new Classification(2L, 0L, "C2", "2"); Classification c3 = new Classification(3L, 0L, "C3", "3"); Classification c4 = new Classification(4L, 0L, "C4", "4"); list.getSubclasses().addAll(c1, c2, c3, c4); c1.getSuperclasses().add(list); c2.getSuperclasses().add(list); c3.getSuperclasses().add(list); c4.getSuperclasses().add(list); list = (Classification)entityManager.mergeExternalData(list); entityManager.clearCache(); Classification c = list.getSubclasses().remove(3); list.getSubclasses().add(2, c); // Case where the server does not build the same permutation as the client // Ex. Client: A B C => A C B : remove C (2) => add C (1) // Server: A B C => A C B : remove B (1) => add B (2) Classification c3b = new Classification(3L, 0L, "C3", "Test"); ((PersistentCollection<?>)c3b.getSubclasses()).uninitialize(); ((PersistentCollection<?>)c3b.getSuperclasses()).uninitialize(); Change change = new Change(classificationAlias, list.getId(), list.getVersion()+1, list.getUid()); change.addCollectionChanges("subclasses", new CollectionChange(-1, 2, c3b), new CollectionChange(1, 3, c3b)); MergeContext mergeContext = entityManager.initMerge(serverSession); entityManager.handleUpdates(mergeContext, null, Arrays.asList(UPDATE.of(new ChangeSet(change)))); Assert.assertEquals("List size", 4, list.getSubclasses().size()); Assert.assertEquals("List elt 3", "C4", list.getSubclasses().get(2).getUid()); Assert.assertEquals("List elt 4", "C3", list.getSubclasses().get(3).getUid()); Assert.assertFalse("Context not dirty", dataManager.isDirty()); } @Test public void testApplyRemoteChangeList6c() { Classification list = new Classification(1L, 0L, "P1", "List"); Classification c1 = new Classification(1L, 0L, "C1", "1"); Classification c2 = new Classification(2L, 0L, "C2", "2"); Classification c3 = new Classification(3L, 0L, "C3", "3"); Classification c4 = new Classification(4L, 0L, "C4", "4"); list.getSubclasses().addAll(c1, c2, c3, c4); c1.getSuperclasses().add(list); c2.getSuperclasses().add(list); c3.getSuperclasses().add(list); c4.getSuperclasses().add(list); list = (Classification)entityManager.mergeExternalData(list); entityManager.clearCache(); Classification c = list.getSubclasses().remove(0); list.getSubclasses().add(1, c); c = list.getSubclasses().remove(2); list.getSubclasses().add(1, c); // Case where the server does not build the same permutation as the client // Ex. Client: A B C D => B A C D => B C A D : remove A (0) => add A (1) => remove C (2) => add C (1) // Server: A B C D => B C A D : remove A (0) => add A (2) Classification c3b = new Classification(3L, 0L, "C3", "3"); ((PersistentCollection<?>)c3b.getSubclasses()).uninitialize(); ((PersistentCollection<?>)c3b.getSuperclasses()).uninitialize(); Change change = new Change(classificationAlias, list.getId(), list.getVersion()+1, list.getUid()); change.addCollectionChanges("subclasses", new CollectionChange(-1, 0, new ChangeRef(classificationAlias, "C1", 1L)), new CollectionChange(1, 2, new ChangeRef(classificationAlias, "C2", 2L)) ); MergeContext mergeContext = entityManager.initMerge(serverSession); entityManager.handleUpdates(mergeContext, null, Arrays.asList(UPDATE.of(new ChangeSet(change)))); Assert.assertEquals("List size", 4, list.getSubclasses().size()); Assert.assertEquals("List elt 3", "C1", list.getSubclasses().get(2).getUid()); Assert.assertEquals("List elt 4", "C4", list.getSubclasses().get(3).getUid()); Assert.assertFalse("Context not dirty", dataManager.isDirty()); } private static String person11Alias = Person11.class.getAnnotation(RemoteAlias.class).value(); @Test public void testApplyRemoteChangeMap() { Person11 person = new Person11(1L, 0L, "P1", "Test", "Test"); SimpleEntity key = new SimpleEntity(null, null, "K1", "Key"); SimpleEntity2 value = new SimpleEntity2(1L, 0L, "V1", "Value"); person.getMap().put(key, value); person = (Person11)entityManager.mergeExternalData(person); entityManager.clearCache(); SimpleEntity key2 = new SimpleEntity(null, null, "K2", "Key2"); SimpleEntity2 val2 = new SimpleEntity2(null, null, "V2", "Value2"); person.getMap().put(key2, val2); SimpleEntity key2b = new SimpleEntity(2L, 0L, "K2", "Key2"); SimpleEntity2 val2b = new SimpleEntity2(2L, 0L, "V2", "Value2"); person.getMap().put(key2b, val2b); Change change1 = new Change(person11Alias, person.getId(), 0L, person.getUid()); change1.addCollectionChanges("map", new CollectionChange(1, key2b, val2b)); MergeContext mergeContext = entityManager.initMerge(serverSession); entityManager.handleUpdates(mergeContext, null, Arrays.asList(UPDATE.of(new ChangeSet(change1)))); Assert.assertSame("Person em", entityManager, getEntityManager(person)); Assert.assertEquals("Entry added to person.map", 2, person.getMap().size()); Assert.assertEquals("Entry key updated", Long.valueOf(2), key2.getId()); Assert.assertEquals("Entry value updated", Long.valueOf(2), val2.getId()); Assert.assertFalse("Context not dirty", dataManager.isDirty()); } @Test public void testApplyRemoteChangeConflict() { Person person = new Person(1L, 0L, "P1", "Test", "Test"); person = (Person)entityManager.mergeExternalData(person); entityManager.clearCache(); person.setLastName("Tutu"); Change change = new Change(personAlias, 1L, 1L, "P1"); change.getChanges().put("lastName", "Toto"); final Conflicts[] conflicts = new Conflicts[1]; entityManager.addListener(new DataConflictListener() { @Override public void onConflict(EntityManager entityManager, Conflicts c) { conflicts[0] = c; } }); MergeContext mergeContext = entityManager.initMerge(serverSession); entityManager.handleUpdates(mergeContext, "EXTUSER", Arrays.asList(UPDATE.of(new ChangeSet(change)))); Assert.assertEquals("Last name not changed", "Tutu", person.getLastName()); Assert.assertEquals("Conflict detected", 1, conflicts[0].getConflicts().size()); conflicts[0].acceptAllServer(); Assert.assertEquals("Last name changed", "Toto", person.getLastName()); } @Test public void testApplyRemoteChangeConflict2() { Person person = new Person(1L, 0L, "P1", "Test", "Test"); person = (Person)entityManager.mergeExternalData(person); entityManager.clearCache(); person.setLastName("Tutu"); Change change = new Change(personAlias, 1L, 1L, "P1"); change.getChanges().put("lastName", "Toto"); final Conflicts[] conflicts = new Conflicts[1]; entityManager.addListener(new DataConflictListener() { @Override public void onConflict(EntityManager entityManager, Conflicts c) { conflicts[0] = c; } }); MergeContext mergeContext = entityManager.initMerge(serverSession); entityManager.handleUpdates(mergeContext, "EXTUSER", Arrays.asList(UPDATE.of(new ChangeSet(change)))); Assert.assertEquals("Last name not changed", "Tutu", person.getLastName()); Assert.assertEquals("Conflict detected", 1, conflicts[0].getConflicts().size()); conflicts[0].acceptAllClient(); Assert.assertEquals("Last name changed", "Tutu", person.getLastName()); Assert.assertEquals("Version increased", Long.valueOf(1), person.getVersion()); } @SuppressWarnings("unchecked") private <T> T serializeCopy(T object) throws Exception { // Simulate serialization of change set ByteArrayOutputStream buf = new ByteArrayOutputStream(1000); JMFSerializer ser = new JMFSerializer(buf, clientSharedContext); ser.writeObject(object); ser.close(); JMFDeserializer deser = new JMFDeserializer(new ByteArrayInputStream(buf.toByteArray()), clientSharedContext); object = (T)deser.readObject(); deser.close(); return object; } @Test public void testApplyChangeRef() throws Exception { Person person = new Person(1L, 0L, "P1", "Test", "Test"); Contact contact = new Contact(1L, 0L, "C1", person, "test@test.com"); person.getContacts().add(contact); person = (Person)entityManager.mergeExternalData(person); entityManager.clearCache(); person.getContacts().remove(0); ChangeSet changeSet = new ChangeSetBuilder(entityManager, serverSession).buildChangeSet(); changeSet = serializeCopy(changeSet); entityManager.resetEntity(person); Assert.assertEquals("Person has 1 contact", 1, person.getContacts().size()); // Check that applied ChangeSet removes the contact MergeContext mergeContext = entityManager.initMerge(serverSession); entityManager.mergeExternal(mergeContext, changeSet, null, null, null, false); Assert.assertEquals("Person contact removed", 0, person.getContacts().size()); } @Test public void testApplyChangeBoolean() throws Exception { entityManager.setUninitializeAllowed(false); Patient4b patient = new Patient4b(1L, 0L, "P1", "Bla", false); patient = (Patient4b)entityManager.mergeExternalData(patient); entityManager.clearCache(); Diagnosisb diagnosis = new Diagnosisb(null, null, "D1", patient, null, null); patient.getDiagnosis().add(diagnosis); patient.setDiagnosisAssessed(true); diagnosis.setName("bla"); Assert.assertTrue("Context dirty", dataManager.isDirty()); ChangeSet changeSet = new ChangeSetBuilder(entityManager, serverSession).buildChangeSet(); // Simulate pre-remote call merge MergeContext mergeContext = entityManager.initMerge(serverSession); changeSet = (ChangeSet)entityManager.mergeExternal(mergeContext, changeSet, null, null, null, false); Assert.assertSame(patient, diagnosis.getPatient()); MergeContext.destroy(entityManager); // Simulate serialization changeSet = serializeCopy(changeSet); Change c = changeSet.getChanges()[0]; Change change = new Change(c.getClassName(), c.getId(), 1L, c.getUid(), false); change.getChanges().putAll(c.getChanges()); Diagnosisb diag = (Diagnosisb)((CollectionChanges)c.getChanges().get("diagnosis")).getChanges()[0].getValue(); diag.resetId(1L, 0L); diag.getPatient().resetId(diag.getPatient().getId(), 1L); mergeContext = entityManager.initMerge(serverSession); entityManager.handleUpdates(mergeContext, null, Arrays.asList(PERSIST.of(diag), UPDATE.of(new ChangeSet(change)))); Assert.assertFalse("Context not dirty", dataManager.isDirty()); Assert.assertEquals("Patient version", Long.valueOf(1), patient.getVersion()); Assert.assertEquals("Diagnosis count", 1, patient.getDiagnosis().size()); } }