|
|
|
Synchronization Language
|
|
|
|
===
|
|
|
|
|
|
|
|
# GENERAL INFORMATION
|
|
|
|
- Jede Regel wird zu einer oder mehrerer Rollen in einer oder mehreren Compartments und bekommt noch einen Präfix Delete* Create* Synchronize*
|
|
|
|
- Damit haben alle Regeln auf jeden Fall schonmal einen einmaligen namen
|
|
|
|
- Andere Regeln wie Helper Regeln bekommen einen anderen Präfix und können als eigenes Compartment mit eigenen Rollen betrachtet werden
|
|
|
|
- Beim Erstellungsregeln werden über das Synchronisationscompartment Verlinkung zwischen den Teilprojekten erzeugt, d.h. sobald es eine Regel gibt die Gleichheit zwischen Objekten spezifiziert oder das erstellen Managed, werden automatischen die Verlinkungen auf Instanzebene mit erstellt. Diese müssen dannach nicht nochmal neu in Regeln spezifiziert werden
|
|
|
|
- Sobald sich die Synchronisationsregeln oder anderen Regeln ändern können diese zur Laufzeit ausgetauscht werden
|
|
|
|
- Falls die Namen identisch bleiben müssen nur die Regeln neu geladen werden und ersetzen sich gegenseitig
|
|
|
|
- Synchronization wird dann wieder auf den Punkt hergestellt und neue Modelle falls sie dazugekommen sind gleich mit integriert
|
|
|
|
- Möchte ich den Fall abbilden können, dass ich ein Element in einem Modelverbund löschen aber nicht die Verknüpften Elemente mitlösche (Nein: da dies zu unkontrollierten Problemen führt => maximal woanders als gelöscht markieren)
|
|
|
|
- darauf ergibt sich die Frage ob ich feingranulare Regeln überhaupt haben möchte oder ob mich eigentlich nur der Ansatz mit einer Regel die alles abbildet interessiert
|
|
|
|
|
|
|
|
# Running Example for this Webpage
|
|
|
|
- 3 Modelle Families, Persons und SimplePersons
|
|
|
|
- Konzept einer Person ist in jedem Modell verhanden
|
|
|
|
- Änderungen von einem Model müssen an die anderen propagiert werden
|
|
|
|
|
|
|
|
### Families (Model A)
|
|
|
|
```
|
|
|
|
class Family {
|
|
|
|
lastName: String
|
|
|
|
father: Member
|
|
|
|
mother: Member
|
|
|
|
sons: List[Member]
|
|
|
|
daughters: List[Member]
|
|
|
|
}
|
|
|
|
class Member {
|
|
|
|
firstName: String
|
|
|
|
address: String
|
|
|
|
birthday: Date
|
|
|
|
familyFather: Member
|
|
|
|
familyMother: Member
|
|
|
|
familySon: Member
|
|
|
|
familyDaughter: Member
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### Persons (Model B)
|
|
|
|
```
|
|
|
|
class Person {
|
|
|
|
fullName: String
|
|
|
|
birthday: Date
|
|
|
|
}
|
|
|
|
class Male extends Person {}
|
|
|
|
class Female extends Person {}
|
|
|
|
```
|
|
|
|
|
|
|
|
### SimplePersons (Model C)
|
|
|
|
```
|
|
|
|
class SimplePerson {
|
|
|
|
completeName: String
|
|
|
|
address: String
|
|
|
|
male: Boolean
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
#### PhoneBook (Model D)
|
|
|
|
```
|
|
|
|
class PhoneBookEntry {
|
|
|
|
firstName: String
|
|
|
|
lstName: String
|
|
|
|
address: String
|
|
|
|
telefonNumber: String
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
# IDEAS WITH THOMAS
|
|
|
|
- Regeln sollten umkehrbar sein um gut abzubilden ist jedoch schon in diesem Beispiel nicht machbar
|
|
|
|
- Families!Member.firstName + ' ' + Families!Family.lastName = Persons!Person.fullName
|
|
|
|
- e.g., fullName: "Phing Phang Phung" => firstName: "Phing Phang" + lastName: "Phung" or firstName: "Phing" + lastName: "Phang Phung" ???
|
|
|
|
|
|
|
|
## Object invariant
|
|
|
|
```
|
|
|
|
Objinv (Person, SimplePerson, Family o Member)
|
|
|
|
with (Member.firstName + " " + Family.lastName, Person.fullName, SimplePerson.completeName)
|
|
|
|
```
|
|
|
|
|
|
|
|
- Problem ist die Unterscheidung von männlich und weiblich, die kann ich hier nicht Abbilden, was natürlich die Problematik mit jeglicher Vererbung wieder mit sich bringt
|
|
|
|
|
|
|
|
## Attribute invariant
|
|
|
|
```
|
|
|
|
Attinv (Person, SimplePerson, Family o Member)
|
|
|
|
with (Member.firstName + " " + Family.lastName, Person.fullName, SimplePerson.completeName)
|
|
|
|
```
|
|
|
|
|
|
|
|
- Als Synchronisationsregel möglich jedoch zum Erzeugen nicht ausreichend
|
|
|
|
- Idee am Ende nur eine Regel Art aus der Synchronisations-, Lösch- und Erstellungsregeln erzeugt werden
|
|
|
|
|
|
|
|
# COMPLETE RULES
|
|
|
|
- Regeln, welche für Synchronization, Löschen und Erstellen verwendet werden können
|
|
|
|
- Vorteil:
|
|
|
|
- Kurze Regelschreibweise
|
|
|
|
- Sobald Elemente in der Regel vergessen werden fällt dies schneller auf
|
|
|
|
- Nachteil:
|
|
|
|
- keine feingranuale Spezifikation der Regeln
|
|
|
|
- Elementtypen werden für Löschen, Erstellen und Synchronisieren immer zusammenbetrachtet
|
|
|
|
|
|
|
|
### Complete Rule
|
|
|
|
- Code Generator muss Erstell-, Lösch- und Synchronisationsregeln aus einer so einer Regel generieren
|
|
|
|
- Erzeugung von Objekten kann anhand von Sync Regeln abgeleitet werden
|
|
|
|
- Trennung in primary Regeln und non-primary Regeln
|
|
|
|
- primary Regeln bestimmen Objekte zwischen Modellen eindeutig
|
|
|
|
- **Alte Idee:** Erzeugung von Objekten kann anhand der primary Regeln abgeleitet werden (Verkettung der primary Regeln für eindeutige Objekt erkennung zwischen Modellelementen verschiedener Modelle)
|
|
|
|
- Probleme
|
|
|
|
- Short Hand notationen für spezial Fälle die immer verwendet werden? **Brauchen wir das wirklich?**
|
|
|
|
- Grenzen von change Operatoren definieren **in folgenden Beispielen schon mit betrachtet**
|
|
|
|
|
|
|
|
#### Rule A
|
|
|
|
```
|
|
|
|
"primary" syncRule NamesOfFamilyAndMemberAndPersonAndSimplePerson {
|
|
|
|
sync
|
|
|
|
a : Families!Member
|
|
|
|
b : Persons!Person
|
|
|
|
c : SimplePersons!SimplePerson
|
|
|
|
d : Families!Family (a.family==d)
|
|
|
|
with
|
|
|
|
//1. normaler Falls
|
|
|
|
a.firstName + ' ' + d.lastName == b.fullName == c.completeName
|
|
|
|
//2.1 falls completeName = d.lastName + ',' + a.firstName wäre
|
|
|
|
a.firstName + ' ' + d.lastName == b.fullName
|
|
|
|
d.lastName + ',' + a.firstName == c.completeName
|
|
|
|
//2.2 oder mittels hilfsfunktionen für first & lastName (Ende Dokument)
|
|
|
|
a.firstName + ' ' + d.lastName == b.firstName + ' ' + b.lastName == c.lastName + ',' + c.firstName
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
#### Rule B
|
|
|
|
```
|
|
|
|
"primary" syncRule AddressesOfMemberAndSimplePerson {
|
|
|
|
sync
|
|
|
|
a : Families!Member
|
|
|
|
c : SimplePersons!SimplePerson
|
|
|
|
with
|
|
|
|
a.address == c.address
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
#### Rule C
|
|
|
|
```
|
|
|
|
"primary" syncRule BirthdaysOfMemberAndPerson {
|
|
|
|
sync
|
|
|
|
a : Families!Member
|
|
|
|
b : Persons!Person
|
|
|
|
with
|
|
|
|
a.birthday == b.birthday
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
#### Fälle Primary Rules
|
|
|
|
- Wenn ich einen Modellverbund habe, wo alle Elemente auf die Regeln zutreffen in der Synchronisation enthalten sind, dann muss ich beim Insert nicht nach schon vorhandenen Elementen suchen, das würde nur bedeuten, dass das Element in dem Model wo es erstellt wurde schon existiert
|
|
|
|
- Deswegen macht die unterscheidung in primary und non-primary Regeln keine Sinn
|
|
|
|
- Außer man nutzt Primary Regeln für die integration von neuen Modellen
|
|
|
|
- **ALT Anfang**
|
|
|
|
- Fall (i): A (non-primary), B (non-primary), C (non-primary)
|
|
|
|
- Keine Erzeugung von Objekten in anderen Modellen, möglich da keine Primary Regeln
|
|
|
|
- Fall (ii): A (primary), B (non-primary), C (non-primary)
|
|
|
|
- firstName + ' ' + lastName == fullName == completeName (bestimmen die Abhängigkeiten zwischen den Modellen eindeutig)
|
|
|
|
- Namen als eindeutige Identifikation zwischen den Modellen angesehen
|
|
|
|
- Fall (iii): A (primary), B (primary), C (primary)
|
|
|
|
- firstName + ' ' + lastName == fullName == completeName && (address || birthday) (bestimmen die Abhängigkeiten zwischen den Modellen eindeutig)
|
|
|
|
- Namen in Kombination mit Geburtstag oder Adresse bestimmen die eindeutigen Referenzen zwischen den Modellen
|
|
|
|
- **ALT Ende**
|
|
|
|
|
|
|
|
#### Anmerkungen
|
|
|
|
- `[a.firstName,d.lastName].join(' ')` wäre umkehrbar zu, a.firstName, d.lastName = syncValue.splitFirst(' ')
|
|
|
|
- typisches muster von `a.p + 'sep' + a.q` ist schwer zu überführen
|
|
|
|
- Möglich `a.p+'sep'+a.q <a.changePandQ(syncValue)>`
|
|
|
|
- Oder im Allgemeinen nicht einfach übersetzen, wie z.B.: `a.p1+':'+a.p2+'.'+a.p3*a.p4`
|
|
|
|
|
|
|
|
### Integrate the FeMaleSync
|
|
|
|
- Female/Male Änderungen in den Modellen:
|
|
|
|
- im Model Families Verweis umsetzen wenn es von männlich zu weiblich wird
|
|
|
|
- im Model SimplePersons nur Attribute male neu setzen
|
|
|
|
- im Model Persons dann eine delete und Insert methode und dann nur case schreiben
|
|
|
|
- Problem:
|
|
|
|
- Was mache ich beim Löschen mit Werten die vorher nie angefasst wurden?
|
|
|
|
- Beispiel: Ändern einer Person im Persons Model von Male zu Female
|
|
|
|
- Benötigen einer Kopie die den Zustand nach dem Löschen und neu erstellen wieder herstellt
|
|
|
|
- Zwischen Werte irgendwie Abspeichern, jedoch sind einige Werte von der Person in keiner Regel definieren
|
|
|
|
- Lösung: Person zwischen speichern und dann, neue Person mit alten Daten befüllen
|
|
|
|
|
|
|
|
```
|
|
|
|
syncRule FeMaleSync {
|
|
|
|
sync
|
|
|
|
a : Families!Member
|
|
|
|
b : Persons!Person
|
|
|
|
c : SimplePersons!SimplePerson
|
|
|
|
d : Families!Family (a.family==d)
|
|
|
|
with
|
|
|
|
//Idee 1: instance of
|
|
|
|
a.isFemale() == not c.male == b.isInstanceOf[Persons!Female]
|
|
|
|
//Idee 2: case statement [syncValue as universal useable variable]
|
|
|
|
a.isFemale() == not c.male == case(b, {syncValue==true: Persons!Female, syncValue==false: Persons!Male})
|
|
|
|
//Idee 3: everything case statement
|
|
|
|
case(a, {syncValue==a.isFemale()}) == case(c, {syncValue==not c.male}) == case(b, {syncValue==true: Persons!Female, syncValue==false: Persons!Male})
|
|
|
|
do
|
|
|
|
a.switchGender(syncValue) //helper Function
|
|
|
|
b.switchMaleFemale(syncValue) //helper Function
|
|
|
|
c.male <- syncValue or c.switchMale(syncValue) //helper Function
|
|
|
|
}
|
|
|
|
|
|
|
|
Other Ideas OLD:
|
|
|
|
a.isFemale<a.switchGender(syncValue)>
|
|
|
|
not c.male<syncValue>
|
|
|
|
b.isInstanceOf[Female]<b.switchMaleFemale(syncValue)> or
|
|
|
|
case(b, {syncValue==true: Persons!Female, syncValue==false: Persons!Male})<b.switchMaleFemale(syncValue)>
|
|
|
|
|
|
|
|
a.f(x) <a.g(y,x)> == y
|
|
|
|
|
|
|
|
c.male <- not a.isFemale() == b instanceOf Female
|
|
|
|
t1 : Persons!Female <- a.isFemale() == not c.male
|
|
|
|
t2 : Persons!Male <- not a.isFemale() == c.male
|
|
|
|
a.changeIsFemale(<- c.male == b instanceOf Male)
|
|
|
|
```
|
|
|
|
|
|
|
|
- Anmerkungen:
|
|
|
|
- `instanceof` ist zwar Boolean aber not (instance of Female) ist nicht sinnvoll.
|
|
|
|
- Beispiel Operator: `case(b, {true: Persons!Female, false: Persons!Male})`
|
|
|
|
- General Operator: `case(o, {v_1:Model!Element1, ... v_n:Model!ElementN})` where Model is an arbitrary model and `Element1` till `ElementN` elements in this model. Moreover, $v_1$ till $v_n$ are arbitrary primitive (later object) values.
|
|
|
|
- Noch generellere wäre $v_1$ könnte $c.age>4 \land c.age<10$ sein, damit könnte ich Phasen oder Altersgruppen in Modell Instanzen synchronisieren
|
|
|
|
|
|
|
|
### Hilfs Funktion (Families) Mother<-> Father & Daughter <-> Son
|
|
|
|
- Anders wäre die Transformation von Persons und SimplePersons zu Families nicht möglich
|
|
|
|
- Funktion setzt Mütter zu Väter, Tochter zu Sohn und umgekehrt
|
|
|
|
- Methode müsste aufgerufen werden falls so eine Änderung in Persons oder SimplePersons auftritt
|
|
|
|
- Problem:
|
|
|
|
- da diese Änderungen auch in die Family Klasse übernommen werden müssen kann es sein das dort eine Vater Relation überschrieben wird oder eine Mutter Relation überschrieben wird, da es sich um opposite Relationen handeln kann
|
|
|
|
- Dies würde zu einer nicht mehr handhabbaren Veränderung führen
|
|
|
|
|
|
|
|
```
|
|
|
|
helper context Families!Member def : switchGender (female : Boolean) : Unit =
|
|
|
|
if female then //female case (set to female)
|
|
|
|
if self.familyFather.oclIsUndefined () then
|
|
|
|
if not self.familySon.oclIsUndefined () then
|
|
|
|
self.familyDaughter <- self.familySon
|
|
|
|
endif
|
|
|
|
else
|
|
|
|
self.familyMother <- self.familyFather
|
|
|
|
endif
|
|
|
|
else //not female case
|
|
|
|
if self.familyMother.oclIsUndefined () then
|
|
|
|
if not self.familyDughter.oclIsUndefined () then
|
|
|
|
self.familySon <- self.familyDughter
|
|
|
|
endif
|
|
|
|
else
|
|
|
|
self.familyFather <- self.familyMother
|
|
|
|
endif
|
|
|
|
endif;
|
|
|
|
```
|
|
|
|
|
|
|
|
### Hilfs Funktion (Persons) Male <-> Female
|
|
|
|
- Müsste wie ein Delete und Insert interagieren `self.type <- Person!Female`
|
|
|
|
- Befehl vielleicht noch ändern nur wie? TODO
|
|
|
|
|
|
|
|
```
|
|
|
|
helper context Persons!Person def : switchMaleFemale (female : Boolean) : Unit =
|
|
|
|
if female then //female case (set to female)
|
|
|
|
if self.isInstanceOf[Persons!Male] then
|
|
|
|
self.type <- Person!Female
|
|
|
|
endif
|
|
|
|
else //not female case (set to male)
|
|
|
|
if self.isInstanceOf[Persons!Female] then
|
|
|
|
self.type <- Person!Male
|
|
|
|
endif
|
|
|
|
endif;
|
|
|
|
```
|
|
|
|
|
|
|
|
### Hilfs Funktion (SimplePersons) male attribute
|
|
|
|
- Braucht nicht extra eine Hilfsfunktion muss nur Attribute umsetzen
|
|
|
|
- Befehl vielleicht noch ändern nur wie? TODO
|
|
|
|
|
|
|
|
```
|
|
|
|
helper context SimplePersons!Person def : switchMale (female : Boolean) : Unit =
|
|
|
|
if female <> self.male then //change if different
|
|
|
|
self.male <- female
|
|
|
|
endif;
|
|
|
|
```
|
|
|
|
|
|
|
|
### Integration of PhoneBook Model: extension of syncrules
|
|
|
|
|
|
|
|
#### New Rules
|
|
|
|
```
|
|
|
|
primary syncRule NamesWithPhoneBookEntry extends NamesOfFamilyAndMemberAndPersonAndSimplePerson{
|
|
|
|
sync
|
|
|
|
e: PhoneBook!PhoneBookEntry
|
|
|
|
with
|
|
|
|
e.first + ' ' + e.last == b.fullName
|
|
|
|
}
|
|
|
|
```
|
|
|
|
```
|
|
|
|
syncRule AddressWithPhoneBookEntry extends AddressesOfMemberAndSimplePerson{
|
|
|
|
sync
|
|
|
|
e: PhoneBook!PhoneBookEntry
|
|
|
|
with
|
|
|
|
e.address == c.address
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
- primary Operator, um zu sehen welche Regeln nötig sind um ein Model in die existierende Synchronisation einzubeziehen
|
|
|
|
- hier wäre nur Model B notwendig, da es das einzige interagierende in der `primary` Regel ist
|
|
|
|
- Erweiterungsregel könnte als neues Compartment einfach mit eingeladen werden
|
|
|
|
- Möglich Regel zu neuer großer Regel zu kombinieren und dann mit einmal neu einzuladen (jedoch dann nicht mehr ganz klar, welches Model neu ist, und wie dies gleich in die existierende Synchronisation integriert wird)
|
|
|
|
|
|
|
|
### Delete Phone Book Model from Synchronization
|
|
|
|
- `delete PhoneBook` könnte genutzt werden um ein Model komplett aus der Synchronisation zu löschen
|
|
|
|
- Regeln würden weiter exisiteren jedoch würde er intern alles davon betroffene ignorieren
|
|
|
|
|
|
|
|
# SPLIT INTO 3 RULE TYPES
|
|
|
|
- Synchronizations-, Lösch und Erstellungsregeln einzeln definieren und dann in dazugehörigen Compartments umsetzen
|
|
|
|
- Vorteil:
|
|
|
|
- Feingranulare Spezifikation der Regeln in der Synchronisationssprache
|
|
|
|
- Element typen können speziell aus dem Löschprozess rausgehalten werden
|
|
|
|
- Nachteil:
|
|
|
|
- Mehr schreib Aufwand für Regel Spezifikation
|
|
|
|
- Sobald Regeln vergessen werden können diese nicht umgesetzt werden
|
|
|
|
|
|
|
|
## Synchronization Rules
|
|
|
|
- 3 Ideen wie Synchronisationsregeln aussehen könnten die 3. ist dabei die vermutlich Eleganteste
|
|
|
|
- die 2. ist nur abgewandelt zur 1. und eigentlich sinnlos
|
|
|
|
|
|
|
|
### Idee 1
|
|
|
|
- Jede Regel sagt genau welche anderen Objekte sie verändert und sorgt dafür das nicht das gleich Model nochmal angefasst wird
|
|
|
|
- 1 zu n
|
|
|
|
|
|
|
|
```
|
|
|
|
syncRule syncFirstNameFromMember {
|
|
|
|
from
|
|
|
|
a : Families!Member (firstName) //variablen Änderung auf die diese Regel reagieren soll
|
|
|
|
in
|
|
|
|
b : Persons!Person (
|
|
|
|
b.fullName <- a.firstName + ' ' + b.lastName //idee in part darf nur von from part beeinflusst werden und nicht von anderem in part
|
|
|
|
),
|
|
|
|
c : SimplePersons!SimplePerson (
|
|
|
|
c.completeName <- a.firstName + ' ' + c.lastName //darf nicht von b beeinflusst werden
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
syncRule syncLastNameFromFamily {
|
|
|
|
from
|
|
|
|
a : Families!Family (lastName) //variablen Änderung auf die diese Regel reagieren soll
|
|
|
|
in
|
|
|
|
b : Persons!Person (
|
|
|
|
b.fullName <- b.firstName + ' ' + a.lastName
|
|
|
|
),
|
|
|
|
c : SimplePersons!SimplePerson (
|
|
|
|
c.completeName <- c.firstName + ' ' + a.lastName
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
syncRule syncFullNameFromPerson {
|
|
|
|
from
|
|
|
|
b : Persons!Person (fullName)
|
|
|
|
in
|
|
|
|
a : Families!Member (
|
|
|
|
a.firstName <- b.firstName
|
|
|
|
),
|
|
|
|
d : Families!Family (
|
|
|
|
d.lastName <- b.lastName
|
|
|
|
),
|
|
|
|
c : SimplePersons!SimplePerson (
|
|
|
|
c.completeName <- b.fullName
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
syncRule syncCompleteNameFromSimplePerson {
|
|
|
|
from
|
|
|
|
c : SimplePersons!SimplePerson (completeName)
|
|
|
|
in
|
|
|
|
a : Families!Member (
|
|
|
|
a.firstName <- c.firstName
|
|
|
|
),
|
|
|
|
d : Families!Family (
|
|
|
|
d.lastName <- c.lastName
|
|
|
|
),
|
|
|
|
b : Persons!Person (
|
|
|
|
b.fullName <- c.completeName
|
|
|
|
)
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### Idee 2
|
|
|
|
- Nachteil Änderungen werden auch im eigenen Model nochmal durchgeführt, da die Funktion syncNames nicht unterscheidet von welchem Element sie aufgerufen wird
|
|
|
|
- diese Regeln Rufen immer nur die Synchonisationsfunktion auf und bestimmen selbst nur welches Änderung als Event fungiert
|
|
|
|
- 1 zu n mit event trigger
|
|
|
|
|
|
|
|
```
|
|
|
|
syncRule syncCompleteNameFromSimplePerson {
|
|
|
|
from
|
|
|
|
c : SimplePersons!SimplePerson (completeName)
|
|
|
|
do
|
|
|
|
syncNameFunction (c.firstName : String, c.lastName : String) // wieder mit Nutzung der Hilfsfunktionen
|
|
|
|
}
|
|
|
|
|
|
|
|
syncRule syncFirstNameFromMember {
|
|
|
|
from
|
|
|
|
a : Families!Member (firstName) //variablen Änderung auf die diese Regel reagieren soll
|
|
|
|
do
|
|
|
|
syncNameFunction (a.firstName : String, a.lastName : String) // wieder mit Nutzung der Hilfsfunktionen
|
|
|
|
}
|
|
|
|
|
|
|
|
syncRule syncLastNameFromFamily {
|
|
|
|
from
|
|
|
|
a : Families!Family (lastName) //variablen Änderung auf die diese Regel reagieren soll
|
|
|
|
do
|
|
|
|
syncNameFunction (a.firstName : String, a.lastName : String) // wieder mit Nutzung der Hilfsfunktionen
|
|
|
|
}
|
|
|
|
|
|
|
|
syncRule syncFullNameFromPerson {
|
|
|
|
from
|
|
|
|
b : Persons!Person (fullName)
|
|
|
|
do
|
|
|
|
syncNameFunction (b.firstName : String, b.lastName : String) // wieder mit Nutzung der Hilfsfunktionen
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
- diese Regel kümmert sich um die Durchführung der Synchronisation und wird nur von denen davor aufgerufen wenn eine Änderung wo eintritt
|
|
|
|
|
|
|
|
```
|
|
|
|
syncRule syncNameFunction ( firstName : String, lastName : String ) {
|
|
|
|
in
|
|
|
|
a : Families!Member (
|
|
|
|
a.firstName <- firstName
|
|
|
|
),
|
|
|
|
d : Families!Family (
|
|
|
|
d.lastName <- lastName
|
|
|
|
),
|
|
|
|
b : Persons!Person (
|
|
|
|
b.fullName <- firstName + ' ' + lastName
|
|
|
|
),
|
|
|
|
c : SimplePersons!SimplePerson (
|
|
|
|
c.completeName <- firstName + ' ' + lastName
|
|
|
|
)
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### Idee 3
|
|
|
|
- Kürzeste aller Regeln und beschreibt die Synchronisation des Namens aller Objekte perfekt
|
|
|
|
- Mit dem richtigen Code Generator wird auch kein unötiger Aufruf in dem Model durchgeführt welches die Synchronisation auslöst
|
|
|
|
- Synchronisationsregeln anderer Attribute müssen extra definiert werden
|
|
|
|
|
|
|
|
```
|
|
|
|
syncRule NamesOfFamilyAndMemberAndPersonAndSimplePerson {
|
|
|
|
sync
|
|
|
|
a : Families!Member
|
|
|
|
b : Persons!Person
|
|
|
|
c : SimplePersons!SimplePerson
|
|
|
|
d : Families!Family (a.family==d)
|
|
|
|
with
|
|
|
|
a.firstName + ' ' + d.lastName == b.fullName == c.completeName
|
|
|
|
//falls completeName = d.lastName + ',' + a.firstName wäre es möglich die Regel so zu schreiben
|
|
|
|
a.firstName + ' ' + d.lastName == b.fullName
|
|
|
|
d.lastName + ',' + a.firstName == c.completeName
|
|
|
|
//oder mittels hilfsfunktionen in b und c könnte man auch sowas schreiben
|
|
|
|
a.firstName + ' ' + d.lastName == b.firstName + ' ' + b.lastName == c.lastName + ',' + c.firstName
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
## Create Rules
|
|
|
|
- 2 Ideen wie man Erstellungsregeln aufbauen kann, zum einen wie in ATL oder so hier
|
|
|
|
- In beiden Arten muss man unterscheiden in männlich und weiblich da dies die meisten Probleme verursacht
|
|
|
|
|
|
|
|
### Meine Idee für andere Art von Erstellungsregeln
|
|
|
|
```
|
|
|
|
createRule MemberAndPersonAndSimplePerson {
|
|
|
|
of
|
|
|
|
s : Families!Member (s.isFemale())
|
|
|
|
s1 : Persons!Female
|
|
|
|
s2 : SimplePersons!SimplePerson (not s2.male)
|
|
|
|
with (brauche ich hier gar nicht)
|
|
|
|
s.firstName + ' ' + s.lastName == s1.fullName == s2.completeName //s.lastName musst be a helper function
|
|
|
|
// Abbilden der Weiblichkeitsbeziehung nicht anders machbar
|
|
|
|
to
|
|
|
|
t1 : Families!Family (
|
|
|
|
lastName <- s1.lastName == s2.lastName
|
|
|
|
),
|
|
|
|
t2 : Families!Member (
|
|
|
|
firstName <- s1.firstName == s2.firstName,
|
|
|
|
familyDaughter <- t1
|
|
|
|
),
|
|
|
|
t3 : SimplePersons!SimplePerson (
|
|
|
|
completeName <- s.firstName + ' ' + s.lastName == s1.fullName,
|
|
|
|
male <- Boolean.FALSE
|
|
|
|
),
|
|
|
|
t4 : Persons!Female (
|
|
|
|
fullName <- s.firstName + ' ' + s.lastName == s2.completeName
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
createRule MemberAndPersonAndSimplePerson {
|
|
|
|
of
|
|
|
|
s : Families!Member (not s.isFemale())
|
|
|
|
s1 : Persons!Male
|
|
|
|
s2 : SimplePersons!SimplePerson (s2.male)
|
|
|
|
with (brauche ich hier gar nicht)
|
|
|
|
s.firstName + ' ' + s.lastName == s1.fullName == s2.completeName //s.lastName musst be a helper function
|
|
|
|
// Abbilden der Weiblichkeitsbeziehung nicht anders machbar
|
|
|
|
to
|
|
|
|
t1 : Families!Family (
|
|
|
|
lastName <- s1.lastName == s2.lastName
|
|
|
|
),
|
|
|
|
t2 : Families!Member (
|
|
|
|
firstName <- s1.firstName == s2.firstName,
|
|
|
|
familySon <- t1
|
|
|
|
),
|
|
|
|
t3 : SimplePersons!SimplePerson (
|
|
|
|
completeName <- s.firstName + ' ' + s.lastName == s1.fullName,
|
|
|
|
male <- Boolean.TRUE
|
|
|
|
),
|
|
|
|
t4 : Persons!Male (
|
|
|
|
fullName <- s.firstName + ' ' + s.lastName == s2.completeName
|
|
|
|
)
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### ATL Variante mit einem Input und mehreren Output Modellen
|
|
|
|
|
|
|
|
### Von Families aus
|
|
|
|
```
|
|
|
|
createRule Families2PersonAndSimplePersonFemale {
|
|
|
|
from
|
|
|
|
s : Families!Member (s.isFemale())
|
|
|
|
to
|
|
|
|
t1 : SimplePersons!SimplePerson (
|
|
|
|
completeName <- s.firstName + ' ' + s.lastName,
|
|
|
|
male <- Boolean.FALSE
|
|
|
|
),
|
|
|
|
t2 : Persons!Female (
|
|
|
|
fullName <- s.firstName + ' ' + s.lastName
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
createRule Families2PersonAndSimplePersonMale {
|
|
|
|
from
|
|
|
|
s : Families!Member (not s.isFemale())
|
|
|
|
to
|
|
|
|
t1 : SimplePersons!SimplePerson (
|
|
|
|
completeName <- s.firstName + ' ' + s.lastName,
|
|
|
|
male <- Boolean.TRUE
|
|
|
|
),
|
|
|
|
t2 : Persons!Male (
|
|
|
|
fullName <- s.firstName + ' ' + s.lastName
|
|
|
|
)
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### Von Person aus
|
|
|
|
|
|
|
|
```
|
|
|
|
createRule Persons2FamiliesAndSimplePersonFemale {
|
|
|
|
from
|
|
|
|
s : Persons!Female
|
|
|
|
to
|
|
|
|
t1 : Families!Family (
|
|
|
|
lastName <- s.lastName
|
|
|
|
),
|
|
|
|
t2 : Families!Member (
|
|
|
|
firstName <- s.firstName,
|
|
|
|
familyDaughter <- t1
|
|
|
|
),
|
|
|
|
t3 : SimplePersons!SimplePerson (
|
|
|
|
completeName <- s.fullName, // s.firstName + ' ' + s.lastName,
|
|
|
|
male <- Boolean.FALSE
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
createRule Persons2FamiliesAndSimplePersonMale {
|
|
|
|
from
|
|
|
|
s : Persons!Male
|
|
|
|
to
|
|
|
|
t1 : Families!Family (
|
|
|
|
lastName <- s.lastName
|
|
|
|
),
|
|
|
|
t2 : Families!Member (
|
|
|
|
firstName <- s.firstName,
|
|
|
|
familySon <- t1
|
|
|
|
),
|
|
|
|
t3 : SimplePersons!SimplePerson (
|
|
|
|
completeName <- s.fullName, // s.firstName + ' ' + s.lastName,
|
|
|
|
male <- Boolean.TRUE
|
|
|
|
)
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### Von SimplePerson aus
|
|
|
|
|
|
|
|
```
|
|
|
|
createRule SimplePersons2FamiliesAndPersonFemale {
|
|
|
|
from
|
|
|
|
s : SimplePersons!SimplePerson (not s.male)
|
|
|
|
to
|
|
|
|
t1 : Families!Family (
|
|
|
|
lastName <- s.lastName
|
|
|
|
),
|
|
|
|
t2 : Families!Member (
|
|
|
|
firstName <- s.firstName,
|
|
|
|
familyDaughter <- t1
|
|
|
|
),
|
|
|
|
t3 : Persons!Famale (
|
|
|
|
fullName <- s.completeName // s.firstName + ' ' + s.lastName
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
createRule SimplePersons2FamiliesAndPersonMale {
|
|
|
|
from
|
|
|
|
s : SimplePersons!SimplePerson (s.male)
|
|
|
|
to
|
|
|
|
t1 : Families!Family (
|
|
|
|
lastName <- s.lastName
|
|
|
|
),
|
|
|
|
t2 : Families!Member (
|
|
|
|
firstName <- s.firstName,
|
|
|
|
familySon <- t1
|
|
|
|
),
|
|
|
|
t4 : Persons!Male (
|
|
|
|
fullName <- s.completeName // s.firstName + ' ' + s.lastName
|
|
|
|
)
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
## Delete Rules
|
|
|
|
```
|
|
|
|
deleteRule MembersAndPersonsAndSimplePersons {
|
|
|
|
of
|
|
|
|
s1 : Families!Member
|
|
|
|
s2 : SimplePersons!SimplePerson
|
|
|
|
s3 : Persons!Person
|
|
|
|
without (Ich weiß nicht ob man das benötigt)
|
|
|
|
s3 : Persons!Person
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
- Regel für interne Relationen in Modellen
|
|
|
|
- Eigentlich uninteressant für die Sprache jedoch wäre es schon schön die irgendwie mit abzudecken
|
|
|
|
|
|
|
|
```
|
|
|
|
deleteRule FamiliesAndMembers {
|
|
|
|
from
|
|
|
|
s1 : Families!Member (s1.onlyFamilyMember())
|
|
|
|
s2 : Families!Family
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
# HYBRID ANSATZ
|
|
|
|
- Verwenden von kompletten Regeln (1) und getrennten Regeln (2)
|
|
|
|
- Vorteil:
|
|
|
|
- kurze Regelschreibweisen möglich
|
|
|
|
- feingranuales betrachten von Elementtypen möglich
|
|
|
|
- Nachteil:
|
|
|
|
- kompliziertere Regelsprache durch das Abdecken aller Fälle
|
|
|
|
- kann zu unübersichtlichkeiten innerhalb der Regeln kommen
|
|
|
|
- oberen 2 Ansätze verbinden
|
|
|
|
- erst möglich falls beide Ansätze komplett ausgearbeitet sind
|
|
|
|
|
|
|
|
# HELPER CONTEXT RULES (from ATL)
|
|
|
|
- Können wir in unserem Ansatz einfach wieder verwenden
|
|
|
|
- Neues Compartment für Helper Regeln mit einer Menge an Rollen für verschiedene Elemente aus den unterschiedlichen Modellen
|
|
|
|
- Beispiele eine Rolle für Families!Member welche die Funktionen implementiert:
|
|
|
|
- helperFamily : Families!Family
|
|
|
|
- helperFamilyName : String
|
|
|
|
- helperIsFemale : Boolean
|
|
|
|
|
|
|
|
```
|
|
|
|
helper context Families!Member def : family : Families!Family =
|
|
|
|
if not self.familyFather.oclIsUndefined () then
|
|
|
|
self.familyFather
|
|
|
|
else
|
|
|
|
if not self.familyMother.oclIsUndefined () then
|
|
|
|
self.familyMother
|
|
|
|
else
|
|
|
|
if not self.familySon.oclIsUndefined () then
|
|
|
|
self.familySon
|
|
|
|
else
|
|
|
|
self.familyDaughter
|
|
|
|
endif
|
|
|
|
endif
|
|
|
|
endif;
|
|
|
|
|
|
|
|
helper context Families!Member def : familyName : String =
|
|
|
|
if not self.familyFather.oclIsUndefined () then
|
|
|
|
self.familyFather.lastName
|
|
|
|
else
|
|
|
|
if not self.familyMother.oclIsUndefined () then
|
|
|
|
self.familyMother.lastName
|
|
|
|
else
|
|
|
|
if not self.familySon.oclIsUndefined () then
|
|
|
|
self.familySon.lastName
|
|
|
|
else
|
|
|
|
self.familyDaughter.lastName
|
|
|
|
endif
|
|
|
|
endif
|
|
|
|
endif;
|
|
|
|
|
|
|
|
helper context Families!Member def : isFemale () : Boolean =
|
|
|
|
if not self.familyMother.oclIsUndefined () then
|
|
|
|
true
|
|
|
|
else
|
|
|
|
if not self.familyDaughter.oclIsUndefined ( ) then
|
|
|
|
true
|
|
|
|
else
|
|
|
|
false
|
|
|
|
endif
|
|
|
|
endif;
|
|
|
|
```
|
|
|
|
|
|
|
|
### Helper Regeln um an die firstName und lastName Elemente aus Person und SimplePerson zu kommen
|
|
|
|
```
|
|
|
|
helper context SimplePersons!SimplePerson def : firstName : String =
|
|
|
|
self.completeName.split(' ').first;
|
|
|
|
|
|
|
|
helper context SimplePersons!SimplePerson def : lastName : String =
|
|
|
|
self.completeName.split(' ').last;
|
|
|
|
|
|
|
|
helper context Persons!Person def : firstName : String =
|
|
|
|
self.fullName.split(' ').first;
|
|
|
|
|
|
|
|
helper context Persons!Person def : lastName : String =
|
|
|
|
self.fullName.split(' ').last;
|
|
|
|
``` |