Skip to content
Snippets Groups Projects
Commit 164df670 authored by Sebastian Ebert's avatar Sebastian Ebert
Browse files

initial parallel rsync contribution

parents
No related branches found
No related tags found
No related merge requests found
Showing
with 2117 additions and 0 deletions
target/
!.mvn/wrapper/maven-wrapper.jar
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
.nb-gradle/
### general ###
*.log
*.cache-main
<?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>conflictresolver</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>Role-Model-Sync Conflict-Resolver</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>
</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>
</build>
</project>
\ No newline at end of file
package org.rosi_project.model_management
import org.rosi_project.model_management.core.{ConflictResolvable, ModelElementLists, ModelInformation, PlayerSync}
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.lock.{ElementLock, ElementLockProvider}
import org.rosi_project.model_management.sync.procedures.data.ClientEntireRecord
import org.rosi_project.model_management.util.{DuplicateValidator, PerformanceCounter, PerformanceInformation, UuidUtil}
import org.slf4j.LoggerFactory
import scroll.internal.Compartment
import scala.collection.mutable
import scala.collection.mutable.ListBuffer
import scala.reflect.classTag
import scala.sys.error
case class SynchronizationResult(lockFailCounter: Int, deletions: Seq[ConflictResolvable])
case class ReferenceResolutionResult(lockFailCounter: Int, notUpdatedOnServer: Set[String])
case class ApplyReferenceResult(successes: Int, notUpdatedOnServer: Set[String])
object ConflictResolution {
val logger = LoggerFactory.getLogger(getClass)
private def applyRefDeletions(targetObject: ConflictResolvable, targetId: String, change: ClientChangeRecord, idMapping: mutable.Map[String, String]): ApplyReferenceResult = {
var successCounter: Int = 0
var notUpdatedOnServer: Set[String] = Set()
val serialized = mutable.Map(targetObject.serialize.toSeq:_*)
change.deletedReferencesTuples.foreach { case (fieldName, oref) =>
val guid = idMapping.getOrElse(oref, oref)
val fieldType = ModelInformation.getAssociationFieldType(change.model, fieldName)
val referencedObject = SystemRuleExecutor.resolveDeletedReferencedElementReferenceConflicts(guid, fieldType).asInstanceOf[ConflictResolvable]
if (referencedObject != null && CustomRuleExecutor
.matchesAllCustomReferenceRules(targetObject, referencedObject, change.rv, isDeletion = true, change.owner, fieldName)) {
logger.info(s"removed ref from ${change.model}: ${targetObject.guid}")
var guidList = serialized(fieldName).split('|').to[Set]
guidList -= referencedObject.guid
serialized.put(fieldName, guidList.mkString ("|"))
successCounter = successCounter + 1
} else {
notUpdatedOnServer += targetId
}
}
targetObject.unserialize(serialized.toMap.withDefaultValue(""))
ApplyReferenceResult(successCounter, notUpdatedOnServer)
}
private def applyRefAdditions(targetObject: ConflictResolvable, targetId: String, change: ClientChangeRecord, idMapping: mutable.Map[String, String]): ApplyReferenceResult = {
var successCounter: Int = 0
var notUpdatedOnServer: Set[String] = Set()
val serialized = mutable.Map(targetObject.serialize().toSeq:_*)
change.addedReferencesTuples.foreach { case (fieldName, ref) =>
val fieldType = ModelInformation.getAssociationFieldType(change.model, fieldName)
val referencedId = idMapping.getOrElse(ref, ref)
val referencedObject: PlayerSync = SystemRuleExecutor.resolveDeletedReferencedElementReferenceConflicts(referencedId, fieldType)
if(referencedObject != null && CustomRuleExecutor.matchesAllCustomReferenceRules(targetObject, referencedObject, change.rv, isDeletion = false, change.owner, fieldName)){
logger.info(s"added ref from ${change.model}: ${targetObject.guid}")
var guidList = serialized(fieldName).split('|').to[Set]
guidList += referencedId
serialized.put(fieldName, guidList.mkString ("|"))
successCounter = successCounter + 1
} else {
notUpdatedOnServer += targetId
}
}
if(successCounter > 0){
targetObject.rv += 1
}
ApplyReferenceResult(successCounter, notUpdatedOnServer)
}
private def syncDeletions(changes: Seq[ClientChangeRecord], lock: ElementLock, idMapping: mutable.Map[String, String]): SynchronizationResult = {
var lockFailCounter: Int = 0
val deletions: mutable.ListBuffer[ConflictResolvable] = ListBuffer()
changes.foreach { change =>
if (change.ts < 0) {
val lockRes = ElementLockProvider.provideLockWithId(change.guid, lock.getId())
if(lockRes.success || lockRes.wasDeleted){
val res: (Boolean, PlayerSync) = SystemRuleExecutor.resolveDataDeletionConflicts(change.ts, change.owner, change.guid, change.model)
if(res._1){
val deleted: ConflictResolvable = res._2.asInstanceOf[ConflictResolvable]
if(deleted.guid == change.guid){
logger.info(s"Deleting ${change.model} with guid ${change.guid}")
deleted.deleteObjectFromSynchro()
deletions += deleted
}
}
} else if(!lockRes.success || lockRes.lock == null || !lockRes.wasDeleted ) {
lockFailCounter += 1
}
}
}
SynchronizationResult(lockFailCounter, deletions)
}
private def syncNewElements(changes: Seq[ClientChangeRecord], lock: ElementLock, idMapping: mutable.Map[String, String]): Set[ConflictResolvable] ={
val newObjects = mutable.Set[ConflictResolvable]()
changes.foreach(change => {
if(change.ts == 0) {
if (!idMapping.contains(change.lokalId)) {
val model: String = change.model
val guid: String = UuidUtil.generateUuid()
val data = change.updatedFields.withDefaultValue("") + ("owner" -> change.owner)
val newObject: ConflictResolvable = Class.forName(model)
.getConstructor(classTag[String].runtimeClass, classTag[ElementLock].runtimeClass, classTag[Map[String, String]].runtimeClass)
.newInstance(guid, lock, data).asInstanceOf[ConflictResolvable]
newObject.ts = 1
newObject.rv = 1
idMapping += change.lokalId -> guid
newObjects.add(newObject)
} else
logger.error("Ignored duplicate element: " + change.guid)
}
})
newObjects.toSet
}
private def syncModifications(changes: ListBuffer[ClientChangeRecord], lock: ElementLock): SynchronizationResult = {
var lockFailCounter = 0
val modifications = ListBuffer[ConflictResolvable]()
changes.foreach { change =>
if(change.ts > 0 && !change.refonly){
val lockRes = ElementLockProvider.provideLockWithId(change.guid, lock.getId())
if(lockRes.success || lockRes.wasDeleted){
val res = SystemRuleExecutor.resolveDataModificationConflicts(change.ts, change.owner, change.guid, change.model)
if(res._1){
val data: ConflictResolvable = res._2.asInstanceOf[ConflictResolvable]
if(data.guid == change.guid){
data.unserialize(change.updatedFields.withDefaultValue(""))
data.owner = change.owner
if(data.ts == Int.MaxValue){
data.ts = 1
} else {
data.ts += 1
}
data.syncFieldsToOtherModels()
modifications.append(data)
}
}
changes -= change
if(lockRes.success) ElementLockProvider.removeLocks(Set(change.model), lockRes.lock.getId())
} else if(!lockRes.success && lockRes.lock == null && !lockRes.wasDeleted){
lockFailCounter += 1
}
}
}
SynchronizationResult(lockFailCounter, modifications)
}
private def syncReferenceModsToHub(changes: ListBuffer[ClientChangeRecord], idMapping: mutable.Map[String, String], lock: ElementLock): ReferenceResolutionResult = {
var notUpdatedOnServer: mutable.Set[String] = mutable.Set()
var lockFailCounter: Int = 0
changes.foreach(change => {
if(change.ts > -1 && (change.addedReferences.nonEmpty || change.deletedReferences.nonEmpty)){
val targetId = idMapping.getOrElse(change.lokalId, change.guid)
val collections = (change.addedReferences.keys ++ change.deletedReferences.keys).toSet
// Maps field names to type names
val changedReferencedTypes: Map[String, String] = collections.map(field => (field, ModelInformation.getAssociationFieldType(change.model, field))).toMap
// Maps type names to element guids
val changedReferencedElements: Map[String, Set[String]] = change.changedReferences
.map { case (name, id) => (changedReferencedTypes(name), id) }
.groupBy(_._1).mapValues(ids => ids.map { case (_, id) => idMapping.getOrElse(id, id) }.toSet)
// Lock referencing element and all changed referenced elements
val lockRes = ElementLockProvider.provideLockWithIdForElements(targetId, change.model, changedReferencedElements, lock.getId())
if(lockRes.success || lockRes.wasDeleted){
val targetPlayer: PlayerSync = SystemRuleExecutor.resolveDeletedReferencingElementReferenceConflicts(targetId, change.model)
if(targetPlayer != null){
logger.info(s"Passed ref-checks for ${change.model}")
val targetObject = targetPlayer.asInstanceOf[ConflictResolvable]
var overAllSuccess: Int = 0
// refs can only be removed if the object is not new
if(change.ts >= 0 && targetObject != null) {
if (change.ts > 0) {
val resDel = applyRefDeletions(targetObject, targetId, change, idMapping)
overAllSuccess += resDel.successes
notUpdatedOnServer ++= resDel.notUpdatedOnServer
}
val resAdd = applyRefAdditions(targetObject, targetId, change, idMapping)
overAllSuccess += resAdd.successes
notUpdatedOnServer ++= resAdd.notUpdatedOnServer
if(overAllSuccess > 0){
val currentRv: Int = targetObject.rv
if(currentRv == Int.MaxValue){
targetObject.rv = 1
} else targetObject.rv += 1
}
}
}
changes -= change
if(lockRes.success) ElementLockProvider.removeLocksFromElement(lockRes.lock.getId(), targetId)
} else if(!lockRes.success || lockRes.lock == null || !lockRes.wasDeleted){
lockFailCounter += 1
}
}
})
if(notUpdatedOnServer.nonEmpty){
logger.warn(s"Elements with invalid refs: ${notUpdatedOnServer}")
}
ReferenceResolutionResult(lockFailCounter, notUpdatedOnServer.to[Set])
}
def syncModel(name: String, changesSeq: Seq[ClientChangeRecord], entireRecords: Seq[ClientEntireRecord], elementCount: Int, owner: String, threadCount: Int = 1): ConflictResolutionResponse = {
val startTime = System.nanoTime()
var totalLockFailCounter = 0
val lock: ElementLock = ElementLockProvider.provideLockObject()
val guids: Seq[String] = changesSeq.map(x => x.guid)
val changes: ListBuffer[ClientChangeRecord] = changesSeq.to[ListBuffer]
val changesRef: ListBuffer[ClientChangeRecord] = changesSeq.to[ListBuffer]
var notUpdatedOnServer: Set[String] = Set()
val models: Set[String] = changes.map(x => x.model).toSet
// Reject complete set of changes if any model is unknown
models.foreach(x => {
if(!ModelInformation.modelExists(x)) throw new IllegalArgumentException(s"Model ${x} is unknown")
})
// Reject complete set of changes if an element was modified twice (INS-INS)
// if(DuplicateValidator.containsDuplicates(guids)) throw new IllegalArgumentException("List of changes contains multiple modifications of the same element")
val idMapping = mutable.Map[String, String]()
// Step 1: Create new Elements
val newElements = synchronized {
syncNewElements(changes, lock, idMapping)
}
// Step 2: Refs
var refRetryNeeded = false
do {
val refModRes = syncReferenceModsToHub(changesRef, idMapping, lock)
notUpdatedOnServer ++= refModRes.notUpdatedOnServer
refRetryNeeded = refModRes.lockFailCounter > 0
totalLockFailCounter += refModRes.lockFailCounter
} while(refRetryNeeded)
// Unlock remaining new elements
ElementLockProvider.removeLocksFromElements(lock.getId(), newElements.map(x => x.guid))
// Step 3: Modify
var modRetryNeeded = false
var modTime = System.nanoTime()
do {
val modRes = syncModifications(changes, lock)
modRetryNeeded = modRes.lockFailCounter > 0
totalLockFailCounter += modRes.lockFailCounter
} while(modRetryNeeded)
// Step 4: Deletions
var delRetryNeeded = false
do {
val delRes = syncDeletions(changes, lock, idMapping)
delRetryNeeded = delRes.lockFailCounter > 0
totalLockFailCounter += delRes.lockFailCounter
} while(delRetryNeeded)
val time = System.nanoTime() - startTime
val performanceInformation = PerformanceInformation(Thread.currentThread().getId, totalLockFailCounter, name, time, elementCount, threadCount)
val response = ResponseBuilder.buildResponse(models, idMapping.toMap, entireRecords, notUpdatedOnServer, owner)
.flatMap { case (_, xs) => xs }
.toSeq
// ElementLockProvider.removeLocksInAllModels(lock.getId())
ConflictResolutionResponse(response, performanceInformation)
}
}
package org.rosi_project.model_management
import org.rosi_project.model_management.util.PerformanceInformation
import scala.collection.mutable
import scala.collection.mutable.ListBuffer
case class ConflictResolutionResponse(changes: Seq[ServerChangeRecord], performance: PerformanceInformation)
package org.rosi_project.model_management
import org.rosi_project.model_management.core.{ConflictResolvable, ModelElementLists, ModelInformation, PlayerSync}
import org.rosi_project.model_management.sync.lock.{ElementLock, ElementLockProvider, LockResult, SynchronizationAware}
import org.rosi_project.model_management.sync.procedures.BaseResponseGeneration
import org.rosi_project.model_management.sync.procedures.data.{ClientEntireRecord, IServerReferenceChangeRecord}
import org.rosi_project.model_management.sync.snapshot.{Snapshot, SnapshotProvider}
import org.slf4j.LoggerFactory
import scala.collection.mutable
import scala.collection.mutable.ListBuffer
import scala.util.control.Breaks.{break, breakable}
object ResponseBuilder extends BaseResponseGeneration {
val logger = LoggerFactory.getLogger(classOf[PlayerSync])
def buildReferenceChanges(snapshot: ListBuffer[Snapshot], idMapping: Map[String, String], cer: Seq[ClientEntireRecord], notUpdatedOnServer: Set[String], lock: ElementLock,
records: mutable.Map[String, ListBuffer[ServerChangeRecord]], referenceRecords: ListBuffer[ServerReferenceChangeRecord],
processedReferencingElements: ListBuffer[String], owner: String): Int = {
var lockFailCounter: Int = 0
snapshot.foreach { sn =>
var found = false
if(!processedReferencingElements.contains(sn.guid)){
breakable {
cer.foreach { ic =>
val realGuid = idMapping.getOrElse(ic.guid, ic.guid)
val element = ModelElementLists.getElementByGuid(realGuid).asInstanceOf[ConflictResolvable]
if(sn.guid == realGuid){
found = true
if(sn.rv > getCerRv(cer, realGuid) || notUpdatedOnServer.contains(realGuid)){
val lockResult = ElementLockProvider.provideLockWithId(realGuid, lock.getId())
if(lockResult.wasDeleted){
processedReferencingElements += realGuid
break
}
if(lockResult.success && !lockResult.wasDeleted){
cleanRefs(sn.guid, sn.elementKey)
val refs: Set[String] = element.getAssociated.values.flatten.toSet[ConflictResolvable].map(x => x.guid)
val refLockRefs = ElementLockProvider.provideLockWithIdForElementList(refs, lock.getId())
// Handle results of reference-locks
if(refLockRefs.lock == null){
// Lock failed on a minimum of 1 referenced element
lockFailCounter += 1
ElementLockProvider.removeLocksInAllModels(lock.getId())
break
} else {
// Lock Success
val refRecordRefs: ListBuffer[String] = ListBuffer()
var recordRvDemotion: Boolean = false
var recordRv: Int = 0
// Integrate references in response
refLockRefs.elements.foreach { ref =>
if(SnapshotProvider.snapshotContains(snapshot, ref.guid)){
refRecordRefs += ref.guid
} else {
recordRvDemotion = true
}
}
if(!recordRvDemotion){
recordRv = sn.rv
}
referenceRecords += ServerReferenceChangeRecord(element.getClass.getName, realGuid, sn.ts, recordRv, refRecordRefs)
processedReferencingElements += realGuid
}
}
if(!lockResult.success && lockResult.lock == null && !lockResult.wasDeleted){
// No lock-success, do nothing
lockFailCounter += 1
break
}
if(realGuid == sn.guid){
ElementLockProvider.removeLocksInAllModels(lock.getId())
break
}
}
}
}
if(!found){
if(!integrateNewRefsFromNewElements(sn, snapshot, lock, processedReferencingElements, referenceRecords)){
lockFailCounter += 1
}
}
}
}
}
lockFailCounter
}
private def cleanRefs(guid: String, model: String): Unit = {
val elementSet: Set[SynchronizationAware] = ModelElementLists.getDirectElementsFromType(model)
val refsToRemove: ListBuffer[ConflictResolvable] = new ListBuffer[ConflictResolvable]()
var element: ConflictResolvable = null
breakable {
elementSet.foreach { e =>
element = e.asInstanceOf[ConflictResolvable]
if (element.guid == guid) {
element.getRelatedObjects().foreach { refd =>
if (refd == null || refd.isDeleted) {
logger.info("Found invalide ref... queueing it for removal.")
refsToRemove += refd.asInstanceOf[ConflictResolvable]
}
}
break
}
}
}
refsToRemove.foreach { r =>
element.removeAssociation(r)
}
}
private def integrateNewRefsFromNewElements(sn: Snapshot, snapshot: ListBuffer[Snapshot], lock: ElementLock, processedReferencingElements: ListBuffer[String],
referenceRecords: ListBuffer[ServerReferenceChangeRecord]): Boolean = {
val lockRes: LockResult = ElementLockProvider.provideLockWithId(sn.guid, lock.getId())
if (lockRes.wasDeleted) {
processedReferencingElements += sn.guid
}
if (lockRes.success && !lockRes.wasDeleted) {
val element = ModelElementLists.getElementByGuid(sn.guid).asInstanceOf[ConflictResolvable]
val associated = element.getAssociated
val refs: Set[String] = associated.values.flatten.map(x => x.guid).toSet
val refLockRes = ElementLockProvider.provideLockWithIdForElementList(refs, lock.getId())
if (refLockRes.lock == null) {
ElementLockProvider.removeLocksInAllModels(lock.getId())
return false
} else {
val refRecordRefs: ListBuffer[String] = ListBuffer()
var recordRvDemotion: Boolean = false
var recordRv: Int = 0
refLockRes.elements.foreach { ref =>
if (SnapshotProvider.snapshotContains(snapshot, ref.guid)) {
refRecordRefs += ref.guid
} else {
recordRvDemotion = true
}
}
if (!recordRvDemotion) {
recordRv = sn.rv
}
referenceRecords += ServerReferenceChangeRecord(sn.elementKey, sn.guid, sn.ts, recordRv, refRecordRefs)
processedReferencingElements += sn.guid
ElementLockProvider.removeLocksInAllModels(lock.getId())
return true
}
}
ElementLockProvider.removeLocksInAllModels(lock.getId())
false
}
def buildResponse(models: Set[String], idMapping: Map[String, String], cer: Seq[ClientEntireRecord], notUpdatedOnServer: Set[String], owner: String): mutable.Map[String, ListBuffer[ServerChangeRecord]] = {
val responseLock = ElementLockProvider.provideLockObject()
val snapshot0 = SnapshotProvider.provideSnapshot(models)
val snapshot1 = SnapshotProvider.copySnapshot(snapshot0)
val changeRecords: mutable.Map[String, ListBuffer[ServerChangeRecord]] = mutable.Map[String, ListBuffer[ServerChangeRecord]]().withDefault(_ => ListBuffer())
val changeRefRecords: mutable.Map[String, ListBuffer[ServerReferenceChangeRecord]] = mutable.Map[String, ListBuffer[ServerReferenceChangeRecord]]().withDefault(_ => ListBuffer())
val processedReferencingElements: ListBuffer[String] = ListBuffer[String]()
var dataRetryNeeded = true
while(dataRetryNeeded){
val dataLockFails: Int = buildDataChanges(snapshot0, idMapping, cer, notUpdatedOnServer, responseLock, changeRecords, owner)
if(dataLockFails == 0) dataRetryNeeded = false
}
var refRetryNeeded = true
while(refRetryNeeded){
val refLockFails: Int = buildReferenceChanges(snapshot1, idMapping, cer, notUpdatedOnServer, responseLock, changeRecords,
ListBuffer(changeRefRecords.values.toSeq.flatten:_*), processedReferencingElements, owner)
if(refLockFails == 0) refRetryNeeded = false
}
// ElementLockProvider.removeLocksInAllModels(responseLock.getId())
changeRecords
}
def buildDataChanges(snapshot: ListBuffer[Snapshot], idMapping: Map[String, String], cer: Seq[ClientEntireRecord], notUpdatedOnServer: Set[String],
lock: ElementLock, records: mutable.Map[String, ListBuffer[ServerChangeRecord]], owner: String): Int = {
var lockFailCounter: Int = 0
snapshot.foreach { sn =>
var found: Boolean = false
breakable {
cer.foreach { r =>
val realGuid = idMapping.getOrElse(r.guid, r.guid)
// Check if element needs to be locked (if there are changes)
if(realGuid == sn.guid && sn.ts > r.ts){
val lockResult: LockResult = ElementLockProvider.provideLockWithId(realGuid, lock.getId())
if(lockResult.success && !lockResult.wasDeleted){
val element = ModelElementLists.getElementByGuid(realGuid).asInstanceOf[ConflictResolvable]
val elements = records(r.elementType)
elements.append(ServerChangeRecord(r.elementType, realGuid, element.ts, element.rv, refonly = false, realGuid, element.owner, element.serialize()))
records.put(r.elementType, elements)
snapshot -= sn
}
if(lockResult.wasDeleted){
val elements = records(r.elementType)
elements.append(ServerChangeRecord(r.elementType, r.guid, 0, 0, refonly = false, "", "", Map()))
records.put(r.elementType, elements)
snapshot -= sn
}
if(!lockResult.success && lockResult.lock == null && !lockResult.wasDeleted){
lockFailCounter += 1
}
}
if(realGuid == sn.guid){
found = true
break
}
}
}
// New element
if(!found) {
val element = ModelElementLists.getElementByGuid(sn.guid).asInstanceOf[ConflictResolvable]
if(element.owner == owner) {
val elementType = element.getClass.getName
val elements = records(elementType)
elements.append(ServerChangeRecord(element.getClass.getName, element.guid, element.ts, element.rv, refonly = false, "", element.owner, element.serialize()))
records.put(elementType, elements)
}
snapshot -= sn
}
}
ElementLockProvider.removeLocksInAllModels(lock.getId())
cer.foreach { r =>
if(r.ts != 0){
val element = ModelElementLists.getElementByGuid(r.guid)
if(element == null){
val elements = records(r.elementType)
elements.append(ServerChangeRecord(r.elementType, r.guid, 0, 0, refonly = false, "", "", Map()))
records.put(r.elementType, elements)
}
}
}
lockFailCounter
}
def getCerRv(cer: Seq[ClientEntireRecord], guid: String): Int = {
val element = cer.find(r => r.guid == guid)
if(element.isDefined) element.get.rv else 0
}
}
package org.rosi_project.model_management
/* object ChangeRecordMode extends Enumeration {
type ChangeRecordMode = Value
val Creation, Deletion, Modification = Value
} */
case class ClientChangeRecord(val model: String, val guid: String, val rv: Int, val ts: Int,
val updatedFields: Map[String, String],
val addedReferences: Map[String, Set[String]],
val deletedReferences: Map[String, Set[String]],
val lokalId: String,
val owner: String,
val refonly: Boolean) {
/**
* Returns an iterable of tuples (fieldname, referenced guid)
*/
def addedReferencesTuples: Iterable[(String, String)] = addedReferences.map { case (field, ids) => ids.map(id => (field, id)) }.flatten
/**
* Returns an iterable of tuples (fieldname, referenced guid)
*/
def deletedReferencesTuples: Iterable[(String, String)] = deletedReferences.map { case (field, ids) => ids.map(id => (field, id)) }.flatten
/**
* Returns an iterable tuples (fieldname, reference guid)
*/
def changedReferences: Iterable[(String, String)] = (addedReferencesTuples ++ deletedReferencesTuples)
}
case class ServerChangeRecord(model: String, guid: String, ts: Int, rv: Int, refonly: Boolean, lokalId: String, owner: String,
fields: Map[String, String])
case class ServerReferenceChangeRecord(model: String, guid: String, ts: Int, rv: Int, refs: Seq[String])
\ No newline at end of file
package org.rosi_project.model_management.core
import org.rosi_project.model_management.core.Cardinality.Cardinality
package org.rosi_project.model_management.core
object Cardinality extends Enumeration {
type Cardinality = Value
val One, Many = Value
}
package org.rosi_project.model_management.core
import org.rosi_project.model_management.sync.lock.{ElementLock, SynchronizationAware}
import scala.collection.mutable
import scala.collection.mutable.ListBuffer
import scala.reflect.classTag
import scala.sys.error
abstract class ConflictResolvable(lock: ElementLock, guid: String, owner: String) extends SynchronizationAware(lock, guid, owner) with MapSerializable {
def syncFieldsToOtherModels()
override def equals(other: Any): Boolean = {
other match {
case p: ConflictResolvable => guid.equals(p.guid)
case _ => false
}
}
override def hashCode(): Int = guid.hashCode
override def serialize(): Map[String, String] = {
Map("guid" -> guid, "owner" -> owner)
}
def getAssociations: Set[AssociationField] = ModelInformation.fieldsByName(getClass.getName).filter(p => p.isInstanceOf[AssociationField]).map(p => p.asInstanceOf[AssociationField])
def getAssociated: mutable.Map[AssociationField, mutable.Set[ConflictResolvable]] = {
val serialized = serialize()
val result = mutable.Map[AssociationField, mutable.Set[ConflictResolvable]]()
val associations = getAssociations
associations.foreach { k =>
result.put(k, mutable.Set[ConflictResolvable](ModelInformation.fromGuids(k.typ, serialized(k.name))
.map(x => x.asInstanceOf[ConflictResolvable]).toSeq:_*))
}
result
}
def getReferenced(associations: Set[String]): Set[ConflictResolvable] = {
val data = serialize()
associations.flatMap { f => ModelInformation.fromGuids(classTag[ConflictResolvable], data(f)) }.map(x => x.asInstanceOf[ConflictResolvable])
}
def removeAssociation(element: ConflictResolvable): Unit = {
val associated = getAssociated
associated.foreach { case (field, elements) =>
val found = elements.contains(element)
if(found){
val f: AssociationField = ModelInformation.fieldsByName(element.getClass.getName).find(p => p.name == field).get.asInstanceOf[AssociationField]
f.onRemove(this, element)
}
}
error("Not found")
}
}
package org.rosi_project.model_management.core
import org.rosi_project.model_management.core.Cardinality.Cardinality
import scala.reflect.ClassTag
abstract class Field {
def name: String
def typ: ClassTag[_]
}
object Field {
def primitives(typ: ClassTag[_], names: String*): Seq[Field] = names.map(x => PrimitiveField(x, typ))
def association(typ: ClassTag[_], name: String, cardinality: Cardinality, onAdd: (ConflictResolvable, ConflictResolvable) => Unit, onRemove: (ConflictResolvable, ConflictResolvable) => Unit): Field = AssociationField(name, typ, cardinality, onAdd, onRemove)
}
case class PrimitiveField(name: String, typ: ClassTag[_]) extends Field()
case class AssociationField(name: String, typ: ClassTag[_], cardinality: Cardinality, onAdd: (ConflictResolvable, ConflictResolvable) => Unit, onRemove: (ConflictResolvable, ConflictResolvable) => Unit) extends Field()
package org.rosi_project.model_management.core
import org.rosi_project.model_management.sync.lock.{ElementLock, LockResult, SynchronizationAware}
import scala.collection.parallel
import scala.collection.parallel.mutable.ParMap
import scala.reflect.{ClassTag, classTag}
import scala.sys.error
case class ModelInformation(c: Class[_], parentClass: Class[_], fields: Seq[Field] = Seq())
object ModelInformation {
private val models: parallel.mutable.ParMap[Class[_], Set[Field]] = ParMap()
private val modelsParentClass: parallel.mutable.ParMap[Class[_], Class[_]] = ParMap().withDefaultValue(null)
def add(m: ModelInformation*): Unit = {
synchronized {
m.foreach { x =>
models.put(x.c, x.fields.toSet)
if (x.parentClass != null) modelsParentClass.put(x.c, x.parentClass)
}
}
}
/**
* Returns the type of a association field in a registered class
* @param typ Full name of class
* @param field Name of field
*/
def getAssociationFieldType(typ: String, field: String): String =
models(Class.forName(typ))
.find(f => f.name == field).getOrElse(error(s"Field ${field} not found for type ${typ}")).typ.runtimeClass.getName
def fieldsByName(c: String): Set[Field] = {
val cl = Class.forName(c).asSubclass(classTag[ConflictResolvable].runtimeClass)
val parent = modelsParentClass(cl)
val parentFields = if(parent != null) fieldsByName(c) else Set()
models(cl) ++ parentFields
}
def modelExists(c: String): Boolean = {
models.contains(Class.forName(c))
}
def getGuid(c: SynchronizationAware): String = if(c != null) c.guid else ""
def getGuids(c: Set[SynchronizationAware]): String = c.filter(x => x != null).map(x => x.guid).mkString("|")
def fromGuid(c: String): SynchronizationAware = if(c != "") ModelElementLists.getElementByGuid(c).asInstanceOf[SynchronizationAware] else null.asInstanceOf[SynchronizationAware]
def fromGuids(t: ClassTag[_], c: String): Set[SynchronizationAware] = {
val list = ModelElementLists.getDirectElementsFromType(t.runtimeClass.getName).map(x => (x.guid, x)).toMap
c.split('|').map(x => if(x != ""){
list(x)
} else null).toSet[SynchronizationAware].filter(x => x != null)
}
}
trait MapSerializable {
def serialize: Map[String, String] = Map()
def unserialize(data: Map[String, String]) = {}
}
package org.rosi_project.model_management.core
import org.slf4j.LoggerFactory
import org.rosi_project.model_management.sync.lock._
import java.util.concurrent.ConcurrentHashMap
/**
* Provides convenient access to all instances of the synchronized models.
*
* New models may be registered by name to simplify retrieving their instances.
*
* Retrieval operations (including get) generally do not block, so may overlap with update operations (including put and remove).
*/
object ModelElementLists {
// element in top-hash-map is only locked on model-creation
// top-level: models, second-level: elements
var elements: ConcurrentHashMap[Class[_ <: AnyRef], ConcurrentHashMap[String, AnyRef]] =
new ConcurrentHashMap[Class[_ <: AnyRef], ConcurrentHashMap[String, AnyRef]]()
var model2Class: ConcurrentHashMap[String, Class[_ <: AnyRef]] = new ConcurrentHashMap[String, Class[_ <: AnyRef]]()
val logger = LoggerFactory.getLogger(ModelElementLists.getClass)
def getElementByGuid(guid: String): AnyRef = {
elements.keySet().forEach { e =>
val elem: AnyRef = elements.get(e).get(guid)
if (elem != null) {
return elem
}
}
null
}
/**
* Inserts a new instance.
*
* The appropriate model will be inferred automatically
*
* @param obj the instance. May never be `null`
*/
def addElement(obj: Object): Unit = {
if (obj == null) {
return
}
var elementsWithClass = elements.get(obj.getClass)
if (elementsWithClass == null) {
logger.info("" + elements + " / " + obj)
initThreadSave(obj, elementsWithClass)
//elements.put(obj.getClass, new ConcurrentHashMap[String, AnyRef]())
elementsWithClass = elements.get(obj.getClass)
}
if (elementsWithClass.isEmpty) {
var value: ConcurrentHashMap[String, AnyRef] = new ConcurrentHashMap[String, AnyRef]()
value.put(obj.asInstanceOf[SynchronizationAware].guid, obj)
elements.put(obj.getClass, value)
} else {
elementsWithClass.put(obj.asInstanceOf[SynchronizationAware].guid, obj)
}
}
/**
* Makes an Threadsave init of the elementsWithClass-map. Reason: If to threads are creating a the first element of the same
* model at the same time, one element would be overridden.
*/
private def initThreadSave(obj: Object, elementsWithClass: ConcurrentHashMap[String, AnyRef]): Unit = {
ElementLockProvider.synchronized {
logger.info("### save init ###")
if (elementsWithClass == null) {
elements.put(obj.getClass, new ConcurrentHashMap[String, AnyRef]())
}
}
}
/**
* Removes an element from the ModelElementsLists.
*/
def removeElement(obj: AnyRef): Unit = {
if (obj == null) {
return
}
var elementsWithClass: ConcurrentHashMap[String, AnyRef] = elements.get(obj.getClass)
elementsWithClass.remove(obj.asInstanceOf[SynchronizationAware].guid)
}
/**
* Informs the repository about what objects belong to which model
*
* @param name the model's name
* @param elemsType the class of the corresponding instances
* @throws IllegalArgumentException if the name is already in use
*/
def registerModel(name: String, elemsType: Class[_ <: AnyRef]): Unit = {
if (model2Class.contains(name)) {
throw new IllegalArgumentException(s"Model is already present: $name")
}
model2Class.put(name, elemsType)
}
/**
* Returns elements of which classname contains the parameter.
*
* @return the elements
*/
def getElementsFromType(s: String): Set[AnyRef] = {
var elementSet: Set[AnyRef] = Set()
elements.keySet().forEach { k =>
if (k.getName.contains(s)) {
elements.get(k).values().forEach { element =>
elementSet += element
}
}
}
return elementSet
}
/**
* Returns elements by their classname.
*
* @param s the classname
* @return the elements
*/
def getDirectElementsFromType(s: String): Set[SynchronizationAware] = {
var elementSet: Set[SynchronizationAware] = Set()
elements.keySet().forEach { k =>
if (k.getName == s) {
elements.get(k).values().forEach { element =>
elementSet += element.asInstanceOf[SynchronizationAware]
}
}
}
return elementSet
}
/**
* Resets ModelElementsLists by cleaning all maps.
*/
def reset() {
elements.keySet().forEach { modelKey =>
elements.get(modelKey).values().forEach { element =>
element.asInstanceOf[PlayerSync].deleteObjectFromSynchro()
}
}
dropAll()
}
def dropAll(): Unit ={
this.elements = new ConcurrentHashMap[Class[_ <: AnyRef], ConcurrentHashMap[String, AnyRef]]()
this.model2Class = new ConcurrentHashMap[String, Class[_ <: AnyRef]]()
}
/**
* Print out all elements to console.
*/
def printAll(): Unit = {
elements.keySet().forEach { modelKey =>
println("Model: " + modelKey)
elements.get(modelKey).values().forEach { element =>
println("** " + element)
}
}
}
/**
* Log out alle elements on info-level.
*/
def logAll(): Unit = {
elements.keySet().forEach { modelKey =>
logger.info("Model: " + modelKey)
elements.get(modelKey).values().forEach { element =>
logger.info("** " + element)
}
}
}
/**
* Log out alle elements on error-level.
*/
def logAllOnError(): Unit = {
elements.keySet().forEach { modelKey =>
logger.error("Model: " + modelKey)
elements.get(modelKey).values().forEach { element =>
logger.error("** " + element)
}
}
}
}
package org.rosi_project.model_management.core
import scroll.internal.MultiCompartment
import org.rosi_project.model_management.sync.lock._
import org.slf4j.Logger
import org.slf4j.LoggerFactory
/**
* Main interface for all elements. Integrates an element to RSYNC.
*/
trait PlayerSync extends MultiCompartment {
val logger = LoggerFactory.getLogger(classOf[PlayerSync])
buildClass()
var deleted: Boolean = false
var ts: Int = 0
var rv: Int = 0
def isDeleted: Boolean = deleted
/**
* Builds and integrates the implementing element to RSYNC.
*/
def buildClass(): Unit = {
ElementLockProvider.synchronized {
if (!SynchronizationCompartment.isUnderConstruction()) {
SynchronizationCompartment combine this
val mani = SynchronizationCompartment.createRoleManager()
this play mani
mani.manage(this)
}
}
}
/**
* Removes the implementing element from RSYNC.
*/
def deleteObjectFromSynchro(): Unit = {
ElementLockProvider.synchronized {
+this deleteManage this
deleted = true
}
}
/**
* Returns relating elements in other models.
*/
def getRelatedObjects(): Set[PlayerSync] = {
ElementLockProvider.synchronized {
var relatedElementsMetaObject = +this getRelatedElements ()
logger.error("rel:" + relatedElementsMetaObject);
try{
var relatedObjects: Set[PlayerSync] = relatedElementsMetaObject.right.get.head.right.get
return relatedObjects
} catch{
case e : NoSuchElementException => logger.error("this should not occur...")
return Set()
}
}
}
}
package org.rosi_project.model_management.core
package org.rosi_project.model_management.core
import scala.collection.Seq
import scala.collection.mutable.ListBuffer
import scala.collection.immutable.Set
import scala.util.control.Breaks._
import org.rosi_project.model_management.sync._
import org.rosi_project.model_management.sync.roles._
import org.rosi_project.model_management.sync.compartments._
import scala.sys.error
/**
* PART OF RSYNC-CORE by Christopher Werner (TUD)
*/
object SynchronizationCompartment extends ISynchronizationCompartment {
def createRoleManager(): IRoleManager = new RoleManager()
private var activeConstructionCompartment: IConstructionCompartment = null //object
private var activeDestructionCompartment: IDestructionCompartment = null //object
private var activeSyncCompartmentInstances = Set.empty[ISyncCompartment] //classes
private var activeExtensionCompartments = Set.empty[IExtenstionCompartment] //objects
private var availableExtensionCompartments: List[IExtenstionCompartment] = List[IExtenstionCompartment]()
private var availableConstructionCompartments: List[IConstructionCompartment] = List[IConstructionCompartment]()
private var availableDestructionCompartments: List[IDestructionCompartment] = List[IDestructionCompartment]()
private var availableSyncCompartments: List[ISyncCompartment] = List[ISyncCompartment]()
def reset(): Unit = {
activeConstructionCompartment = null
activeDestructionCompartment = null
activeSyncCompartmentInstances = Set.empty[ISyncCompartment]
activeExtensionCompartments = Set.empty[IExtenstionCompartment]
availableExtensionCompartments = List[IExtenstionCompartment]()
availableConstructionCompartments = List[IConstructionCompartment]()
availableDestructionCompartments = List[IDestructionCompartment]()
availableSyncCompartments = List[ISyncCompartment]()
allPlayers.foreach { p =>
removePlayer(p)
}
if(allPlayers.nonEmpty) error("Players not deleted")
}
changeConstructionRule(SuppressingConstructionCompartment)
changeDestructionRule(GeneralDestructor)
def getConstructionRule(): IConstructionCompartment = activeConstructionCompartment
def getDestructionRule(): IDestructionCompartment = activeDestructionCompartment
def getSyncRules(): Set[ISyncCompartment] = activeSyncCompartmentInstances
def getExtensions(): Set[IExtenstionCompartment] = activeExtensionCompartments
def getAvailableConstructionRule(): List[IConstructionCompartment] = availableConstructionCompartments
def getAvailableDestructionRule(): List[IDestructionCompartment] = availableDestructionCompartments
def getAvailableSyncRules(): List[ISyncCompartment] = availableSyncCompartments
def getAvailableExtensions(): List[IExtenstionCompartment] = availableExtensionCompartments
/**
* Method for Debug Output.
*/
private def debugCompleteRoleGraphOutput(): Unit = {
println("")
val nodes = this.allPlayers
nodes.foreach { n =>
println("Output N: " + n + " Player: " + n.player)
}
println("")
}
/**
* Method for Debug Output.
*/
private def debugSyncRoleGraphOutput(): Unit = {
println("")
val nodes = this.allPlayers
nodes.foreach {
case n: ISyncRole =>
val role: ISyncRole = n.asInstanceOf[ISyncRole]
val compart: ISyncCompartment = role.getOuterCompartment
println("Output N: " + n + " Player: " + n.player + " Comp: " + compart + " RN: " + compart.getRuleName)
case _ =>
}
println("")
}
/**
* Method for Debug Output.
*/
private def debugPlayerRolesOutput(): Unit = {
println("")
val nodes = this.allPlayers
nodes.foreach {
case player: PlayerSync =>
println("Output N: " + player.roles())
case _ =>
}
println("")
}
def registerConstructionCompartment(compartment: IConstructionCompartment): Unit = {
if (compartment == null)
return
if (!availableConstructionCompartments.contains(compartment)) {
availableConstructionCompartments = availableConstructionCompartments :+ compartment
this combine compartment
}
}
def registerDestructionCompartment(compartment: IDestructionCompartment): Unit = {
if (compartment == null)
return
if (!availableDestructionCompartments.contains(compartment)) {
availableDestructionCompartments = availableDestructionCompartments :+ compartment
this combine compartment
}
}
def registerSyncRule(compartment: ISyncCompartment): Unit = {
if (compartment == null)
return
if (!availableSyncCompartments.contains(compartment)) {
availableSyncCompartments = availableSyncCompartments :+ compartment
}
}
def registerExtensionCompartment(compartment: IExtenstionCompartment): Unit = {
if (compartment == null)
return
if (!availableExtensionCompartments.contains(compartment)) {
availableExtensionCompartments = availableExtensionCompartments :+ compartment
this combine compartment
}
}
def activateExtensionCompartment(compartment: IExtenstionCompartment): Unit = {
if (compartment == null)
return
activeExtensionCompartments += compartment
registerExtensionCompartment(compartment)
}
def deactivateExtensionCompartment(compartment: IExtenstionCompartment): Unit = {
if (compartment == null)
return
activeExtensionCompartments -= compartment
}
/**
* Change the actual construction role.
*/
def changeConstructionRule(construct: IConstructionCompartment): Unit = {
if (construct == null) {
return
}
activeConstructionCompartment = construct
registerConstructionCompartment(construct)
}
/**
* Change the destruction role.
* Set the new one and remove old roles and add new ones.
*/
def changeDestructionRule(destruct: IDestructionCompartment): Unit = {
if (destruct == null) {
return
}
if (activeDestructionCompartment == null) {
activeDestructionCompartment = destruct
registerDestructionCompartment(destruct)
return
}
//debugCompleteRoleGraphOutput()
var nodes = this.allPlayers; //get all nodes
//delete all destruction roles
nodes.foreach { n =>
if (n.isInstanceOf[IDestructor])
n.remove()
}
//debugCompleteRoleGraphOutput()
//add all new ones
nodes = this.allPlayers
nodes.foreach {
case n: IRoleManager =>
//add new role here
val player = n.player
if (player.isRight) {
val realPlayer = player.right.get
val newRole = destruct.getDestructorForClassName(realPlayer)
n play newRole
}
case _ =>
}
//debugCompleteRoleGraphOutput()
activeDestructionCompartment = destruct
registerDestructionCompartment(destruct)
}
/**
* Integration of a new Model with an integration compartment.
*/
def integrateNewModel(integrationRule: IIntegrationCompartment): Unit = {
this combine integrationRule
val nodes = this.allPlayers
nodes.foreach {
case player: PlayerSync =>
val role = integrationRule.getIntegratorForClassName(player)
if (role != null) {
player play role
underConstruction = true;
(+player).integrate(player)
underConstruction = false;
role.remove()
}
case _ =>
}
nodes.foreach {
case player: PlayerSync =>
val role = integrationRule.getRelationalIntegratorsForClassName(player)
if (role != null) {
player play role
underConstruction = true;
(+player).integrate(player)
underConstruction = false;
role.remove()
}
case _ =>
}
integrationRule.finalEditFunction()
}
/**
* Add a new synchronization rule to the synchronization process.
*/
def addSynchronizationRule(newRule: ISyncCompartment): Unit = {
if (newRule == null) {
return
}
//if the rule is in the list stop
activeSyncCompartmentInstances.foreach { s =>
if (s.getRuleName == newRule.getRuleName)
return
}
activeSyncCompartmentInstances += newRule
var running = true
var nodes = Seq[AnyRef]()
//debugSyncRoleGraphOutput()
while (running) {
breakable {
running = false
nodes = this.allPlayers; //get all nodes
nodes.foreach {
case n: RoleManager =>
//proof if the role manager does not play this rule
var proof = true
val player = n.player
if (player.isRight) {
val realPlayer = player.right.get
val relatedRoles = n.roles()
relatedRoles.foreach {
case syncRole: ISyncRole =>
val syncComp: ISyncCompartment = syncRole.getOuterCompartment
if (syncComp.getRuleName == newRule.getRuleName || !newRule.isFirstIntegration(realPlayer))
proof = false
case _ =>
}
//if synchronization compartment was not integrated before then integrate now
if (proof) {
//add new role to the player
//the new compartment
val newComp: ISyncCompartment = newRule.getNewInstance
val newRole = newComp.getNextIntegrationRole(realPlayer)
if (newRole != null)
n play newRole
else
proof = false
if (proof) {
//add roles to related role manager because on is added to this one
val related = n.getRelatedManager
related.foreach { r =>
val player = r.player
if (player.isRight) {
val realPlayer = player.right.get
if (newComp.isNextIntegration(realPlayer)) {
val newRole = newComp.getNextIntegrationRole(realPlayer)
r play newRole
}
}
}
this combine newComp
running = true
break
}
}
}
case _ =>
}
}
}
registerSyncRule(newRule)
//debugPlayerRolesOutput()
//debugSyncRoleGraphOutput()
}
def hasSynchronizationRule(ruleName: String): Boolean = {
activeSyncCompartmentInstances.map(_.getRuleName).contains(ruleName)
}
/**
* Delete all rules with this name.
*/
def deleteRule(ruleName: String): Unit = {
val nodes = this.allPlayers //get all nodes
nodes.foreach {
case n: ISyncRole =>
val role: ISyncRole = n.asInstanceOf[ISyncRole]
val compart: ISyncCompartment = role.getOuterCompartment
if (compart.getRuleName == ruleName) {
compart.clearSyncer()
n.remove()
}
case _ =>
}
// rule names should be unique (in theory)
// but we're better save than sorry
val ruleCompartments = activeSyncCompartmentInstances.filter(_.getRuleName == ruleName)
for (comp <- ruleCompartments) {
activeSyncCompartmentInstances -= comp
}
//debugCompleteRoleGraphOutput()
}
/**
* Change rule with this name to new rule.
*/
def changeRuleFromTo(from: String, to: ISyncCompartment): Unit = {
var running = true
var nodes = Seq[AnyRef]()
while (running) {
breakable {
running = false
nodes = this.allPlayers //get all nodes
nodes.foreach {
case role: ISyncRole =>
val compart: ISyncCompartment = role.getOuterCompartment
if (compart.getRuleName == from) {
//exchange this with a new compartment
val newComp: ISyncCompartment = to.getNewInstance
compart.getSyncer.foreach { r =>
val manager = (+r).getManager()
if (manager.isRight) {
val realManager: RoleManager = manager.right.get(0).right.get
val player = r.player
if (player.isRight) {
val realPlayer = player.right.get
val newRole = newComp.getNextIntegrationRole(realPlayer)
r.remove()
realManager play newRole
}
}
}
//role graph combination
this combine newComp
//delete compartment
compart.clearSyncer()
running = true
break
}
case _ =>
}
}
}
// rule names should be unique (in theory)
// but we're better save than sorry
val oldRuleCompartments = activeSyncCompartmentInstances.filter(_.getRuleName == from)
for (comp <- oldRuleCompartments) {
activeSyncCompartmentInstances -= comp
}
activeSyncCompartmentInstances += to
registerSyncRule(to)
//debugSyncRoleGraphOutput()
}
class RoleManager() extends IRoleManager {
def getRelatedClassFromName(name: String): PlayerSync = {
getRelatedManager.foreach(rm => {
val realPlayer = rm.player.right.get
if (realPlayer.getClass.getName.contains(name) || realPlayer.getClass.getSuperclass.getName.contains(name)) {
return realPlayer.asInstanceOf[PlayerSync]
}
})
null
}
def getSetRelatedClassesFromName(name: String): Set[PlayerSync] = {
var resultSet: Set[PlayerSync] = Set.empty
getRelatedManager.foreach(rm => {
val realPlayer = rm.player.right.get
if (realPlayer.getClass.getName.contains(name) || realPlayer.getClass.getSuperclass.getName.contains(name)) {
resultSet += realPlayer.asInstanceOf[PlayerSync]
}
})
resultSet
}
def insertNotification(): Unit = {
+this notifyInsertion ()
}
def deletionNotification(): Unit = {
+this notifyDeletion ()
}
def updateNotification(): Unit = {
+this notifyUpdate ()
}
def printAllManager(): Unit = {
println("++ Ma => Pl: " + this + " | " + this.player.right.get)
getRelatedManager().foreach(m => {
println("-- Ma => Pl: " + m + " | " + m.player.right.get)
})
}
def deleteManage(value: PlayerSync): Unit = {
val delete = activeDestructionCompartment.getDestructorForClassName(value)
if (delete != null) {
this play delete
+this deleteRoleFunction ()
}
}
def manage(value: PlayerSync): Unit = { // TODO
val construct = activeConstructionCompartment.getConstructorForClassName(value)
if (construct != null) {
this play construct
underConstruction = true;
val _ = +this construct (value, this)
underConstruction = false;
construct.remove()
}
}
/**
* Create a relation between two IRoleManager and RoleManager of other PlayerSync instances.
*/
def makePlayerSyncRelated(playerSync: PlayerSync): Unit = {
+playerSync makeRelated (this)
}
}
}
package org.rosi_project.model_management.sync
import scroll.internal.Compartment
import org.rosi_project.model_management.core._
import org.rosi_project.model_management.sync.helper.ConstructionContainer
import org.rosi_project.model_management.sync.roles.IConstructor
/**
* PART OF RSYNC-CORE by Christopher Werner (TUD)
* Interface for each construction rule.
*/
trait IConstructionCompartment extends Compartment {
/**
* Return a role instance that handles the construction process for the object.
*/
def getConstructorForClassName(classname: Object): IConstructor
def getRuleName: String
private def addExtensionRoles(containers: Set[ConstructionContainer]): Unit = {
containers.foreach { cc =>
if (cc.isConstructed) {
SynchronizationCompartment.getExtensions().foreach { e =>
var role = e.getExtensionForClassName(cc.getPlayerInstance())
if (role != null) {
cc.getManagerInstance() play role
}
}
}
}
}
private def notifyExtensionRoles(containers: Set[ConstructionContainer]): Unit = {
if (!SynchronizationCompartment.getExtensions().isEmpty) {
containers.foreach { cc =>
if (cc.isConstructed) {
var playerInstance = cc.getPlayerInstance()
+playerInstance insertNotification ()
}
}
}
}
/**
* Add the RoleManager roles from the synchronization compartment if necessary
*/
protected def addManagerRoles(containers: Set[ConstructionContainer]): Unit = {
containers.foreach { cc =>
if (cc.isConstructed && !cc.isStartElement) {
cc.getPlayerInstance play cc.getManagerInstance
}
}
}
/**
* Add the delete roles for the elements in the ConstructionContainers.
*/
protected def addDeleteRoles(containers: Set[ConstructionContainer]): Unit = {
containers.foreach { cc =>
if (cc.isConstructed) {
cc.getManagerInstance() play SynchronizationCompartment.getDestructionRule().getDestructorForClassName(cc.getPlayerInstance())
}
}
}
/**
* Add the related RoleManagers for the elements in the ConstructionContainers.
*/
protected def addRelatedRoleManager(containers: Set[ConstructionContainer]): Unit = {
containers.foreach { cc =>
containers.foreach { inner =>
cc.getManagerInstance.addRelatedManager(inner.getManagerInstance)
}
}
}
/**
* Combine the SynchronizationCompartment with all Players from the ConstructionContainers.
*/
protected def synchronizeCompartments(containers: Set[ConstructionContainer]): Unit = {
containers.foreach { cc =>
if (cc.isConstructed() && !cc.isStartElement()) {
SynchronizationCompartment combine cc.getPlayerInstance
}
}
}
/**
* Create the Synchronization mechanisms for the elements in the ConstructionContainers.
*/
protected def bindSynchronizationRules(containers: Set[ConstructionContainer]): Unit = {
SynchronizationCompartment.getSyncRules().foreach { s =>
var sync: ISyncCompartment = null
//Proof all container for integration
containers.foreach { cc =>
if (s.isNextIntegration(cc.getPlayerInstance)) {
if (cc.isConstructed && sync == null) {
sync = s.getNewInstance
}
if (sync != null) {
cc.getManagerInstance() play sync.getNextIntegrationRole(cc.getPlayerInstance())
}
}
}
if (sync != null)
SynchronizationCompartment combine sync
}
}
/**
* Fill the test lists with all Players from the ConstructionContainers.
*/
protected def fillTestLists(containers: Set[ConstructionContainer]): Unit = {
containers.foreach { cc =>
ModelElementLists.addElement(cc.getPlayerInstance)
}
}
protected def makeCompleteConstructionProcess(containers: Set[ConstructionContainer]): Unit = {
//first synchronize new compartments
this.synchronizeCompartments(containers)
//add role manager and relations
this.addManagerRoles(containers)
this.addRelatedRoleManager(containers)
//binding of roles
//this.addDeleteRoles(containers)
this.bindSynchronizationRules(containers)
this.addExtensionRoles(containers)
//notify extensions
this.notifyExtensionRoles(containers)
//fill test list
this.fillTestLists(containers)
/*println("Construction ++++++++++++++++++++++++++++++++++++++++++++------------------------++++++++++++++++++++++++++++++++++++++++++++++++++++")
containers.foreach { cc =>
println((cc.getPlayerInstance).roles())
}
println("Construction ++++++++++++++++++++++++++++++++++++++++++++------------------------++++++++++++++++++++++++++++++++++++++++++++++++++++")*/
}
}
package org.rosi_project.model_management.sync
import org.rosi_project.model_management.sync.roles.IDestructor
import scroll.internal.Compartment
/**
* PART OF RSYNC-CORE by Christopher Werner (TUD)
* Interface for each destruction rule.
*/
trait IDestructionCompartment extends Compartment {
/**
* Return a role instance that handles the destruction process for the object.
*/
def getDestructorForClassName(classname: Object) : IDestructor
def getRuleName: String
}
package org.rosi_project.model_management.sync
import org.rosi_project.model_management.sync.roles.IExtension
import scroll.internal.Compartment
/**
* PART OF RSYNC-CORE by Christopher Werner (TUD)
* Interface for each extension rule.
*/
trait IExtenstionCompartment extends Compartment {
/**
* Return a role instance that handles the extension process for the object.
*/
def getExtensionForClassName(classname: Object) : IExtension
/**
* Return a unique name that describes this extension.
*/
def getExtensionName() : String
}
\ No newline at end of file
package org.rosi_project.model_management.sync
import scroll.internal.Compartment
import org.rosi_project.model_management.sync.roles.ISyncRole
import org.rosi_project.model_management.sync.roles.IIntegrator
import org.rosi_project.model_management.sync.helper.IntegrationContainer
import org.rosi_project.model_management.core._
import org.rosi_project.model_management.sync.roles.IRoleManager
/**
* PART OF RSYNC-CORE by Christopher Werner (TUD)
* Interface for each integration rule.
*/
trait IIntegrationCompartment extends Compartment {
/**
* Return a role instance that handles the integration process for a new model to this instance.
*/
def getIntegratorForClassName(classname: Object): IIntegrator
/**
* Return a role instance that handles the integration process for a new relational compartment.
*/
def getRelationalIntegratorsForClassName(classname: Object): IIntegrator
def finalEditFunction(): Unit
protected def connectTargetElementWithSourceElementes(target: PlayerSync, sourceList: Set[PlayerSync]): Unit = {
var containers: Set[IntegrationContainer] = Set.empty
//Create Containers
sourceList.foreach(e => {
containers += new IntegrationContainer(target, e)
})
//Finish Creation
makeCompleteIntegrationProcess(containers)
}
protected def connectTargetElementWithSourceElemente(target: PlayerSync, source: PlayerSync): Unit = {
var containers: Set[IntegrationContainer] = Set.empty
//Create Container
containers += new IntegrationContainer(target, source)
//Finish Creation
makeCompleteIntegrationProcess(containers)
}
private def addExtensionRoles(containers: Set[IntegrationContainer]): Unit = {
containers.filter(_.newManagerConnection).foreach { cc =>
SynchronizationCompartment.getExtensions().foreach { e =>
var role = e.getExtensionForClassName(cc.getNewPlayerInstance())
if (role != null) {
cc.getNewManagerInstance() play role
}
}
}
}
private def notifyExtensionRoles(containers: Set[IntegrationContainer]): Unit = {
if (!SynchronizationCompartment.getExtensions().isEmpty) {
containers.filter(_.newManagerConnection).foreach { cc =>
var playerInstance = cc.getNewPlayerInstance()
+playerInstance insertNotification ()
}
}
}
/**
* Add Manager roles to all constructed elements.
*/
private def addManagerRoles(containers: Set[IntegrationContainer]): Unit = {
containers.filter(_.newManagerConnection).foreach { cc =>
cc.getNewPlayerInstance() play cc.getNewManagerInstance()
}
}
/**
* Add the delete roles for the elements in the IntegrationContainer.
*/
private def addDeleteRoles(containers: Set[IntegrationContainer]): Unit = {
containers.filter(_.newManagerConnection).foreach { cc =>
cc.getNewManagerInstance() play SynchronizationCompartment.getDestructionRule().getDestructorForClassName(cc.getNewPlayerInstance())
}
}
/**
* Add the related RoleManagers for the elements in the IntegrationContainer.
*/
private def addRelatedRoleManager(containers: Set[IntegrationContainer]): Unit = {
containers.foreach { cc =>
val oldPlayer = cc.getOldPlayerInstance()
if (cc.simpleRelatedManagerConnection) {
val manager: IRoleManager = +oldPlayer getManager ()
if (manager != null) {
manager.makeRelated(cc.getNewManagerInstance())
}
} else {
val allManager: Set[IRoleManager] = +oldPlayer getAllManager ()
if (allManager != null) {
allManager.foreach { r =>
r.makeRelated(cc.getNewManagerInstance())
}
}
}
}
}
/**
* Combine the SynchronizationCompartment with all Players from the IntegrationContainer.
*/
private def synchronizeCompartments(containers: Set[IntegrationContainer]): Unit = {
containers.filter(_.newManagerConnection).foreach { cc =>
SynchronizationCompartment combine cc.getNewPlayerInstance()
}
}
/**
* Create the Synchronization mechanisms for the elements in the IntegrationContainer.
*/
private def bindSynchronizationRules(containers: Set[IntegrationContainer]): Unit = {
containers.filter(_.newManagerConnection).foreach { cc =>
val oldPlayer = cc.getOldPlayerInstance()
val allManager: Set[IRoleManager] = +oldPlayer getAllManager ()
if (allManager != null) {
allManager.foreach { rm =>
val roles = rm.roles()
//println("Player: " + rm.player + "Roles: " + roles)
roles.foreach { r =>
if (r.isInstanceOf[ISyncRole]) {
val syncRole: ISyncRole = r.asInstanceOf[ISyncRole]
val syncComp: ISyncCompartment = syncRole.getOuterCompartment
//println("+~~~Sync: " + syncRole + " " + syncComp)
if (!syncComp.containsSyncer(cc.getNewPlayerInstance()) && syncComp.isFirstIntegration(r.player.right.get)) {
val newRole = syncComp.getNextIntegrationRole(cc.getNewPlayerInstance())
//println("+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~New Role: " + newRole)
if (newRole != null) {
cc.getNewManagerInstance() play newRole
allManager.foreach { internalSync =>
val playerSync = internalSync.player.right.get
if (syncComp.isNextIntegration(playerSync)) {
if (!syncComp.containsSyncer(playerSync)) {
internalSync play syncComp.getNextIntegrationRole(playerSync)
}
}
}
}
}
}
}
}
}
}
}
/**
* Fill the test lists with all Players from the IntegrationContainer.
*/
private def fillTestLists(containers: Set[IntegrationContainer]): Unit = {
containers.filter(_.newManagerConnection).foreach { cc =>
ModelElementLists.addElement(cc.getNewPlayerInstance())
}
}
/**
* Do the integration process automatically.
*/
protected def makeCompleteIntegrationProcess(containers: Set[IntegrationContainer]): Unit = {
containers.foreach(cc => {
if (cc.getNewManagerInstance() == null) {
val newPlayer = cc.getNewPlayerInstance()
val manager = +newPlayer getManager ()
if (manager.isRight && manager.right.get != null) {
cc.newManagerConnection = false
cc.newManagerInstance = manager.right.get
} else {
cc.newManagerConnection = true
cc.newManagerInstance = SynchronizationCompartment.createRoleManager()
}
}
})
//add new role managers to the new players
this.addManagerRoles(containers)
//this.addDeleteRoles(containers)
this.addRelatedRoleManager(containers)
//combines the new compartments with the existing ones
this.synchronizeCompartments(containers)
this.bindSynchronizationRules(containers)
//add extension roles and notify them because of creation
this.addExtensionRoles(containers)
this.notifyExtensionRoles(containers)
//add the new model element to the elements list
this.fillTestLists(containers)
/*println("Integrate +++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------+++++++++++++++++++++++++++++++++++++++++++++++++++")
containers.foreach { cc =>
println((cc.getNewPlayerInstance()).roles())
println((cc.getOldPlayerInstance()).roles())
}
println("Integrate ++++++++++++++++++++++++++++++++++++++++++++------------------------++++++++++++++++++++++++++++++++++++++++++++++++++++")*/
}
}
package org.rosi_project.model_management.sync
import org.rosi_project.model_management.core.PlayerSync
import org.rosi_project.model_management.sync.roles.ISyncRole
import scroll.internal.Compartment
import scala.collection.immutable.Set
/**
* PART OF RSYNC-CORE by Christopher Werner (TUD)
* Interface for each synchronization rule.
*/
trait ISyncCompartment extends Compartment {
/**
* Variable to proof if he is actual in a sync process.
*/
protected var doSync = false
/**
* All sync roles of this synchronization rule.
*/
private var syncer: Set[ISyncRole] = Set.empty
/**
* Get roles for all integration classes.
*/
protected def getNextRole(classname: Object) : ISyncRole = {
getFirstRole(classname)
}
/**
* Get roles for integration classes. Should give less roles than getNextRole.
*/
protected def getFirstRole(classname: Object) : ISyncRole
def containsSyncer(value: Object): Boolean = {
syncer.foreach { s =>
if (+s == +value) {
//if (s.player.equals(value.player)) {
return true;
}
}
return false
}
def addSyncer(sync: ISyncRole): Unit = {
syncer += sync
}
/**
* Get the list of all sync roles.
*/
def getSyncer(): Set[ISyncRole] = syncer
/**
* Clear the list of all sync roles.
*/
def clearSyncer(): Unit = {
syncer = Set.empty
}
/**
* Method for retrieving the related elements of an element "outside" of the "role-world".
*/
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]
}
}
return relatedObjects
}
/**
* Get roles for integration classes. Should give less roles than getNextRole.
*/
def getFirstIntegrationRole(classname: Object) : ISyncRole = {
val role: ISyncRole = this.getFirstRole(classname)
if (role != null)
this.addSyncer(role)
role
}
/**
* Get all roles for integration classes.
*/
def getNextIntegrationRole(classname: Object) : ISyncRole = {
val role: ISyncRole = this.getNextRole(classname)
if (role != null)
this.addSyncer(role)
role
}
/**
* Get roles for all integration classes.
*/
def isFirstIntegration(classname: Object): Boolean
/**
* Get boolean if next integration
*/
def isNextIntegration(classname: Object): Boolean = {
isFirstIntegration(classname)
}
/**
* Create a new instance of this class.
*/
def getNewInstance: ISyncCompartment
/**
* Get the name of this rule.
*/
def getRuleName: String
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment