diff --git a/crm-example/pom.xml b/crm-example/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..9f978e06e4704796084fad9c4719075311f2144e --- /dev/null +++ b/crm-example/pom.xml @@ -0,0 +1,92 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <parent> + <artifactId>parent</artifactId> + <groupId>de.tudresden.inf.st.rmsc</groupId> + <version>1.0.0</version> + </parent> + + <artifactId>crm-example</artifactId> + <version>1.0.0</version> + <packaging>jar</packaging> + <name>CRM EXAMPLE</name> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> + <java.version>1.8</java.version> + </properties> + + <dependencies> + <!-- SCALA LANGUAGE --> + <dependency> + <groupId>org.scala-lang</groupId> + <artifactId>scala-library</artifactId> + <version>2.12.8</version> + </dependency> + <!-- SCROLL LANGUAGE --> + <dependency> + <groupId>com.github.max-leuthaeuser</groupId> + <artifactId>scroll_2.12</artifactId> + <version>1.8</version> + </dependency> + <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api --> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>1.7.30</version> + </dependency> + <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-simple --> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-nop</artifactId> + <version>1.7.30</version> + </dependency> + <!-- THE CONFLICT RESOLVER INCLUDING RSYNC --> + <dependency> + <groupId>de.tudresden.inf.st.rmsc</groupId> + <artifactId>conflictresolver</artifactId> + <version>1.0.0</version> + <scope>system</scope> + <systemPath>${project.basedir}/src/main/resources/libs/conflictresolver-1.0.0.jar</systemPath> + </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-engine</artifactId> + <version>5.5.2</version> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>net.alchim31.maven</groupId> + <artifactId>scala-maven-plugin</artifactId> + <version>3.1.3</version> + <executions> + <execution> + <goals> + <goal>compile</goal> + <goal>testCompile</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + <pluginManagement> + <plugins> + <!-- JUNIT --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>3.0.0-M3</version> + </plugin> + </plugins> + </pluginManagement> + </build> +</project> diff --git a/crm-example/src/main/resources/application.properties b/crm-example/src/main/resources/application.properties new file mode 100644 index 0000000000000000000000000000000000000000..c915bcfe24c7549723325d052925af4372e6bb3a --- /dev/null +++ b/crm-example/src/main/resources/application.properties @@ -0,0 +1,14 @@ +# Needs to be disabled until https://jira.spring.io/browse/SPR-12542 is fixed +spring.mvc.ignore-default-model-on-redirect=false + +spring.jpa.hibernate.ddl-auto=update +spring.datasource.url=jdbc:h2:~/test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE +spring.datasource.driverClassName=org.h2.Driver +#spring.datasource.username=sa +#spring.datasource.password=sa +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect + +# Logging +logging.file=crm.log + +logging.level.root=ERROR diff --git a/crm-example/src/main/resources/libs/conflictresolver-1.0.0.jar b/crm-example/src/main/resources/libs/conflictresolver-1.0.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..83ffb2dad102794a6663ba11f1df2d7d1e6a256e Binary files /dev/null and b/crm-example/src/main/resources/libs/conflictresolver-1.0.0.jar differ diff --git a/crm-example/src/main/scala/de/tudresden/inf/st/crme/Application.scala b/crm-example/src/main/scala/de/tudresden/inf/st/crme/Application.scala new file mode 100644 index 0000000000000000000000000000000000000000..bf474f857c76e2f13a1735f5281e945d32a52b54 --- /dev/null +++ b/crm-example/src/main/scala/de/tudresden/inf/st/crme/Application.scala @@ -0,0 +1,17 @@ +package de.tudresden.inf.st.crme + +import de.tudresden.inf.st.crme.models.modelA.PresenceEmployee +import de.tudresden.inf.st.crme.models.modelB.{Member, Team} +import de.tudresden.inf.st.crme.models.modelC.SimpleEmployee +import de.tudresden.inf.st.crme.rsync.compartments.{CrmModelsConstructionCompartment, CrmModelsDestructionCompartment, CrmModelsSyncCompartment} +import de.tudresden.inf.st.crme.rsync.constants.ModelConstants +import org.rosi_project.model_management.core.{ModelElementLists, PlayerSync, SynchronizationCompartment} +import org.rosi_project.model_management.sync.lock.{ElementLock, ElementLockProvider, SynchronizationAware} +import org.rosi_project.model_management.util.UuidUtil +import org.slf4j.LoggerFactory +import scroll.internal.Compartment + +object Application extends App { + + +} diff --git a/crm-example/src/main/scala/de/tudresden/inf/st/crme/models/MetaModels.scala b/crm-example/src/main/scala/de/tudresden/inf/st/crme/models/MetaModels.scala new file mode 100644 index 0000000000000000000000000000000000000000..85c06d8fddb0dafc657f9cc131fc01824ac38bca --- /dev/null +++ b/crm-example/src/main/scala/de/tudresden/inf/st/crme/models/MetaModels.scala @@ -0,0 +1,68 @@ +package de.tudresden.inf.st.crme.models + +import de.tudresden.inf.st.crme.models.modelA.{Employee, PresenceEmployee, RemoteEmployee} +import de.tudresden.inf.st.crme.models.modelB.{Member, Team} +import de.tudresden.inf.st.crme.models.modelC.SimpleEmployee +import de.tudresden.inf.st.crme.rsync.compartments.{CrmModelsConstructionCompartment, CrmModelsDestructionCompartment, CrmModelsSyncCompartment} +import de.tudresden.inf.st.crme.rules.customrules.{LeaderCustomReferenceCreationRule, MemberCustomDeletionRule, MemberCustomReferenceCreationRule, MemberCustomReferenceDeletionRule} +import de.tudresden.inf.st.crme.rules.systemrules.{OwnerDataConflictSystemRule, TsDataConflictSystemRule, TsReferenceConflictSystemRule} +import org.rosi_project.model_management.core.{Cardinality, Field, ModelElementLists, ModelInformation, SynchronizationCompartment} +import org.rosi_project.model_management.sync.conflict.customrules.CustomRuleExecutor +import org.rosi_project.model_management.sync.conflict.systemrules.SystemRuleExecutor + +import scala.reflect.classTag + +object MetaModels { + def reset(): Unit = { + ModelElementLists.dropAll() + initCrmMetaModels() + System.gc() + } + + def initCrmMetaModels(): Unit ={ + // Model A + ModelInformation.add( + ModelInformation(classTag[PresenceEmployee].runtimeClass, classTag[Employee].runtimeClass), + ModelInformation(classTag[Employee].runtimeClass, null, Field.primitives(classTag[String], "fullName", "birthday", "address") ++ + Field.primitives(classTag[Float], "salary")), + ModelInformation(classTag[RemoteEmployee].runtimeClass, classTag[Employee].runtimeClass)) + + // Model B + ModelInformation.add( + ModelInformation(classTag[Team].runtimeClass, null, Field.primitives(classTag[String], "teamName") ++ + Set(Field.association(classTag[Member], "members", Cardinality.Many, + (team, member) => team.asInstanceOf[Team].addMember(member.asInstanceOf[Member]), + (team, member) => team.asInstanceOf[Team].removeMember(member.asInstanceOf[Member])), + + Field.association(classTag[Member], "leader", Cardinality.One, + (team, leader) => team.asInstanceOf[Team].setLeader(leader.asInstanceOf[Member]), + (team, leader) => team.asInstanceOf[Team].setLeader(null)) + )), + ModelInformation(classTag[Member].runtimeClass, null, Field.primitives(classTag[String], "birthday", "firstName", "companyLocation", "lastName", "address") ++ + Set(Field.association(classTag[Team], "leaderInTeam", Cardinality.One, + (member, team) => member.asInstanceOf[Member].setLeaderInTeam(team.asInstanceOf[Team]), + (member, team) => member.asInstanceOf[Member].setLeaderInTeam(null)), + + Field.association(classTag[Member], "memberInTeam", Cardinality.One, + (member, team) => member.asInstanceOf[Member].setMemberInTeam(team.asInstanceOf[Team]), + (member, team) => member.asInstanceOf[Member].setMemberInTeam(null)), + ))) + + // Model C + ModelInformation.add(ModelInformation(classTag[SimpleEmployee].runtimeClass, null, Field.primitives(classTag[String], "birthday", "team", "fullName", "address") ++ + Field.primitives(classTag[Boolean], "isRemoteEmployee"))) + + // RSync Setup + SynchronizationCompartment.reset() + SynchronizationCompartment.createRoleManager() + SynchronizationCompartment.changeConstructionRule(CrmModelsConstructionCompartment) + SynchronizationCompartment.changeDestructionRule(CrmModelsDestructionCompartment) + SynchronizationCompartment.addSynchronizationRule(new CrmModelsSyncCompartment()) + + SystemRuleExecutor.addSystemDataRule(new TsDataConflictSystemRule, new OwnerDataConflictSystemRule) + SystemRuleExecutor.addSystemReferenceRule(new TsReferenceConflictSystemRule) + + CustomRuleExecutor.addCustomDeletionRule(new MemberCustomDeletionRule) + CustomRuleExecutor.addCustomReferenceRule(new MemberCustomReferenceCreationRule, new MemberCustomReferenceDeletionRule, new LeaderCustomReferenceCreationRule) + } +} diff --git a/crm-example/src/main/scala/de/tudresden/inf/st/crme/models/modelA/Employee.scala b/crm-example/src/main/scala/de/tudresden/inf/st/crme/models/modelA/Employee.scala new file mode 100644 index 0000000000000000000000000000000000000000..ea55de905a9fc96439d4c582c118e509c6bfddb2 --- /dev/null +++ b/crm-example/src/main/scala/de/tudresden/inf/st/crme/models/modelA/Employee.scala @@ -0,0 +1,71 @@ +package de.tudresden.inf.st.crme.models.modelA + +import org.rosi_project.model_management.core +import org.rosi_project.model_management.core.{ConflictResolvable, Field, MapSerializable, ModelInformation, PlayerSync, PrimitiveField} +import org.rosi_project.model_management.sync.lock.{ElementLock, SynchronizationAware} + +import scala.reflect.classTag + +abstract class Employee (protected var fullName: String, protected var birthday: String, + protected var address: String, protected var salary: Float, + lock: ElementLock, guid: String, owner: String) extends ConflictResolvable(lock, guid, owner) { + + def this(guid: String, lock: ElementLock, data: Map[String, String]) = this(data("fullName"), data("birthday"), + data("address"), data("salary").toFloat, lock, guid, data("owner")) + + override def serialize: Map[String, String] = Map("fullName" -> fullName, "birthday" -> birthday, "adress" -> address, "salary" -> salary.toString) ++ super.serialize() + + override def unserialize(data: Map[String, String]): Unit ={ + super.unserialize(data) + if(data.contains("fullName")) fullName = data("fullName") + if(data.contains("birthday")) birthday = data("birthday") + if(data.contains("address")) address = data("address") + if(data.contains("salary")) salary = data("salary").toFloat + } + + def syncFieldsToOtherModels(): Unit = { + +this syncEmployeeFields() + } + + def getFullName(): String = { + fullName + } + + def setFullName(s : String): Unit = { + fullName = s + } + + def getSalary(): Float = { + salary + } + + def setSalary(f : Float): Unit = { + salary = f + } + + def getAddress(): String = { + address + } + + def setAddress(s : String): Unit = { + address = s + } + + def getBirthday(): String = { + birthday + } + + def setBirthday(s : String): Unit = { + birthday = s + } + + def getRelated: Set[PlayerSync] = { + val relatedElementsMetaObject = +this getRelatedElements() + val relatedObjects: Set[PlayerSync] = relatedElementsMetaObject.right.get.head.right.get + relatedObjects + } + + override def toString(): String = { + return "Employee: " + fullName + " D: " + deleted + } +} diff --git a/crm-example/src/main/scala/de/tudresden/inf/st/crme/models/modelA/PresenceEmployee.scala b/crm-example/src/main/scala/de/tudresden/inf/st/crme/models/modelA/PresenceEmployee.scala new file mode 100644 index 0000000000000000000000000000000000000000..51a76ff83d9a352f44acdf2610e73139cbd8bc7d --- /dev/null +++ b/crm-example/src/main/scala/de/tudresden/inf/st/crme/models/modelA/PresenceEmployee.scala @@ -0,0 +1,26 @@ +package de.tudresden.inf.st.crme.models.modelA + +import org.rosi_project.model_management.core.{Field, ModelInformation} +import org.rosi_project.model_management.sync.lock.ElementLock + +class PresenceEmployee(fullName: String, birthday: String, + address: String, salary: Float, + lock: ElementLock, guid: String, owner: String) + extends Employee (fullName, birthday, address, salary, lock, guid, owner ) { + + def this(guid: String, lock: ElementLock, data: Map[String, String]) = this(data("fullName"), data("birthday"), + data("address"), data("salary").toFloat, lock, guid, data("owner")) + + override def toString(): String = { + var lockData: String = "" + + if(this.lock != null){ + lockData += this.lock.getId() + }else{ + lockData += "---" + } + + return "PresenceEmployee: " + getFullName() + " pbirthday: " + getBirthday() + " paddress: " + + getAddress() + " psalary: " + getSalary() + " guid: " + guid + " D: " + deleted + " lock: " + lockData + } +} diff --git a/crm-example/src/main/scala/de/tudresden/inf/st/crme/models/modelA/RemoteEmployee.scala b/crm-example/src/main/scala/de/tudresden/inf/st/crme/models/modelA/RemoteEmployee.scala new file mode 100644 index 0000000000000000000000000000000000000000..7a2e91194d952ca27061506ed924823fdeca1f69 --- /dev/null +++ b/crm-example/src/main/scala/de/tudresden/inf/st/crme/models/modelA/RemoteEmployee.scala @@ -0,0 +1,29 @@ +package de.tudresden.inf.st.crme.models.modelA + +import org.rosi_project.model_management.core.ModelInformation +import org.rosi_project.model_management.sync.lock.ElementLock + +import scala.reflect.classTag + +class RemoteEmployee (fullName: String, birthday: String, + address: String, salary: Float, lock: ElementLock, + guid: String, owner: String) + extends Employee (fullName, birthday, address, salary, lock, guid, owner) { + + def this(guid: String, lock: ElementLock, data: Map[String, String]) = this(data("fullName"), data("birthday"), + data("address"), data("salary").toFloat, lock, guid, data("owner")) + + override def toString(): String = { + + var lockData: String = "" + + if(this.lock != null){ + lockData += this.lock.getId() + }else{ + lockData += "---" + } + + return "RemoteEmployee: " + getFullName() + " rbirthday: " + getBirthday() + " raddress: " + + getAddress() + " rSalary: " + getSalary() + " reGuid: " + guid + " D: " + deleted + " lock: " + lockData + } +} diff --git a/crm-example/src/main/scala/de/tudresden/inf/st/crme/models/modelB/Member.scala b/crm-example/src/main/scala/de/tudresden/inf/st/crme/models/modelB/Member.scala new file mode 100644 index 0000000000000000000000000000000000000000..e0c341d37237bd2fba968484726e9b250c2cb6a8 --- /dev/null +++ b/crm-example/src/main/scala/de/tudresden/inf/st/crme/models/modelB/Member.scala @@ -0,0 +1,122 @@ +package de.tudresden.inf.st.crme.models.modelB + +import org.rosi_project.model_management.core.{ConflictResolvable, ModelInformation, PlayerSync} +import org.rosi_project.model_management.sync.lock.{ElementLock, SynchronizationAware} + +class Member (protected var birthday: String, protected var firstName: String, protected var companyLocation : String, + protected var lastName: String, protected var address: String, + protected var leaderInTeam: Team, protected var memberInTeam: Team, + lock: ElementLock, guid: String, owner: String) extends ConflictResolvable (lock, guid, owner){ + + def this(guid: String, lock: ElementLock, map: Map[String, String]) = this(map("birthday"), map("fullname"), map("companyLocation"), map("lastName"), + map("address"), ModelInformation.fromGuid(map("leaderInTeam")).asInstanceOf[Team], ModelInformation.fromGuid(map("memberInTeam")).asInstanceOf[Team], lock, guid, map("owner")) + + override def serialize: Map[String, String] = Map("birthday" -> birthday, "firstName" -> firstName, "lastName" -> lastName, + "companyLocation" -> companyLocation, "address" -> address, "leaderInTeam" -> ModelInformation.getGuid(leaderInTeam), + "memberInTeam" -> ModelInformation.getGuid(memberInTeam)) ++ super.serialize() + + override def unserialize(data: Map[String, String]): Unit = { + super.unserialize(data) + birthday = data("birthday") + firstName = data("firstName") + lastName = data("lastName") + companyLocation = data("companyLocation") + address = data("address") + leaderInTeam = ModelInformation.fromGuid(data("leaderInTeam")).asInstanceOf[Team] + memberInTeam = ModelInformation.fromGuid(data("memberInTeam")).asInstanceOf[Team] + } + + def syncFieldsToOtherModels(): Unit = { + +this syncMemberFields() + } + + def getCompanyLocation(): String = { + companyLocation + } + + def getFullName() = s"${firstName} ${lastName}" + + def setCompanyLocation(s : String): Unit = { + companyLocation = s + } + + def getLastName(): String = { + lastName + } + + def setLastName(s : String): Unit = { + lastName = s + } + + def getFirstName(): String = { + firstName + } + + def setFirstName(s : String): Unit = { + firstName = s + } + + def getAddress(): String = { + address + } + + def setAddress(s : String): Unit = { + address = s + } + + def getBirthday(): String = { + birthday + } + + def setBirthday(s : String): Unit = { + birthday = s + } + + def getLeaderInTeam(): Team = { + leaderInTeam + } + + def setLeaderInTeam(t : Team): Unit = { + leaderInTeam = t + +this syncLeaderInTeam() + } + + def getMemberInTeam(): Team = { + memberInTeam + } + + def setMemberInTeam(t : Team): Unit = { + memberInTeam = t + +this syncMemberInTeam() + } + + def setMemberWithoutSyncInTeam(t : Team): Unit = { + memberInTeam = t + } + + def getRelated: Set[PlayerSync] = { + val relatedElementsMetaObject = +this getRelatedElements() + val relatedObjects: Set[PlayerSync] = relatedElementsMetaObject.right.get.head.right.get + relatedObjects + } + + override def toString: String = { + + var lockData: String = "" + var teamName = "---" + + if(memberInTeam != null){ + teamName = memberInTeam.getTeamName() + } + + if(this.lock != null){ + lockData += this.lock.getId() + }else{ + lockData += "---" + } + + return "Member: " + guid + " ts: " + ts + " rv: " + rv + " owner: " + owner + " memberteam: "+ + teamName + " firstname: " + firstName + " lastName: " + lastName + " birthday: " + + birthday + " companyLocation: " + companyLocation + " address: " + address + " D: " + deleted + " lock: " + lockData + } +} \ No newline at end of file diff --git a/crm-example/src/main/scala/de/tudresden/inf/st/crme/models/modelB/Team.scala b/crm-example/src/main/scala/de/tudresden/inf/st/crme/models/modelB/Team.scala new file mode 100644 index 0000000000000000000000000000000000000000..60e02456d8f6d5a485d0435131860461c99440a1 --- /dev/null +++ b/crm-example/src/main/scala/de/tudresden/inf/st/crme/models/modelB/Team.scala @@ -0,0 +1,109 @@ +package de.tudresden.inf.st.crme.models.modelB + +import de.tudresden.inf.st.crme.models.modelA.Employee +import org.rosi_project.model_management.core.{AssociationField, Cardinality, ConflictResolvable, Field, ModelInformation, PlayerSync} +import org.rosi_project.model_management.sync.lock.{ElementLock, SynchronizationAware} + +import scala.:: +import scala.reflect.classTag + +class Team(protected var teamName: String, protected var leader: Member, + protected var members: Set[Member], + tLock: ElementLock, tGuid: String, tOwner: String) extends ConflictResolvable (tLock, tGuid, tOwner){ + + def this(guid: String, lock: ElementLock, data: Map[String, String]) = this(data("teamName"), + ModelInformation.fromGuid(data("leader")).asInstanceOf[Member], ModelInformation.fromGuids(classTag[Member], data("members")).map(x => x.asInstanceOf[Member]), lock, guid, data("owner")) + + override def serialize(): Map[String, String] = Map("teamName" -> teamName, "members" -> ModelInformation.getGuids(members.toSet[SynchronizationAware]), + "leader" -> ModelInformation.getGuid(leader)) ++ super.serialize() + + override def unserialize(data: Map[String, String]): Unit = { + super.unserialize(data) + if(data.contains("teamName")) teamName = data("teamName") + if(data.contains("members")) members = ModelInformation.fromGuids(classTag[Member], data("members")).map(x => x.asInstanceOf[Member]) + if(data.contains("leader")) leader = ModelInformation.fromGuid(data("leader")).asInstanceOf[Member] + } + + def syncFieldsToOtherModels(): Unit = { + +this syncTeamFields() + } + + def setLeader(m: Member): Unit = { + leader = m + } + + def getLeader(): Member = { + leader + } + + def setTeamName(s: String): Unit = { + teamName = s + } + + def getTeamName(): String = { + teamName + } + + def getMembers(): Set[Member] = { + members + } + + def addMember(m: Member): Unit = { + addMemberWithoutSync(m) + +this syncAddMember (m) + } + + def addMemberWithoutSync(m: Member): Unit = { + + if(members == null){ + members = Set() + } + + require(m != null) + require(!members.contains(m)) + members += m + } + + def removeMember(m: Member): Unit = { + removeMemberWithoutSync(m) + +this syncRemoveMember (m) + } + + def addMemberOnlySync(m: Member): Unit = +this syncAddMember(m) + + def removeMemberOnlySync(m: Member): Unit = +this syncRemoveMember(m) + + def removeMemberWithoutSync(m: Member): Unit = { + require(m != null) + require(members.contains(m)) + members -= m + } + + def getRelated: Set[PlayerSync] = { + val relatedElementsMetaObject = +this getRelatedElements() + val relatedObjects: Set[PlayerSync] = relatedElementsMetaObject.right.get.head.right.get + relatedObjects + } + + override def toString: String = { + + var mString: String = "" + + getMembers().foreach { m => + mString += " ++ Member: " + mString += m.getLastName + } + + var lockData: String = "" + + if(this.lock != null){ + lockData += this.lock.getId() + }else{ + lockData += "---" + } + + return "Team: " + guid + " ts: " + ts + " rv: " + rv + " owner: " + tOwner + " teamname: " + teamName + " leader: "+ + leader + " D: " + deleted + " lock: " + lockData + " ** With members:" + mString + } + +} \ No newline at end of file diff --git a/crm-example/src/main/scala/de/tudresden/inf/st/crme/models/modelC/SimpleEmployee.scala b/crm-example/src/main/scala/de/tudresden/inf/st/crme/models/modelC/SimpleEmployee.scala new file mode 100644 index 0000000000000000000000000000000000000000..09de63d78cfaca00378e388c45209119d23e81cf --- /dev/null +++ b/crm-example/src/main/scala/de/tudresden/inf/st/crme/models/modelC/SimpleEmployee.scala @@ -0,0 +1,91 @@ +package de.tudresden.inf.st.crme.models.modelC + +import de.tudresden.inf.st.crme.models.modelA.Employee +import org.rosi_project.model_management.core.{ConflictResolvable, Field, ModelInformation, PlayerSync} +import org.rosi_project.model_management.sync.lock.{ElementLock, SynchronizationAware} + + +class SimpleEmployee (protected var birthday: String, protected var isRemoteEmployee : Boolean, var team: String, + protected var fullName: String, protected var address: String, lock: ElementLock, + guid: String, owner: String) extends ConflictResolvable (lock, guid, owner){ + + def this(guid: String, lock: ElementLock, data: Map[String, String]) = this(data("birthday"), + data("isRemoteEmployee").toBoolean, data("team"), data("fullName"), data("address"), lock, guid, data("owner")) + + override def serialize(): Map[String, String] = Map("isRemoteEmployee" -> isRemoteEmployee.toString, "fullName" -> fullName, + "birthday" -> birthday, "address" -> address, "team" -> team) ++ super.serialize() + + override def unserialize(data: Map[String, String]): Unit = { + super.unserialize(data) + isRemoteEmployee = data("isRemoteEmployee").toBoolean + fullName = data("fullName") + birthday = data("birthday") + address = data("address") + team = data("team") + } + + def syncFieldsToOtherModels(): Unit = { + +this syncSimpleEmployeeFields() + } + + def getIsRemoteEmployee(): Boolean = { + isRemoteEmployee + } + + def setIsRemoteEmployee(b : Boolean): Unit = { + isRemoteEmployee = b + } + + def getTeam(): String = { + team + } + + def setTeam(s : String): Unit = { + team = s + } + + def getFullName(): String = { + fullName + } + + def setFullName(s : String): Unit = { + fullName = s + } + + def getAddress(): String = { + address + } + + def setAddress(s : String): Unit = { + address = s + } + + def getBirthday(): String = { + birthday + } + + def setBirthday(s : String): Unit = { + birthday = s + } + + def getRelated: Set[PlayerSync] = { + val relatedElementsMetaObject = +this getRelatedElements() + val relatedObjects: Set[PlayerSync] = relatedElementsMetaObject.right.get.head.right.get + relatedObjects + } + + override def toString: String = { + + var lockData: String = "" + + if(this.lock != null){ + lockData += this.lock.getId() + }else{ + lockData += "---" + } + + return "SimpleEmployee: " + guid + " ts: " + ts + " rv: " + rv + " owner: " + owner + + " isRemoteEmployee: " + isRemoteEmployee + " fullName: " + fullName + " birthday: " + + birthday + " address: " + address + " team: " + team + " D: " + deleted + " lock: " + lockData + } +} \ No newline at end of file diff --git a/crm-example/src/main/scala/de/tudresden/inf/st/crme/rsync/compartments/CrmModelsConstructionCompartment.scala b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rsync/compartments/CrmModelsConstructionCompartment.scala new file mode 100644 index 0000000000000000000000000000000000000000..50690fd598251e438fdb30fa8e1daeeb1a346b41 --- /dev/null +++ b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rsync/compartments/CrmModelsConstructionCompartment.scala @@ -0,0 +1,195 @@ +package de.tudresden.inf.st.crme.rsync.compartments + +import de.tudresden.inf.st.crme.models.modelA.{Employee, PresenceEmployee, RemoteEmployee} +import de.tudresden.inf.st.crme.models.modelB.{Member, Team} +import de.tudresden.inf.st.crme.models.modelC.SimpleEmployee +import org.rosi_project.model_management.core.{ModelElementLists, PlayerSync, SynchronizationCompartment} +import org.rosi_project.model_management.sync.IConstructionCompartment +import org.rosi_project.model_management.sync.lock.{ElementLock, SynchronizationAware} +import org.rosi_project.model_management.sync.roles.{IConstructor, IRoleManager} +import org.rosi_project.model_management.util.UuidUtil + +object CrmModelsConstructionCompartment extends IConstructionCompartment { + + override def getRuleName: String = "CrmModelsConstruction" + + override def getConstructorForClassName(classname: Object): IConstructor = { + + if (classname.isInstanceOf[Member]) { + return new MemberConstruct() + } + + if (classname.isInstanceOf[Team]) { + return new TeamConstruct() + } + + if (classname.isInstanceOf[SimpleEmployee]) { + return new SimpleEmployeeConstruct() + } + + if(classname.isInstanceOf[Employee] || classname.isInstanceOf[PresenceEmployee] || classname.isInstanceOf[RemoteEmployee]){ + return new EmployeeConstruct() + } + + null + } + + class EmployeeConstruct() extends IConstructor { + + override def construct(comp: PlayerSync, man: IRoleManager): Unit = { + + val birthday: String = +this getBirthday() + val fullName: String = +this getFullName() + val address: String = +this getAddress() + val owner: String = +this getOwner() + val splitName: Array[String] = fullName.split(" ") + var firstName: String = null + var lastName: String = null + + if (splitName.size == 2) { + firstName = splitName(0); + lastName = splitName(1); + } + + val lock: ElementLock = comp.asInstanceOf[SynchronizationAware].lock + + val simpleEmployee: SimpleEmployee = new SimpleEmployee(birthday, comp.isInstanceOf[RemoteEmployee], null, + fullName, address, lock, UuidUtil.generateUuid(), owner) + simpleEmployee.ts = 1 + simpleEmployee.rv = 1 + + val member: Member = new Member(birthday, firstName, "DEFAULT", lastName, address + , null, null, lock, UuidUtil.generateUuid(), owner) + member.ts = 1 + member.rv = 1 + + createContainerElement(true, true, comp, man) + createContainerElement(false, true, simpleEmployee, SynchronizationCompartment.createRoleManager()) + createContainerElement(false, true, member, SynchronizationCompartment.createRoleManager()) + + makeCompleteConstructionProcess(containers) + } + } + + class MemberConstruct() extends IConstructor { + + override def construct(comp: PlayerSync, man: IRoleManager): Unit = { + + val birthday: String = +this getBirthday() + val firstName: String = +this getFirstName() + val companyLocation: String = +this getCompanyLocation() + val lastName: String = +this getLastName() + val address: String = +this getAddress() + val memberInTeam: Team = +this getMemberInTeam() + val owner: String = +this getOwner() + + val isRemoteWorker = (companyLocation == null) + val fullName = firstName + " " + lastName + + val lock: ElementLock = comp.asInstanceOf[SynchronizationAware].lock + + var tName: String = null + + if(memberInTeam != null){ + tName = memberInTeam.getTeamName() + } + + val simpleEmployee: SimpleEmployee = new SimpleEmployee(birthday, isRemoteWorker, tName, + fullName, address, lock, UuidUtil.generateUuid(), owner) + simpleEmployee.ts = 1 + simpleEmployee.rv = 1 + + var employee: Employee = null + var teamName: String = null + + if(memberInTeam != null){ + teamName = memberInTeam.getTeamName() + } + + if(companyLocation == null){ + employee = new RemoteEmployee(fullName, birthday, address, -1f, lock, UuidUtil.generateUuid(), owner) + }else{ + employee = new PresenceEmployee(fullName, birthday, address, -1f, lock, UuidUtil.generateUuid(), owner) + } + + employee.ts = 1 + employee.rv = 1 + + createContainerElement(true, true, comp, man) + createContainerElement(false, true, simpleEmployee, SynchronizationCompartment.createRoleManager()) + createContainerElement(false, true, employee, SynchronizationCompartment.createRoleManager()) + + makeCompleteConstructionProcess(containers) + } + } + + class TeamConstruct() extends IConstructor { + + override def construct(comp: PlayerSync, man: IRoleManager): Unit = { + + comp.ts = 1 + comp.rv = 1 + + createContainerElement(true, true, comp, man) + makeCompleteConstructionProcess(containers) + + } + } + + class SimpleEmployeeConstruct() extends IConstructor { + + override def construct(comp: PlayerSync, man: IRoleManager): Unit = { + + val birthday: String = +this getBirthday() + val isRemoteEmployee: Boolean = +this getIsRemoteEmployee() + val fullName: String = +this getFullName() + val address: String = +this getAddress() + val owner: String = +this getOwner() + val teamName: String = +this getTeam() + + val lock: ElementLock = comp.asInstanceOf[SynchronizationAware].lock + val splitName: Array[String] = fullName.split(" ") + var firstName: String = null + var lastName: String = null + var companyLocation: String = null + + if (splitName.size == 2) { + firstName = splitName(0); + lastName = splitName(1); + } + + if(!isRemoteEmployee){ + companyLocation = "DEFAULT" + } + +/* val team: Team = new Team(teamName, null, null, lock, UuidUtil.generateUuid(), owner) + team.ts = 1 + team.rv = 1 */ + + val member: Member = new Member(birthday, firstName, companyLocation, lastName, address + , null, null, lock, UuidUtil.generateUuid(), owner) + member.ts = 1 + member.rv = 1 + +// team.addMemberWithoutSync(member) + + var employee: Employee = null + + if(companyLocation == null){ + employee = new RemoteEmployee(fullName, birthday, address, -1f, lock, UuidUtil.generateUuid(), owner) + }else{ + employee = new PresenceEmployee(fullName, birthday, address, -1f, lock, UuidUtil.generateUuid(), owner) + } + + employee.ts = 1 + employee.rv = 1 + + createContainerElement(true, true, comp, man) + createContainerElement(false, true, member, SynchronizationCompartment.createRoleManager()) + // createContainerElement(false, true, team, SynchronizationCompartment.createRoleManager()) + createContainerElement(false, true, employee, SynchronizationCompartment.createRoleManager()) + + makeCompleteConstructionProcess(containers) + } + } +} diff --git a/crm-example/src/main/scala/de/tudresden/inf/st/crme/rsync/compartments/CrmModelsDestructionCompartment.scala b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rsync/compartments/CrmModelsDestructionCompartment.scala new file mode 100644 index 0000000000000000000000000000000000000000..9193e8a894b94dc25203bac4d1fe97c9ff7eb652 --- /dev/null +++ b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rsync/compartments/CrmModelsDestructionCompartment.scala @@ -0,0 +1,54 @@ +package de.tudresden.inf.st.crme.rsync.compartments + +import org.rosi_project.model_management.core.{ModelElementLists, PlayerSync} +import org.rosi_project.model_management.sync.IDestructionCompartment +import org.rosi_project.model_management.sync.roles.{IDestructor, IRoleManager} +import org.slf4j.LoggerFactory + +object CrmModelsDestructionCompartment extends IDestructionCompartment{ + + override def getRuleName: String = "CrmModelsDestruction" + + override def getDestructorForClassName(classname: Object): IDestructor = { + new DeleteRoleAndConnections(); + } + + /** + * Destruction-role that deletes objects in all models + */ + class DeleteRoleAndConnections() extends IDestructor { + + val logger = LoggerFactory.getLogger(classOf[DeleteRoleAndConnections]) + + def deleteRoleFunction(): Unit = { + + logger.info("%%%%%%% Executing DeleteRoleAndConnections %%%%%%%") + //get the list of related manager + var relatedManagers: Set[IRoleManager] = (+this).getRelatedManager() + + //clear all lists from the related managers + (+this).clearListsOfRelatedManager() + + //delete also all related elements + relatedManagers.foreach { m => + (+m).deleteObjectFromSynchro() + } + + //send notification about deletion + (+this).deletionNotification() + + //clear now the related manager list + (+this).clearRelatedManager() + //delete all roles this element has + val player = this.player + if (player.isRight) { + val test: PlayerSync = player.right.get.asInstanceOf[PlayerSync] + ModelElementLists.removeElement(test) + val roles = test.roles() + roles.foreach { r => + r.remove() + } + } + } + } +} diff --git a/crm-example/src/main/scala/de/tudresden/inf/st/crme/rsync/compartments/CrmModelsSyncCompartment.scala b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rsync/compartments/CrmModelsSyncCompartment.scala new file mode 100644 index 0000000000000000000000000000000000000000..5a34feec90dbf07827155753f17ad507e889ee03 --- /dev/null +++ b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rsync/compartments/CrmModelsSyncCompartment.scala @@ -0,0 +1,342 @@ +package de.tudresden.inf.st.crme.rsync.compartments + +import de.tudresden.inf.st.crme.models.modelA.Employee +import de.tudresden.inf.st.crme.models.modelB.{Member, Team} +import de.tudresden.inf.st.crme.models.modelC.SimpleEmployee +import de.tudresden.inf.st.crme.rsync.constants.ModelConstants +import org.rosi_project.model_management.core.{ModelElementLists, PlayerSync} +import org.rosi_project.model_management.sync.ISyncCompartment +import org.rosi_project.model_management.sync.lock.{ElementLock, ElementLockProvider, LockResult} +import org.rosi_project.model_management.sync.roles.ISyncRole +import org.rosi_project.model_management.util.UuidUtil +import org.slf4j.LoggerFactory + +import scala.sys.error + +class CrmModelsSyncCompartment extends ISyncCompartment { + + override def getRuleName: String = "CrmModelsSync" + + val logger = LoggerFactory.getLogger(classOf[CrmModelsSyncCompartment]) + + override protected def getFirstRole(classname: Object): ISyncRole = { + if (classname.isInstanceOf[Employee] || classname.isInstanceOf[Member] || classname.isInstanceOf[Team] + || classname.isInstanceOf[SimpleEmployee]) + return new Sync() + null + } + + override def isFirstIntegration(classname: Object): Boolean = { + (classname.isInstanceOf[Employee] || classname.isInstanceOf[Member] || classname.isInstanceOf[Team] + || classname.isInstanceOf[SimpleEmployee]) + } + + override def getNewInstance: ISyncCompartment = new CrmModelsSyncCompartment + + class Sync() extends ISyncRole { + + override def getOuterCompartment: ISyncCompartment = CrmModelsSyncCompartment.this + + def getRelatedElements(): Set[PlayerSync] = { + var relatedObjects: Set[PlayerSync] = Set() + getSyncer().foreach { a => + if (a.player.right.get.isInstanceOf[PlayerSync]) { + relatedObjects += a.player.right.get.asInstanceOf[PlayerSync] + } + } + relatedObjects + } + + def syncEmployeeFields(): Unit = { + ElementLockProvider.synchronized { + if (!doSync) { + // start sync + doSync = true + + val birthday: String = +this getBirthday() + val fullName: String = +this getFullName() + val address: String = +this getAddress() + val owner: String = +this getOwner() + val splitName: Array[String] = fullName.split(" ") + var firstName: String = null + var lastName: String = null + + if (splitName.size == 2) { + firstName = splitName(0); + lastName = splitName(1); + } + + getSyncer().foreach { syncer => + + val ts: Int = (+syncer).ts + + if (syncer.player.right.get.isInstanceOf[SimpleEmployee]) { + (+syncer).setFullName(fullName) + (+syncer).setBirthday(birthday) + (+syncer).setAddress(address) + + if (ts == Int.MaxValue) { + (+syncer).ts = 1 + } else { + (+syncer).ts = ts + 1 + } + } + + if (syncer.player.right.get.isInstanceOf[Member]) { + (+syncer).setFirstName(firstName) + (+syncer).setLastName(lastName) + (+syncer).setBirthday(birthday) + (+syncer).setAddress(address) + (+syncer).setOwner(owner) + + if (ts == Int.MaxValue) { + (+syncer).ts = 1 + } else { + (+syncer).ts = ts + 1 + } + } + } + } + doSync = false + } + } + + def syncSimpleEmployeeFields(): Unit = { + ElementLockProvider.synchronized { + if (!doSync) { + // start sync + doSync = true + + val birthday: String = +this getBirthday() + val fullName: String = +this getFullName() + val address: String = +this getAddress() + val owner: String = +this getOwner() + val isRemoteEmployee: Boolean = +this getIsRemoteEmployee() + val teamName: String = +this getTeam() + val splitName: Array[String] = fullName.split(" ") + var firstName: String = null + var lastName: String = null + + if (splitName.size == 2) { + firstName = splitName(0); + lastName = splitName(1); + } + + getSyncer().foreach { syncer => + + val ts: Int = (+syncer).ts + val guid: String = (+syncer).guid + + if (syncer.player.right.get.isInstanceOf[Employee]) { + (+syncer).setFullName(fullName) + (+syncer).setOwner(owner) + (+syncer).setAddress(address) + (+syncer).setBirthday(birthday) + + if (ts == Int.MaxValue) { + (+syncer).ts = 1 + } else { + (+syncer).ts = ts + 1 + } + } + + if (syncer.player.right.get.isInstanceOf[Member]) { + (+syncer).setFirstName(firstName) + (+syncer).setLastName(lastName) + (+syncer).setBirthday(birthday) + (+syncer).setAddress(address) + (+syncer).setOwner(owner) + val currentLocation: String = (+syncer).getCompanyLocation() + + if (!isRemoteEmployee && currentLocation != null) { + (+syncer).setCompanyLocation("DEFAULT") + } + +/* val t: Team = (+syncer).getMemberInTeam() + + var found: Boolean = false + if (((t != null && t.getTeamName() != teamName) || t == null) && teamName != null) { + ModelElementLists.getDirectElementsFromType(ModelConstants.TEAM_MODEL_TYPE).foreach { i => + if (i.asInstanceOf[Team].getTeamName() == teamName) { + found = true + + var lockSuccess: Boolean = false + var lockRes: LockResult = null + + while (!lockSuccess){ + val lockResIter = ElementLockProvider.provideLock(i.asInstanceOf[Team].guid) + lockRes = lockResIter + lockSuccess = lockResIter.success + } + + (+syncer).setMemberWithoutSyncInTeam(i) + // enables bi-directional sync .. + i.asInstanceOf[Team].addMemberWithoutSync(ModelElementLists.getElementByGuid(guid).asInstanceOf[Member]) + i.asInstanceOf[Team].rv = i.asInstanceOf[Team].rv + 1 + + ElementLockProvider.removeLocksFromElement(lockRes.lock.getId(), i.asInstanceOf[Team].guid) + } else if(i.asInstanceOf[Team].getMembers().exists(x => x.guid == guid)){ + // Remove member from old team + val member = ModelElementLists.getElementByGuid(guid).asInstanceOf[Member] + i.asInstanceOf[Team].removeMemberWithoutSync(member) + // Remove team if now empty + // if(i.asInstanceOf[Team].getMembers().isEmpty) i.asInstanceOf[Team].deleteObjectFromSynchro() + } + } + } */ + + if (ts == Int.MaxValue) { + (+syncer).ts = 1 + } else { + (+syncer).ts = ts + 1 + } + } + } + } + doSync = false + } + } + + def syncMemberFields(): Unit = { + ElementLockProvider.synchronized { + if (!doSync) { + // start sync + doSync = true + + val birthday: String = +this getBirthday() + val firstName: String = +this firstName() + val lastName: String = +this lastName() + val address: String = +this getAddress() + val owner: String = +this getOwner() + val companyLocation: String = +this getCompanyLocation() + + getSyncer().foreach { syncer => + + val ts: Int = (+syncer).ts + + if (syncer.player.right.get.isInstanceOf[Employee]) { + (+syncer).setFullName(firstName + " " + lastName) + (+syncer).setOwner(owner) + (+syncer).setAddress(address) + (+syncer).setBirthday(birthday) + + if (ts == Int.MaxValue) { + (+syncer).ts = 1 + } else { + (+syncer).ts = ts + 1 + } + } + + if (syncer.player.right.get.isInstanceOf[SimpleEmployee]) { + (+syncer).setFullName(firstName + " " + lastName) + (+syncer).setBirthday(birthday) + (+syncer).setAddress(address) + + if (companyLocation == null) { + (+syncer).setIsRemoteEmployee(true) + } else { + (+syncer).setIsRemoteEmployee(false) + } + + if (ts == Int.MaxValue) { + (+syncer).ts = 1 + } else { + (+syncer).ts = ts + 1 + } + } + } + } + doSync = false + } + } + + def syncTeamFields(): Unit = { + ElementLockProvider.synchronized { + if (!doSync) { + // start sync + doSync = true + // nothing to do + } + doSync = false + } + } + + def syncLeaderInTeam(): Unit = { + ElementLockProvider.synchronized { + if (!doSync) { + // start sync + doSync = true + // nothing to do + } + doSync = false + } + } + + def syncMemberInTeam(): Unit = { + ElementLockProvider.synchronized { + if (!doSync) { + // start sync + doSync = true + var memberInTeam: Team = (+this).getMemberInTeam() + + getSyncer().foreach { syncer => + + val ts: Int = (+syncer).ts + + if (syncer.player.right.get.isInstanceOf[SimpleEmployee]) { + + if (memberInTeam != null) { + (+syncer).setTeam(memberInTeam.getTeamName()) + } else { + (+syncer).setTeam(null) + } + + if (ts == Int.MaxValue) { + (+syncer).ts = 1 + } else { + (+syncer).ts = ts + 1 + } + } + } + doSync = false + } + } + } + + def syncAddMember(member: PlayerSync): Unit = { + ElementLockProvider.synchronized { + if (!doSync) { + + // start sync + doSync = true + + val name: String = +this getTeamName() + + member.getRelatedObjects().foreach { + case employee: SimpleEmployee => + employee.setTeam(name) + case _ => + } + } + doSync = false + } + } + } + + def syncRemoveMember(member: PlayerSync): Unit = { + ElementLockProvider.synchronized { + if (!doSync) { + + // start sync + doSync = true + + member.getRelatedObjects().foreach { + case employee: SimpleEmployee => + employee.setTeam(null) + case _ => + } + } + doSync = false + } + } +} \ No newline at end of file diff --git a/crm-example/src/main/scala/de/tudresden/inf/st/crme/rsync/constants/ModelConstants.scala b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rsync/constants/ModelConstants.scala new file mode 100644 index 0000000000000000000000000000000000000000..7c78fcc4ceec1d71406d3b56a2b4ec37af93698c --- /dev/null +++ b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rsync/constants/ModelConstants.scala @@ -0,0 +1,14 @@ +package de.tudresden.inf.st.crme.rsync.constants + +object ModelConstants { + + final val SIMPLE_EMPLOYEE_MODEL_TYPE = "de.tudresden.inf.st.crme.models.modelC.SimpleEmployee" + + final val MEMBER_MODEL_TYPE = "de.tudresden.inf.st.crme.models.modelB.Member" + final val TEAM_MODEL_TYPE = "de.tudresden.inf.st.crme.models.modelB.Team" + + final val EMPLOYEE_MODEL_TYPE = "de.tudresden.inf.st.crme.models.modelA.Employee" + final val PRESENCE_EMPLOYEE_MODEL_TYPE = "de.tudresden.inf.st.crme.models.modelA.PresenceEmployee" + final val REMOTE_EMPLOYEE_MODEL_TYPE = "de.tudresden.inf.st.crme.models.modelA.RemoteEmployee" + +} diff --git a/crm-example/src/main/scala/de/tudresden/inf/st/crme/rules/customrules/LeaderCustomReferenceCreationRule.scala b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rules/customrules/LeaderCustomReferenceCreationRule.scala new file mode 100644 index 0000000000000000000000000000000000000000..0e0a597c80e7f202788f8895f5b94af8f61ec276 --- /dev/null +++ b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rules/customrules/LeaderCustomReferenceCreationRule.scala @@ -0,0 +1,34 @@ +package de.tudresden.inf.st.crme.rules.customrules + +import de.tudresden.inf.st.crme.models.modelA.Employee +import de.tudresden.inf.st.crme.models.modelB.Team +import org.rosi_project.model_management.core.PlayerSync +import org.rosi_project.model_management.sync.conflict.customrules.ICustomReferenceRule +import org.slf4j.LoggerFactory +import scroll.internal.Compartment + +class LeaderCustomReferenceCreationRule extends ICustomReferenceRule { + + override def getRuleName(): String = "LeaderCustomReferenceCreationRule" + + override def isReferenceDeletionRule(): Boolean = false + + override def matchesRule(referencingElement: PlayerSync, referencedElement: PlayerSync, senderRv: Int, senderOwner: String, collection: String): Boolean = { + var isEligible = false + + new Compartment { + referencingElement match { + case _: Team => { + if (collection == "leader") { + val related: Set[AnyRef] = (+referencingElement).getRelatedElements() + related.foreach { + case s: Employee => isEligible = s.getSalary() >= 3000 + } + } + } + } + } + + return isEligible + } +} diff --git a/crm-example/src/main/scala/de/tudresden/inf/st/crme/rules/customrules/MemberCustomDeletionRule.scala b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rules/customrules/MemberCustomDeletionRule.scala new file mode 100644 index 0000000000000000000000000000000000000000..51762997d354b1781b56703e5e150f3813e77f28 --- /dev/null +++ b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rules/customrules/MemberCustomDeletionRule.scala @@ -0,0 +1,42 @@ +package de.tudresden.inf.st.crme.rules.customrules + +import de.tudresden.inf.st.crme.models.modelB.{Member, Team} +import org.rosi_project.model_management.core.{ModelElementLists, PlayerSync} +import org.rosi_project.model_management.sync.conflict.customrules.ICustomDeletionRule +import org.rosi_project.model_management.sync.lock.SynchronizationAware +import org.slf4j.LoggerFactory + +class MemberCustomDeletionRule extends ICustomDeletionRule { + + private val logger = LoggerFactory.getLogger(classOf[MemberCustomDeletionRule]) + + /** + * get name of this rule + */ + def getRuleName(): String = "MemberCustomDeletionRule" + + /** + * return true if no task references comment (the element) + */ + def matchesRule(element: PlayerSync, senderOwner: String): Boolean = { + + if (element.isInstanceOf[Member]) { + val elems: Set[SynchronizationAware] = ModelElementLists + .getDirectElementsFromType("de.tudresden.inf.st.crme.models.modelB.Team") + elems.foreach{ e => + val team: Team = e.asInstanceOf[Team] + team.getMembers().foreach{ c=> + if(c.guid == element.asInstanceOf[SynchronizationAware].guid && team.getLeader() == null){ + logger.info("Custom-Deletion-Rule does not allow deletion") + return false + } + } + } + logger.info("Custom-Deletion-Rule allows deletion") + return true + } + + logger.info("Custom-Deletion-Rule does not allow deletion") + false + } +} diff --git a/crm-example/src/main/scala/de/tudresden/inf/st/crme/rules/customrules/MemberCustomReferenceCreationRule.scala b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rules/customrules/MemberCustomReferenceCreationRule.scala new file mode 100644 index 0000000000000000000000000000000000000000..f93937fd0c9d0fca71f4c3bc6bbee00d0f6417cf --- /dev/null +++ b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rules/customrules/MemberCustomReferenceCreationRule.scala @@ -0,0 +1,32 @@ +package de.tudresden.inf.st.crme.rules.customrules + +import de.tudresden.inf.st.crme.models.modelB.Team +import org.rosi_project.model_management.core.PlayerSync +import org.rosi_project.model_management.sync.conflict.customrules.ICustomReferenceRule +import org.rosi_project.model_management.sync.lock.SynchronizationAware +import org.slf4j.LoggerFactory + +class MemberCustomReferenceCreationRule extends ICustomReferenceRule{ + + private val log = LoggerFactory.getLogger(classOf[MemberCustomReferenceCreationRule]) + + override def getRuleName(): String = "MemberCustomReferenceCreationRule" + + override def isReferenceDeletionRule(): Boolean = false + + override def matchesRule(referencingElement: PlayerSync, referencedElement: PlayerSync, senderRv: Int, senderOwner: String, collection: String): Boolean = { + + if (referencingElement.isInstanceOf[Team]) { + val team: Team = referencingElement.asInstanceOf[Team] + team.getMembers().foreach { c => + if (c.guid == referencedElement.asInstanceOf[SynchronizationAware].guid) { + // REF-ADD-ADD + log.info("Detected conflict (REF-ADD-ADD): " + team.guid) + return false + } + } + return true + } + false + } +} diff --git a/crm-example/src/main/scala/de/tudresden/inf/st/crme/rules/customrules/MemberCustomReferenceDeletionRule.scala b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rules/customrules/MemberCustomReferenceDeletionRule.scala new file mode 100644 index 0000000000000000000000000000000000000000..55e0b41ee6b990140e30901e7ad84ec7b6518f38 --- /dev/null +++ b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rules/customrules/MemberCustomReferenceDeletionRule.scala @@ -0,0 +1,41 @@ +package de.tudresden.inf.st.crme.rules.customrules + +import de.tudresden.inf.st.crme.models.modelB.Team +import org.rosi_project.model_management.core.PlayerSync +import org.rosi_project.model_management.sync.conflict.customrules.ICustomReferenceRule +import org.slf4j.LoggerFactory +import org.rosi_project.model_management.sync.lock._ + + +class MemberCustomReferenceDeletionRule extends ICustomReferenceRule { + + private val logger = LoggerFactory.getLogger(classOf[MemberCustomReferenceDeletionRule]) + + /** + * returns the name of this rule + */ + def getRuleName(): String = "MemberCustomReferenceCreationRule" + + /** + * true -> it is a ReferenceCreationRule + */ + def isReferenceDeletionRule(): Boolean = true + + /** + * return true if rule allows deletion of reference + */ + def matchesRule(referencingElement: PlayerSync, referencedElement: PlayerSync, senderRv: Int, senderOwner: String, collection: String): Boolean = { + if (referencingElement.isInstanceOf[Team]) { + val team: Team = referencingElement.asInstanceOf[Team] + team.getMembers().foreach { c => + if (c.guid == referencedElement.asInstanceOf[SynchronizationAware].guid) { + return true + } + } + // REF-DEL-DEL + logger.error("Detected conflict (REF-DEL-DEL): " + team.guid) + return false + } + false + } +} \ No newline at end of file diff --git a/crm-example/src/main/scala/de/tudresden/inf/st/crme/rules/systemrules/OwnerDataConflictSystemRule.scala b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rules/systemrules/OwnerDataConflictSystemRule.scala new file mode 100644 index 0000000000000000000000000000000000000000..2cf08a02c7d83fe1e15f77bdf863bcc8d6f17f29 --- /dev/null +++ b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rules/systemrules/OwnerDataConflictSystemRule.scala @@ -0,0 +1,69 @@ +package de.tudresden.inf.st.crme.rules.systemrules + +import org.rosi_project.model_management.core.PlayerSync +import org.rosi_project.model_management.core.ModelElementLists +import org.rosi_project.model_management.sync.conflict.systemrules.{DataConflictSystemRule, SystemRule} +import org.rosi_project.model_management.sync.lock._ +import org.slf4j.LoggerFactory + +/** + * Data-conflict-system-rule which integrates the owner mechanism. + */ +@SystemRule("data") +class OwnerDataConflictSystemRule extends DataConflictSystemRule { + + val logger = LoggerFactory.getLogger(classOf[OwnerDataConflictSystemRule]) + + def getRuleName() = "OwnerDataConflictSystemRule" + + def resolveModificationConflicts(ts: Int, modifier: String, guid: String, elementKey: String): (Boolean, PlayerSync) = { + + val elementSet: Set[SynchronizationAware] = ModelElementLists.getDirectElementsFromType(elementKey) + + elementSet.foreach { elem => + val playerSync: SynchronizationAware = elem.asInstanceOf[SynchronizationAware] + + // check for conflicts + if (playerSync.guid == guid) { + if (playerSync.deleted) { + logger.error("Detected deleted element in ModelElementsList ... this should not occur!") + } + // check if mod-mod-conflict + if (playerSync.owner != modifier) { + logger.error("Owner-Rule detected conflict (MOD-MOD): " + guid) + return (false, playerSync) + } else { + logger.info("Owner-Rule passed by " + guid) + return (true, playerSync) + } + } + } + logger.error("Owner-Rule detected conflict (DEL-MOD): " + guid) + (false, null) + } + + def resolveDeletionConflicts(ts: Int, modifier: String, guid: String, elementKey: String): (Boolean, PlayerSync) = { + + val elementSet: Set[SynchronizationAware] = ModelElementLists.getDirectElementsFromType(elementKey) + + elementSet.foreach { elem => + val playerSync: SynchronizationAware = elem.asInstanceOf[SynchronizationAware] + + if (playerSync.guid == guid) { + if (playerSync.deleted) { + logger.error("Detected deleted element in ModelElementsList ... this should not occur!") + } + // check if mod-del-conflict + if (playerSync.owner != modifier) { + logger.error("Owner-Rule detected conflict (MOD-DEL): " + guid) + return (false, playerSync) + } else { + logger.info("Owner-Rule passed by " + guid) + return (true, playerSync) + } + } + } + logger.error("Owner-Rule detected conflict (DEL-DEL): " + guid) + (false, null) + } +} diff --git a/crm-example/src/main/scala/de/tudresden/inf/st/crme/rules/systemrules/TsDataConflictSystemRule.scala b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rules/systemrules/TsDataConflictSystemRule.scala new file mode 100644 index 0000000000000000000000000000000000000000..729fadc34a744605967d6bc68d3dcb2d9a15a51c --- /dev/null +++ b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rules/systemrules/TsDataConflictSystemRule.scala @@ -0,0 +1,69 @@ +package de.tudresden.inf.st.crme.rules.systemrules + +import org.rosi_project.model_management.core.PlayerSync +import org.rosi_project.model_management.core.ModelElementLists +import org.rosi_project.model_management.sync.conflict.systemrules.{DataConflictSystemRule, SystemRule} +import org.rosi_project.model_management.sync.lock._ +import org.slf4j.LoggerFactory + +/** + * Data-conflict-system-rule which integrates the data-version mechanism. + */ +@SystemRule("data") +class TsDataConflictSystemRule extends DataConflictSystemRule { + + val logger = LoggerFactory.getLogger(classOf[TsDataConflictSystemRule]) + + def getRuleName() = "TsDataConflictSystemRule" + + def resolveModificationConflicts(ts: Int, modifier: String, guid: String, elementKey: String): (Boolean, PlayerSync) = { + + val elementSet: Set[SynchronizationAware] = ModelElementLists.getDirectElementsFromType(elementKey) + + elementSet.foreach { elem => + val playerSync: SynchronizationAware = elem.asInstanceOf[SynchronizationAware] + + // check for conflicts + if (playerSync.guid == guid) { + if (playerSync.deleted) { + logger.error("Detected deleted element in ModelElementsList ... this should not occur!") + } + // check if mod-mod-conflict + if (playerSync.ts > ts) { + logger.error("TS-Rule detected conflict (MOD-MOD): " + guid) + return (false, playerSync) + } else { + logger.info("TS-Rule passed by " + guid) + return (true, playerSync) + } + } + } + logger.error("TS-Rule detected conflict (DEL-MOD): " + guid) + (false, null) + } + + def resolveDeletionConflicts(ts: Int, modifier: String, guid: String, elementKey: String): (Boolean, PlayerSync) = { + + val elementSet: Set[SynchronizationAware] = ModelElementLists.getDirectElementsFromType(elementKey) + + elementSet.foreach { elem => + val playerSync: SynchronizationAware = elem.asInstanceOf[SynchronizationAware] + + if (playerSync.guid == guid) { + if (playerSync.deleted) { + logger.error("Detected deleted element in ModelElementsList ... this should not occur!") + } + // check if mod-del-conflict + if (playerSync.ts > (ts * (-1))) { + logger.error("TS-Rule detected conflict (MOD-DEL): " + guid) + return (false, playerSync) + } else { + logger.info("TS-Rule passed by " + guid) + return (true, playerSync) + } + } + } + logger.error("TS-Rule detected conflict (DEL-DEL): " + guid) + (false, null) + } +} diff --git a/crm-example/src/main/scala/de/tudresden/inf/st/crme/rules/systemrules/TsReferenceConflictSystemRule.scala b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rules/systemrules/TsReferenceConflictSystemRule.scala new file mode 100644 index 0000000000000000000000000000000000000000..f05cd1689d377d3b2d21da39ad82512005d8cd02 --- /dev/null +++ b/crm-example/src/main/scala/de/tudresden/inf/st/crme/rules/systemrules/TsReferenceConflictSystemRule.scala @@ -0,0 +1,63 @@ +package de.tudresden.inf.st.crme.rules.systemrules + +import org.rosi_project.model_management.core.PlayerSync +import org.rosi_project.model_management.core.ModelElementLists +import org.rosi_project.model_management.sync.conflict.systemrules.{ReferenceConflictSystemRule, SystemRule} +import org.rosi_project.model_management.sync.lock._ +import org.slf4j.LoggerFactory + +/** + * Reference-conflict-system-rule which integrates the reference-version mechanism. + */ +@SystemRule("reference") +class TsReferenceConflictSystemRule extends ReferenceConflictSystemRule { + + val logger = LoggerFactory.getLogger(classOf[TsReferenceConflictSystemRule]) + + def getRuleName() = "TsReferenceConflictSystemRule" + + def resolveDeletedReferencedElementConflicts(guid: String, elementKey: String): PlayerSync = { + + val elementSet: Set[SynchronizationAware] = ModelElementLists.getDirectElementsFromType(elementKey) + + elementSet.foreach { elem => + val playerSync: SynchronizationAware = elem.asInstanceOf[SynchronizationAware] + + // check for conflicts + if (playerSync.guid == guid) { + if (playerSync.deleted) { + logger.warn("Detected deleted element in ModelElementsList ... this should not occur!") + } else { + return playerSync + } + } + } + logger.info("Detected ref-conflict (ADD-REF/DEL-REF): " + guid) + null + } + + def resolveDeletedReferencingElementConflicts(guid: String, elementKey: String): PlayerSync = { + + val elementSet: Set[SynchronizationAware] = ModelElementLists.getDirectElementsFromType(elementKey) + + elementSet.foreach { elem => + val playerSync: SynchronizationAware = elem.asInstanceOf[SynchronizationAware] + + if (playerSync.guid == guid) { + if (playerSync.deleted) { + logger.warn("Detected deleted element in ModelElementsList ... this should not occur!") + } else { + return playerSync + } + } + } + logger.error("Detected ref-conflict (REF-MOD-DEL/REF-MOD-ADD): " + guid) + null + } + + @deprecated + def resolveReferenceCounterConflicts(rv: Int, referencingElement: PlayerSync): Boolean = { + // reason for 2nd condition: initially the ref-version of a new element is set to 1 + return rv == referencingElement.rv || (rv == 0 && referencingElement.rv == 1) + } +} diff --git a/crm-example/src/main/scala/de/tudresden/inf/st/crme/services/.gitkeep b/crm-example/src/main/scala/de/tudresden/inf/st/crme/services/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/crm-example/src/test/java/CrmConflictBenchmark.scala b/crm-example/src/test/java/CrmConflictBenchmark.scala new file mode 100644 index 0000000000000000000000000000000000000000..46ed39eb7b1f74ea6ead65c4ea368093777659d3 --- /dev/null +++ b/crm-example/src/test/java/CrmConflictBenchmark.scala @@ -0,0 +1,316 @@ +import de.tudresden.inf.st.crme.models.MetaModels +import de.tudresden.inf.st.crme.models.modelB.Team +import de.tudresden.inf.st.crme.models.modelC.SimpleEmployee +import de.tudresden.inf.st.crme.rsync.compartments.{CrmModelsConstructionCompartment, CrmModelsDestructionCompartment, CrmModelsSyncCompartment} +import de.tudresden.inf.st.crme.rsync.constants.ModelConstants +import de.tudresden.inf.st.crme.rules.customrules.{MemberCustomDeletionRule, MemberCustomReferenceCreationRule, MemberCustomReferenceDeletionRule} +import de.tudresden.inf.st.crme.rules.systemrules.{OwnerDataConflictSystemRule, TsDataConflictSystemRule, TsReferenceConflictSystemRule} +import org.junit.jupiter.api.{BeforeAll, BeforeEach, Test} +import org.rosi_project.model_management.{ClientChangeRecord, ConflictResolution, ConflictResolutionResponse} +import org.rosi_project.model_management.core.{ModelElementLists, SynchronizationCompartment} +import org.rosi_project.model_management.sync.conflict.customrules.CustomRuleExecutor +import org.rosi_project.model_management.sync.conflict.systemrules.SystemRuleExecutor +import org.rosi_project.model_management.sync.procedures.data.ClientEntireRecord +import org.rosi_project.model_management.util.{PerformanceCounter, PerformanceInformation} +import org.slf4j.{Logger, LoggerFactory} +import org.testng.annotations.BeforeClass +import scroll.internal.Compartment + +import java.util.concurrent.{Callable, Executors} +import scala.collection.mutable.ListBuffer +import scala.sys.error + +class CrmConflictBenchmark { + val log: Logger = LoggerFactory.getLogger(getClass) + + @BeforeEach + def init(): Unit ={ + MetaModels.initCrmMetaModels() + } + + def createSimpleElements(count: Int): (ConflictResolutionResponse, Seq[String]) ={ + // Initial creation of elements + val clientChangeRecords = ListBuffer[ClientChangeRecord]() + val clientEntireRecords = ListBuffer[ClientEntireRecord]() + + for(i <- 1 to count) { + clientChangeRecords.append(ClientChangeRecord(ModelConstants.SIMPLE_EMPLOYEE_MODEL_TYPE, s"e${i} t${Thread.currentThread().getId}", 0, 0, + Map("birthday" -> "01.01.1995", "fullName" -> s"Member ${i}", "address" -> "Dresden"), Map(), Map(), s"e${i} t${Thread.currentThread().getId}", s"testuser${Thread.currentThread().getId}", refonly = false)) + clientEntireRecords.append(ClientEntireRecord(s"e${i} t${Thread.currentThread().getId}", 0, 0, ModelConstants.SIMPLE_EMPLOYEE_MODEL_TYPE)) + } + + val initResponse = ConflictResolution.syncModel("creation", clientChangeRecords, clientEntireRecords, count, s"testuser${Thread.currentThread().getId}") + val employeeGuids = initResponse.changes.filter(x => x.model == ModelConstants.SIMPLE_EMPLOYEE_MODEL_TYPE).map(x => x.guid) + // val teams: Seq[Team] = for(i <- 1 to count) + // yield ModelElementLists.getDirectElementsFromType(ModelConstants.TEAM_MODEL_TYPE).find(p => p.asInstanceOf[Team].getTeamName().equals(s"Team ${i}")).get.asInstanceOf[Team] + + (initResponse, employeeGuids) + } + + def createElements(count: Int, teamCount: Int): (ConflictResolutionResponse, Seq[String], Seq[String]) ={ + // Initial creation of elements + val clientChangeRecords = ListBuffer[ClientChangeRecord]() + val clientEntireRecords = ListBuffer[ClientEntireRecord]() + + for(i <- 0 until count) { + clientChangeRecords.append(ClientChangeRecord(ModelConstants.MEMBER_MODEL_TYPE, s"e${i} t${Thread.currentThread().getId}", 0, 0, + Map("birthday" -> s"${i}.01.1995", "lastName" -> s"Member ${i}", "address" -> "Dresden"), Map(), Map(), s"e${i} t${Thread.currentThread().getId}", s"testuser${Thread.currentThread().getId}", refonly = false)) + clientEntireRecords.append(ClientEntireRecord(s"e${i} t${Thread.currentThread().getId}", 0, 0, ModelConstants.MEMBER_MODEL_TYPE)) + } + for(i <- 0 until teamCount){ + clientChangeRecords.append(ClientChangeRecord(ModelConstants.TEAM_MODEL_TYPE, s"t${i} t${Thread.currentThread().getId}", 0, 0, + Map("teamName" -> s"Team ${i}"), Map(), Map(), s"t${i} t${Thread.currentThread().getId}", s"testuser${Thread.currentThread().getId}", refonly = false)) + clientEntireRecords.append(ClientEntireRecord(s"t${i} t${Thread.currentThread().getId}", 0, 0, ModelConstants.TEAM_MODEL_TYPE)) + } + + val initResponse = ConflictResolution.syncModel("creation", clientChangeRecords, clientEntireRecords, count, s"testuser${Thread.currentThread().getId}") + val employeeGuids = initResponse.changes.filter(x => x.model == ModelConstants.MEMBER_MODEL_TYPE).map(x => x.guid) + val teamGuids = initResponse.changes.filter(x => x.model == ModelConstants.TEAM_MODEL_TYPE).map(x => x.guid) + + if(employeeGuids.length != count) + error("Employee count does not match") + if(teamGuids.length != teamCount) + error("Team count does not match") + +// val teams: Seq[Team] = for(i <- 1 to count) +// yield ModelElementLists.getDirectElementsFromType(ModelConstants.TEAM_MODEL_TYPE).find(p => p.asInstanceOf[Team].getTeamName().equals(s"Team ${i}")).get.asInstanceOf[Team] + + (initResponse, employeeGuids, teamGuids) + } + + @Test + def testSimpleCreation(): Unit = { + MetaModels.reset() + createElements(1, 1) + ModelElementLists.printAll() + } + + @Test + def testCreation(): Unit ={ + for(m <- 1 to 2) { + val times = ListBuffer[PerformanceInformation]() + for (count <- 100 to 500 by 100) { + for (n <- 0 until 5) { + println(s"${n} ${count}") + MetaModels.reset() + val (response, _, _) = createElements(count, 0) + times.append(response.performance) + } + } + PerformanceCounter.writeRecords(times, "../../evaluation/bench_creation.csv") + } + } + + def oneDeletionIteration(count: Int, threadCount: Int): PerformanceInformation = { + val (creationResult, employeeGuids, teamGuids) = createElements(count, 0) + + val clientChangeRecords = ListBuffer[ClientChangeRecord]() + val clientEntireRecords = ListBuffer[ClientEntireRecord]() + + val countConflicts = Math.ceil(count / 10.0).toInt + for (i <- 0 until count) { + val ts = if (i % countConflicts == 0) 3 else 2 + clientChangeRecords.append(ClientChangeRecord(ModelConstants.MEMBER_MODEL_TYPE, employeeGuids(i), 1, -ts, + Map("birthday" -> "01.01.1995", "fullName" -> s"Member ${i}", "address" -> "Dresden", "salary" -> "0.0"), Map(), Map(), s"e${i} t${Thread.currentThread().getId}", s"${Thread.currentThread().getId}", refonly = false)) + clientEntireRecords.append(ClientEntireRecord(employeeGuids(i), -ts, 1, ModelConstants.MEMBER_MODEL_TYPE)) + } + + val result = ConflictResolution.syncModel("deletion", clientChangeRecords, clientEntireRecords, count * 3, s"testuser${Thread.currentThread().getId}", threadCount) + + result.performance + } + + def oneModificationIteration(count: Int, threadCount: Int): PerformanceInformation = { + val clientChangeRecords = ListBuffer[ClientChangeRecord]() + val clientEntireRecords = ListBuffer[ClientEntireRecord]() + val countConflicts = Math.ceil(count / 10.0).toInt + + val (creationResult, employeeGuids, teamGuids) = createElements(count, 0) + + // Change elements: Some with lower ts than already registered + for (i <- 0 until count) { + val ts = if (i % countConflicts == 0) 2 else 1 + clientChangeRecords.append(ClientChangeRecord(ModelConstants.MEMBER_MODEL_TYPE, employeeGuids(i), 1, ts, + Map("birthday" -> s"0${i}.01.1995", "fullName" -> s"Member ${i}", "address" -> "Dresden", "salary" -> "0"), Map(), Map(), s"e${i} t${Thread.currentThread().getId}", s"${Thread.currentThread().getId}", refonly = false)) + clientEntireRecords.append(ClientEntireRecord(employeeGuids(i), ts, 1, ModelConstants.MEMBER_MODEL_TYPE)) + } + val modificationResult = ConflictResolution.syncModel("modification", clientChangeRecords, clientEntireRecords, count * 3, s"testuser${Thread.currentThread().getId}", threadCount) + + modificationResult.performance + } + + def oneReferenceDeletionIteration(count: Int, threadCount: Int): PerformanceInformation = { + val countConflicts = Math.ceil(count / 10.0).toInt + + val clientChangeRecords = ListBuffer[ClientChangeRecord]() + val clientEntireRecords = ListBuffer[ClientEntireRecord]() + // val clientChangeRecords2 = ListBuffer[ClientChangeRecord]() + // val clientEntireRecords2 = ListBuffer[ClientEntireRecord]() + + val (creationResult, employeeGuids, teams) = createElements(count, count) + + for(i <- 0 until count) { + //val rv = if (i % countConflicts == 0) 3 else 2 + clientChangeRecords.append(ClientChangeRecord(ModelConstants.TEAM_MODEL_TYPE, teams(i), 1, 1, + Map(), Map(), Map("members" -> Set(employeeGuids(i))), s"Team0", s"${Thread.currentThread().getId}", refonly = false)) + // clientEntireRecords.append(ClientEntireRecord(employeeGuids(i), 2, 1, ModelConstants.EMPLOYEE_MODEL_TYPE)) + clientEntireRecords.append(ClientEntireRecord(teams(i), 1, 1, ModelConstants.TEAM_MODEL_TYPE)) + + if (i % countConflicts == 0) { + clientChangeRecords.append(ClientChangeRecord(ModelConstants.TEAM_MODEL_TYPE, teams(i), 2, 1, + Map(), Map(), Map("members" -> Set(employeeGuids(i))), "Team0", s"${Thread.currentThread().getId}", refonly = false)) + //clientEntireRecords.append(ClientEntireRecord(employeeGuids(i), 3, 1, ModelConstants.EMPLOYEE_MODEL_TYPE)) + //clientEntireRecords.append(ClientEntireRecord(teamGuids(i), 3, 1, ModelConstants.TEAM_MODEL_TYPE)) + } + } + + val result1 = ConflictResolution.syncModel("referencedeletion", clientChangeRecords, clientEntireRecords, count * 3, s"testuser${Thread.currentThread().getId}", threadCount) + val r1performance = result1.performance + + // val result2 = ConflictResolution.syncModel("referencedeletion", clientChangeRecords2, clientEntireRecords2) + // val r2performance = result2.performance + + r1performance + //PerformanceInformation(r2performance.thread, r2performance.lockFailures + r1performance.lockFailures, r2performance.name, r1performance.time + r2performance.time, count, r1performance.threads) + } + + @Test + def testModification(): Unit ={ + for(m <- 1 to 2) { + val times = ListBuffer[PerformanceInformation]() + for (count <- 30 to 300 by 30) { + println(s"${count}") + for (n <- 1 to 8) { + MetaModels.reset() + + times.append(oneModificationIteration(count, 1)) + } + } + PerformanceCounter.writeRecords(times, "../../evaluation/bench_modification.csv") + } + } + + @Test + def testModificationParallel() { + val perflist = ListBuffer[PerformanceInformation]() + val executor = Executors.newFixedThreadPool(4) + + for (threads <- 1 to 4) { + for (count <- 30 to 300 by 30) { + val m = if(threads == 1) 6 else 3 + for (n <- 1 to m) { + println(s"THREADS: ${threads} COUNT: ${count} N: ${n}") + + MetaModels.reset() + + val run: Callable[PerformanceInformation] = () => oneModificationIteration(count, threads) + val futures = for (i <- 0 until threads) yield executor.submit(run) + + futures.foreach { f => + val perf = f.get() + perflist.append(perf) + } + } + } + } + + PerformanceCounter.writeRecords(perflist, "../../evaluation/bench_modification_parallel.csv") + } + + @Test + def testDeletion(): Unit = { + val times = ListBuffer[PerformanceInformation]() + + for(m <- 1 to 2) { + for (count <- 30 to 300 by 30) { + for (n <- 1 to 5) { + println(s"COUNT: ${count} N: ${n}") + + MetaModels.reset() + val result = oneDeletionIteration(count, 1) + times.append(result) + } + } + + PerformanceCounter.writeRecords(times, "../../evaluation/bench_deletion.csv") + } + } + + @Test + def testDeletionParallel(): Unit ={ + val perflist = ListBuffer[PerformanceInformation]() + val executor = Executors.newFixedThreadPool(4) + + for (threads <- 1 to 4) { + for (count <- 30 to 300 by 30) { + for (n <- 1 to 4) { + println(s"THREADS: ${threads} COUNT: ${count} N: ${n}") + + MetaModels.reset() + + val run: Callable[PerformanceInformation] = () => oneDeletionIteration(count, threads) + val futures = for (i <- 0 until threads) yield executor.submit(run) + + futures.foreach { f => + val perf = f.get() + perflist.append(perf) + } + } + } + } + + PerformanceCounter.writeRecords(perflist, "../../evaluation/bench_deletion_parallel.csv") + } + + @Test + def testReferenceDeletion(): Unit = { + for(m <- 1 to 2) { + val times = ListBuffer[PerformanceInformation]() + + // Delete some elements: Some twice + for (count <- 30 to 300 by 30) { + for (n <- 1 to 6) { + println(s"COUNT: ${count} N: ${n}") + + MetaModels.reset() + + val performanceInformation = oneReferenceDeletionIteration(count, 1) + times.append(performanceInformation) + } + } + + PerformanceCounter.writeRecords(times, "../../evaluation/bench_reference_deletion.csv") + } + } + + @Test + def testParallelReferenceDeletion(): Unit = { + val executor = Executors.newFixedThreadPool(4) + + for(m <- 1 to 2) { + val times = ListBuffer[PerformanceInformation]() + + // Delete some elements: Some twice + for (threads <- 1 to 4) { + for (count <- 30 to 300 by 30) { + val iter = if(threads == 1) 8 else 5 + for (n <- 1 to iter) { + println(s"THREADS: ${threads} COUNT: ${count} N: ${n}") + + MetaModels.reset() + + val run: Callable[PerformanceInformation] = () => oneReferenceDeletionIteration(count, threads) + val futures = for (i <- 0 until threads) yield executor.submit(run) + + futures.foreach { f => + val perf = f.get() + times.append(perf) + } + } + } + } + + PerformanceCounter.writeRecords(times, "../../evaluation/bench_reference_deletion_parallel.csv") + } + } +} diff --git a/crm-example/src/test/java/RsyncOnlyBenchmark.scala b/crm-example/src/test/java/RsyncOnlyBenchmark.scala new file mode 100644 index 0000000000000000000000000000000000000000..7c45c0b8eb8040a8da493a1b80dcc5cd6b9077a2 --- /dev/null +++ b/crm-example/src/test/java/RsyncOnlyBenchmark.scala @@ -0,0 +1,105 @@ +import de.tudresden.inf.st.crme.models.MetaModels +import de.tudresden.inf.st.crme.models.modelA.Employee +import de.tudresden.inf.st.crme.models.modelB.{Member, Team} +import de.tudresden.inf.st.crme.models.modelC.SimpleEmployee +import de.tudresden.inf.st.crme.rsync.constants.ModelConstants +import org.junit.jupiter.api.{BeforeAll, BeforeEach, Test} +import org.rosi_project.model_management.core.ModelElementLists +import org.rosi_project.model_management.util.{PerformanceCounter, RsyncOnlyPerformanceInformation} + +import scala.collection.mutable.ListBuffer + + +class RsyncOnlyBenchmark { + @BeforeEach + def init(): Unit ={ + MetaModels.initCrmMetaModels() + } + + def createElementsRsyncOnly(count: Int): Seq[Member] ={ + MetaModels.reset() + val t = new Team("Team 0", null, Set(), null, "t0", "user1") + val employees = for(i <- 1 to count) yield new Member("01.01.1995", "Tim", "Dresden", "K", "Dresden", t, t, null, s"e${i}", "user1") + + employees + } + + @Test + def modificationRsyncOnly: Unit = { + for(j <- 1 to 2) { + val times = new ListBuffer[RsyncOnlyPerformanceInformation]() + + for (count <- 30 to 300 by 30) { + val countConflicts = Math.ceil(count / 10.0).toInt + + println(s"${count}") + val employees = createElementsRsyncOnly(count) + + for (n <- 1 to 10) { + val start = System.nanoTime() + var i = 0 + employees.foreach { e => + e.setBirthday(s"0${n}.01.1995") + e.syncFieldsToOtherModels() + if(i % countConflicts == 0){ + e.setBirthday(s"test") + e.syncFieldsToOtherModels() + } + i += 1 + } + val duration = System.nanoTime() - start + times.append(RsyncOnlyPerformanceInformation("modification", duration, count * 3)) + } + } + + PerformanceCounter.writeRsyncRecords(times, "../../evaluation/bench_modification_rsync.csv") + } + } + + @Test + def deletionRsyncOnly: Unit = { + val times = new ListBuffer[RsyncOnlyPerformanceInformation]() + + for(j <- 1 to 2) { + for (count <- 30 to 300 by 30) { + println(s"${count}") + val employees = createElementsRsyncOnly(count) + + for (n <- 1 to 8) { + val start = System.nanoTime() + employees.foreach { e => + e.deleteObjectFromSynchro() + } + val duration = System.nanoTime() - start + times.append(RsyncOnlyPerformanceInformation("modification", duration, count * 3)) + } + } + + PerformanceCounter.writeRsyncRecords(times, "../../evaluation/bench_deletion_rsync.csv") + } + } + + @Test + def referenceDeletionRsyncOnly: Unit = { + val times = new ListBuffer[RsyncOnlyPerformanceInformation]() + + for (j <- 1 to 2) { + for (count <- 30 to 300 by 30) { + println(s"${count}") + val employees = createElementsRsyncOnly(count) + + for (n <- 1 to 8) { + val start = System.nanoTime() + employees.foreach { e => + e.setMemberInTeam(null) + e.syncFieldsToOtherModels() + } + val duration = System.nanoTime() - start + times.append(RsyncOnlyPerformanceInformation("referencedeletion", duration, count * 3)) + } + } + + PerformanceCounter.writeRsyncRecords(times, "../../evaluation/bench_reference_deletion_rsync.csv") + } + } +} diff --git a/crm-example/src/test/java/TestCrmSync.scala b/crm-example/src/test/java/TestCrmSync.scala new file mode 100644 index 0000000000000000000000000000000000000000..bf1184a6fbcb869d3d1776e5791cb9aa438f7446 --- /dev/null +++ b/crm-example/src/test/java/TestCrmSync.scala @@ -0,0 +1,81 @@ +import de.tudresden.inf.st.crme.models.MetaModels +import de.tudresden.inf.st.crme.models.modelA.PresenceEmployee +import de.tudresden.inf.st.crme.models.modelB.{Member, Team} +import de.tudresden.inf.st.crme.models.modelC.SimpleEmployee +import de.tudresden.inf.st.crme.rsync.compartments.{CrmModelsConstructionCompartment, CrmModelsDestructionCompartment, CrmModelsSyncCompartment} +import de.tudresden.inf.st.crme.rsync.constants.ModelConstants +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import org.rosi_project.model_management.core.{ModelElementLists, SynchronizationCompartment} +import org.rosi_project.model_management.sync.lock.{ElementLock, ElementLockProvider} +import org.rosi_project.model_management.util.UuidUtil +import org.slf4j.{Logger, LoggerFactory} +import scroll.internal.Compartment + +class TestCrmSync { + val log: Logger = LoggerFactory.getLogger(getClass) + + @Test + def testSync(){ + new Compartment { + MetaModels.initCrmMetaModels() + + val lock: ElementLock = ElementLockProvider.provideLockObject() + + val simpleEmployee: SimpleEmployee = new SimpleEmployee("16.07.95", false, "NEWTEAM", "John Doe", "Sample Address 123", lock, UuidUtil.generateUuid(), "owner1") + val team = new Team("ATeam", null, Set(), lock, UuidUtil.generateUuid(), "owner1") + val member: Member = new Member("01.01.2001", "Max", "Headquarter", "Muster", "Sample Address 456", team, null, lock, + UuidUtil.generateUuid(), "owner1") + new PresenceEmployee("Jane Doe", "05.06.1999", "Sample Address 789", 4000.00f, lock, UuidUtil.generateUuid(), "owner1") + + ElementLockProvider.removeLocks(Set(ModelConstants.MEMBER_MODEL_TYPE, ModelConstants.TEAM_MODEL_TYPE), lock.getId()) + + // Assert that all employees have been created as every type + + val presenceEmployees: Set[PresenceEmployee] = ModelElementLists.getElementsFromType("modelA.PresenceEmployee").map(x => x.asInstanceOf[PresenceEmployee]) + assert(presenceEmployees.exists(x => x.getFullName() == "John Doe")) + assert(presenceEmployees.exists(x => x.getFullName() == "Jane Doe")) + assert(presenceEmployees.exists(x => x.getFullName() == "Max Muster")) + + val simpleEmployees: Set[SimpleEmployee] = ModelElementLists.getElementsFromType("modelC.SimpleEmployee").map(x => x.asInstanceOf[SimpleEmployee]) + assert(simpleEmployees.exists(x => x.getFullName() == "John Doe")) + assert(simpleEmployees.exists(x => x.getFullName() == "Jane Doe")) + assert(simpleEmployees.exists(x => x.getFullName() == "Max Muster")) + + val members: Set[Member] = ModelElementLists.getElementsFromType("modelB.Member").map(x => x.asInstanceOf[Member]) + assert(members.exists(x => x.getFullName() == "John Doe")) + assert(members.exists(x => x.getFullName() == "Jane Doe")) + assert(members.exists(x => x.getFullName() == "Max Muster")) + + + // ModelElementLists.printAll() + // log.error("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%") + + simpleEmployee.setTeam("TEAM TEAM TEAM") + simpleEmployee.syncFieldsToOtherModels() + + // assert(ModelElementLists.getElementsFromType("modelB.Member").map(x => x.asInstanceOf[Member]).exists(x => x.getMemberInTeam() != null && x.getMemberInTeam().getTeamName() == "TEAM TEAM TEAM")) + + member.setFirstName("Sebastian") + member.syncFieldsToOtherModels() + + assert(ModelElementLists.getElementsFromType("modelC.SimpleEmployee").map(x => x.asInstanceOf[SimpleEmployee]).exists(x => x.getFullName() == "Sebastian Muster")) + + team.addMember(member) + + assert(ModelElementLists.getElementsFromType("modelC.SimpleEmployee").map(x => x.asInstanceOf[SimpleEmployee]).exists(x => x.getTeam() != null && x.getTeam() == team.getTeamName() && x.getFullName() == "Sebastian Muster")) + + //ModelElementLists.printAll() + //log.error("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%--") + + team.deleteObjectFromSynchro() + member.deleteObjectFromSynchro() + ModelElementLists.printAll() + + assert(ModelElementLists.getElementsFromType("modelB.SimpleEmployee").map(x => x.asInstanceOf[SimpleEmployee]).forall(x => !(x.getFullName() == member.getFullName()))) + + // log.error("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%--") + // assertEquals("Hello", "Hello"); + } + } +}