diff --git a/.gitignore b/.gitignore index a5b301de2e3f121b8dd7a09ea9fe0b667da4c369..5e142013c2bdbc64d4fe3558748328a282bbfc7a 100644 --- a/.gitignore +++ b/.gitignore @@ -176,3 +176,8 @@ local.properties .project output/ doc/ +[lL]ocal[tT]est* + +# ANTLR + +gen/ diff --git a/.gitmodules b/.gitmodules index 5ed635731bd2541c2765d6ab654a00c411e18bbc..84f8c68c71d26f84896c11395e0cf33dad5ac73f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,3 @@ -[submodule "lib/ModelSyncProvider"] - path = lib/ModelSyncProvider - url = https://git-st.inf.tu-dresden.de/cwerner/role_model_synchronization_provider.git -[submodule "lib/SCROLL"] - path = lib/SCROLL - url = https://github.com/portux/SCROLL.git [submodule "src/main/asciidoc"] path = src/main/doc url = https://git-st.inf.tu-dresden.de/cwerner/code_generator.wiki.git diff --git a/assets/Classdiagram_acr_model.pdf b/assets/Classdiagram_acr_model.pdf new file mode 100644 index 0000000000000000000000000000000000000000..53971a45fd0799ae231074a519fc6025c53a601a Binary files /dev/null and b/assets/Classdiagram_acr_model.pdf differ diff --git a/assets/model_join/complex.modeljoin b/assets/model_join/complex.modeljoin new file mode 100644 index 0000000000000000000000000000000000000000..610f0771a034d528b50c58f2fcc84dc021435705 --- /dev/null +++ b/assets/model_join/complex.modeljoin @@ -0,0 +1,16 @@ + +natural join imdbdatabase.Film with elib.VideoCassette as joins.JoinMovie { + keep attributes imdbdatabase.Film.year + keep aggregate avg(score) over Film.votes as Movie.averageRating + keep calculated attribute imdbdatabase.Film.votes->select(v|v.score==10)->size() as Movie.topratings:EInt + keep supertype elib.AudioVisualItem as type jointarget.MediaItem { + keep attributes elib.AudioVisualItem.minutesLength + } + keep outgoing imdbdatabase.Film.votes as type jointarget.Vote { + keep attributes imdbdatabase.Vote.score + } + keep outgoing elib.VideoCassette.cast as type jointarget.Person { + keep attributes elib.Person.lastName + } + +} diff --git a/assets/model_join/libraryComplete.modeljoin b/assets/model_join/libraryComplete.modeljoin new file mode 100644 index 0000000000000000000000000000000000000000..27db0faf62b4600552a15e3fd62cdfb0d7cdc55e --- /dev/null +++ b/assets/model_join/libraryComplete.modeljoin @@ -0,0 +1,11 @@ +natural join lib.Library with lib.Library as lib.Library { + keep attributes lib.Library.name + keep outgoing lib.Library.employees as type lib.Employee { + keep attributes lib.Employee.salary + keep outgoing lib.Employee.manager as type lib.Employee { + } + keep supertype lib.Person as type lib.Person { + keep attributes lib.Person.name + } + } + } \ No newline at end of file diff --git a/assets/model_join/librarySimple.modeljoin b/assets/model_join/librarySimple.modeljoin new file mode 100644 index 0000000000000000000000000000000000000000..db8daaed892dc182f0ba8d5eec3e967099ecdd65 --- /dev/null +++ b/assets/model_join/librarySimple.modeljoin @@ -0,0 +1,9 @@ +natural join lib.Library with lib.Library as lib.Library { + keep attributes lib.Library.name + keep outgoing lib.Library.employees as type lib.Employee { + keep attributes lib.Employee.salary + keep supertype lib.Person as type lib.Person { + keep attributes lib.Person.name + } + } + } \ No newline at end of file diff --git a/assets/model_join/manager.modeljoin b/assets/model_join/manager.modeljoin new file mode 100644 index 0000000000000000000000000000000000000000..267f864506286730978bf97d5cdc5426438adf86 --- /dev/null +++ b/assets/model_join/manager.modeljoin @@ -0,0 +1,8 @@ +natural join lib.Employee with lib.Employee as lib.Employee { + keep attributes lib.Employee.salary + keep outgoing lib.Employee.manager as type lib.Employee { + } + keep supertype lib.Person as type lib.Person { + keep attributes lib.Person.name + } + } \ No newline at end of file diff --git a/assets/model_join/multiple_joins.modeljoin b/assets/model_join/multiple_joins.modeljoin new file mode 100644 index 0000000000000000000000000000000000000000..dbee52d23a4a0c00ae7c0eb74a5d4989cdc611c7 --- /dev/null +++ b/assets/model_join/multiple_joins.modeljoin @@ -0,0 +1,10 @@ + +natural join imdb.Film with library.VideoCassette as jointarget.Movie { + keep attributes imdb.Film.year + keep attributes library.AudioVisualItem.minutesLength +} + +natural join imdb.Film with library.Author as jointarget.Director { + keep attributes imdb.Film.title + keep attributes library.Author.name +} diff --git a/assets/model_join/shrinking.modeljoin b/assets/model_join/shrinking.modeljoin new file mode 100644 index 0000000000000000000000000000000000000000..427c5b2a8f8176f3aa78d3bc436dc9fa064b9b76 --- /dev/null +++ b/assets/model_join/shrinking.modeljoin @@ -0,0 +1,14 @@ + +natural join shrinking.Class with shrinking.Class as shrinking.Class { + keep supertype shrinking.Classifier as type shrinking.Classifier { + keep attributes shrinking.Classifier.name + } + keep outgoing shrinking.StructuredClassifier.part as type shrinking.Property { + keep attributes shrinking.ConnectableElement.name + } + keep outgoing shrinking.StructuredClassifier.role as type shrinking.Property { + keep attributes shrinking.ConnectableElement.name + } + keep outgoing shrinking.StructuredClassifier.ownedAttribute as type shrinking.Property { + } +} diff --git a/assets/model_join/simple.modeljoin b/assets/model_join/simple.modeljoin new file mode 100644 index 0000000000000000000000000000000000000000..5c22f623aa25cfc5361290c89310c984e7f7abf4 --- /dev/null +++ b/assets/model_join/simple.modeljoin @@ -0,0 +1,11 @@ + +natural join imdbdatabase.Film with elib.VideoCassette as joins.JoinMovie { + keep attributes imdbdatabase.Film.year + keep attributes eclipselibrary.AudioVisualItem.minutesLength + keep outgoing imdbdatabase.Film.votes as type jointarget.Vote { + keep attributes imdbdatabase.Vote.score + } + keep outgoing elib.VideoCassette.cast as type jointarget.Person { + keep attributes elib.Person.lastName + } +} diff --git a/assets/model_join/theta_join.modeljoin b/assets/model_join/theta_join.modeljoin new file mode 100644 index 0000000000000000000000000000000000000000..73a1d88b433b511fa8ad57ca9f74a867facaab6f --- /dev/null +++ b/assets/model_join/theta_join.modeljoin @@ -0,0 +1,4 @@ +theta join imdb.Film with library.Movie where imdb.Film.title = library.Movie.name as jointarget.Movie { + keep attributes imdb.Film.title + keep attributes library.Author.name +} diff --git a/assets/models/AML.ecore b/assets/models/AML.ecore new file mode 100644 index 0000000000000000000000000000000000000000..a073b44ca3e0778a8a37fbd86c546b49da53a881 --- /dev/null +++ b/assets/models/AML.ecore @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="AMLLanguage" nsURI="http://www.example.org/aml" nsPrefix="aml"> + <eClassifiers xsi:type="ecore:EClass" name="CAEXObject" abstract="true"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="id" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Attribute" eSuperTypes="#//CAEXObject"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="SystemUnitClass" eSuperTypes="#//CAEXObject"> + <eStructuralFeatures xsi:type="ecore:EReference" name="attributes" upperBound="-1" + eType="#//Attribute" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="internalElements" upperBound="-1" + eType="#//InternalElement" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="InternalElement" eSuperTypes="#//SystemUnitClass"> + <eStructuralFeatures xsi:type="ecore:EReference" name="baseSystemUnit" eType="#//SystemUnitClass"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="InstanceHierarchy" eSuperTypes="#//CAEXObject"> + <eStructuralFeatures xsi:type="ecore:EReference" name="internalElements" upperBound="-1" + eType="#//InternalElement" containment="true"/> + </eClassifiers> +</ecore:EPackage> diff --git a/assets/models/BDD.ecore b/assets/models/BDD.ecore new file mode 100644 index 0000000000000000000000000000000000000000..746b77f223ecbfcbc42d5f1d256f351869dd3d22 --- /dev/null +++ b/assets/models/BDD.ecore @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> + <ecore:EPackage name="BDD" nsURI="https://www.transformation-tool-contest.eu/2019/bdd" xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" + nsPrefix="bdd"> + <eClassifiers xsi:type="ecore:EClass" name="BDD"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" ordered="false" + unique="false" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="ports" ordered="false" + lowerBound="1" upperBound="-1" eType="#/0/Port" containment="true" eOpposite="#/0/Port/owner"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="tree" ordered="false" + lowerBound="1" eType="#/0/Tree" containment="true" eOpposite="#/0/Tree/ownerBDD"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Port" abstract="true"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" ordered="false" + unique="false" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="owner" ordered="false" + lowerBound="1" eType="#/0/BDD" eOpposite="#/0/BDD/ports"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="InputPort" eSuperTypes="#/0/Port"> + <eStructuralFeatures xsi:type="ecore:EReference" name="subtrees" ordered="false" + upperBound="-1" eType="#/0/Subtree" eOpposite="#/0/Subtree/port"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="OutputPort" eSuperTypes="#/0/Port"> + <eStructuralFeatures xsi:type="ecore:EReference" name="assignments" ordered="false" + upperBound="-1" eType="#/0/Assignment" eOpposite="#/0/Assignment/port"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Tree" abstract="true"> + <eStructuralFeatures xsi:type="ecore:EReference" name="ownerBDD" ordered="false" + eType="#/0/BDD" eOpposite="#/0/BDD/tree"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="ownerSubtreeForZero" + ordered="false" eType="#/0/Subtree" eOpposite="#/0/Subtree/treeForZero"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="ownerSubtreeForOne" ordered="false" + eType="#/0/Subtree" eOpposite="#/0/Subtree/treeForOne"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Leaf" eSuperTypes="#/0/Tree"> + <eStructuralFeatures xsi:type="ecore:EReference" name="assignments" ordered="false" + lowerBound="1" upperBound="-1" eType="#/0/Assignment" containment="true" + eOpposite="#/0/Assignment/owner"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Assignment"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" ordered="false" + unique="false" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="port" ordered="false" + lowerBound="1" eType="#/0/OutputPort" eOpposite="#/0/OutputPort/assignments"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="owner" ordered="false" + lowerBound="1" eType="#/0/Leaf" eOpposite="#/0/Leaf/assignments"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Subtree" eSuperTypes="#/0/Tree"> + <eStructuralFeatures xsi:type="ecore:EReference" name="port" ordered="false" + lowerBound="1" eType="#/0/InputPort" eOpposite="#/0/InputPort/subtrees"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="treeForZero" ordered="false" + lowerBound="1" eType="#/0/Tree" containment="true" eOpposite="#/0/Tree/ownerSubtreeForZero"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="treeForOne" ordered="false" + lowerBound="1" eType="#/0/Tree" containment="true" eOpposite="#/0/Tree/ownerSubtreeForOne"/> + </eClassifiers> + </ecore:EPackage> diff --git a/assets/models/BDDv2.ecore b/assets/models/BDDv2.ecore new file mode 100644 index 0000000000000000000000000000000000000000..451da6f04bf5b7609b80d69503beb024a6cc8a89 --- /dev/null +++ b/assets/models/BDDv2.ecore @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="bddg" nsURI="https://www.transformation-tool-contest.eu/2019/bdd/graph" + nsPrefix="bddg"> + <eClassifiers xsi:type="ecore:EClass" name="BDD"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" ordered="false" unique="false" + lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="ports" ordered="false" + lowerBound="1" upperBound="-1" eType="#//Port" containment="true" eOpposite="#//Port/owner"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="root" ordered="false" lowerBound="1" + eType="#//Tree"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="trees" upperBound="-1" + eType="#//Tree" containment="true" eOpposite="#//Tree/ownerBDD"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Port" abstract="true"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" ordered="false" unique="false" + lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="owner" ordered="false" + lowerBound="1" eType="#//BDD" eOpposite="#//BDD/ports"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="InputPort" eSuperTypes="#//Port"> + <eStructuralFeatures xsi:type="ecore:EReference" name="subtrees" ordered="false" + upperBound="-1" eType="#//Subtree" eOpposite="#//Subtree/port"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="OutputPort" eSuperTypes="#//Port"> + <eStructuralFeatures xsi:type="ecore:EReference" name="assignments" ordered="false" + upperBound="-1" eType="#//Assignment" eOpposite="#//Assignment/port"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Tree" abstract="true"> + <eStructuralFeatures xsi:type="ecore:EReference" name="ownerBDD" ordered="false" + eType="#//BDD" eOpposite="#//BDD/trees"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="ownerSubtreeForZero" ordered="false" + upperBound="-1" eType="#//Subtree" eOpposite="#//Subtree/treeForZero"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="ownerSubtreeForOne" ordered="false" + upperBound="-1" eType="#//Subtree" eOpposite="#//Subtree/treeForOne"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Leaf" eSuperTypes="#//Tree"> + <eStructuralFeatures xsi:type="ecore:EReference" name="assignments" ordered="false" + lowerBound="1" upperBound="-1" eType="#//Assignment" containment="true" eOpposite="#//Assignment/owner"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Assignment"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" ordered="false" + unique="false" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="port" ordered="false" lowerBound="1" + eType="#//OutputPort" eOpposite="#//OutputPort/assignments"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="owner" ordered="false" + lowerBound="1" eType="#//Leaf" eOpposite="#//Leaf/assignments"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Subtree" eSuperTypes="#//Tree"> + <eStructuralFeatures xsi:type="ecore:EReference" name="port" ordered="false" lowerBound="1" + eType="#//InputPort" eOpposite="#//InputPort/subtrees"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="treeForZero" ordered="false" + lowerBound="1" eType="#//Tree" eOpposite="#//Tree/ownerSubtreeForZero"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="treeForOne" ordered="false" + lowerBound="1" eType="#//Tree" eOpposite="#//Tree/ownerSubtreeForOne"/> + </eClassifiers> +</ecore:EPackage> diff --git a/assets/models/ClassDiagram.ecore b/assets/models/ClassDiagram.ecore new file mode 100644 index 0000000000000000000000000000000000000000..f9051d9176d20d20ee263381e392d9830bd78026 --- /dev/null +++ b/assets/models/ClassDiagram.ecore @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="classdiagram" nsURI="http://www.example.org/develop" nsPrefix="dev"> + <eClassifiers xsi:type="ecore:EClass" name="ClassDiagram"> + <eStructuralFeatures xsi:type="ecore:EReference" name="classes" upperBound="-1" + eType="#//Class" containment="true" eOpposite="#//Class/diagram"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Class"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="className" unique="false" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="diagram" lowerBound="1" + eType="#//ClassDiagram" eOpposite="#//ClassDiagram/classes"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="associations" upperBound="-1" + eType="#//Association" containment="true" eOpposite="#//Association/class"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="usedBy" upperBound="-1" + eType="#//Association" eOpposite="#//Association/type"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Association"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" unique="false" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="lowerBound" unique="false" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="upperBound" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="class" lowerBound="1" eType="#//Class" + eOpposite="#//Class/associations"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="type" lowerBound="1" eType="#//Class" + eOpposite="#//Class/usedBy"/> + </eClassifiers> +</ecore:EPackage> diff --git a/assets/models/ClassDiagram.png b/assets/models/ClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..424064e2fca73ded663ccadd999cdbcf37c99356 Binary files /dev/null and b/assets/models/ClassDiagram.png differ diff --git a/assets/models/EMFLibrary.ecore b/assets/models/EMFLibrary.ecore new file mode 100644 index 0000000000000000000000000000000000000000..9d9235783b17819f20b820f832c7d418cd00e833 --- /dev/null +++ b/assets/models/EMFLibrary.ecore @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="UTF-8"?> + <ecore:EPackage xmi:version="2.0" + xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="library" + nsURI="http://www.eclipse.org/emf/jcrm/samples/emf/sample/Library" nsPrefix="library"> + <eClassifiers xsi:type="ecore:EClass" name="Book"> + <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData"> + <details key="name" value="Book"/> + <details key="kind" value="elementOnly"/> + </eAnnotations> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="title" unique="false" lowerBound="1" + eType="ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//String"> + <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData"> + <details key="kind" value="element"/> + <details key="name" value="title"/> + </eAnnotations> + </eStructuralFeatures> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="pages" unique="false" lowerBound="1" + eType="ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//Int" unsettable="true"> + <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData"> + <details key="kind" value="element"/> + <details key="name" value="pages"/> + </eAnnotations> + </eStructuralFeatures> + <eStructuralFeatures xsi:type="ecore:EReference" name="author" lowerBound="1" + eType="#//Writer"> + <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData"> + <details key="kind" value="element"/> + <details key="name" value="author"/> + </eAnnotations> + </eStructuralFeatures> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Library"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" unique="false" lowerBound="1" + eType="ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//String"> + <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData"> + <details key="kind" value="element"/> + <details key="name" value="name"/> + </eAnnotations> + </eStructuralFeatures> + <eStructuralFeatures xsi:type="ecore:EReference" name="books" upperBound="-1" + eType="#//Book" containment="true"> + <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData"> + <details key="kind" value="element"/> + <details key="name" value="books"/> + </eAnnotations> + </eStructuralFeatures> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Writer"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" unique="false" lowerBound="1" + eType="ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//String"> + <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData"> + <details key="kind" value="element"/> + <details key="name" value="name"/> + </eAnnotations> + </eStructuralFeatures> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="GuideBookWriter" eSuperTypes="#//Writer"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="countries" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="SpecialistBookWriter" eSuperTypes="#//Writer"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="subject" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> +</ecore:EPackage> \ No newline at end of file diff --git a/assets/models/Family.ecore b/assets/models/Family.ecore new file mode 100644 index 0000000000000000000000000000000000000000..c2218c505028bedbc10a417e4747b371359b6da4 --- /dev/null +++ b/assets/models/Family.ecore @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="Family" nsURI="http://www.example.org/ttc17" nsPrefix="ttc17"> + <eClassifiers xsi:type="ecore:EClass" name="Member"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="firstName" unique="false" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="familyMother" eType="#//Family" + eOpposite="#//Family/mother"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="familyFather" eType="#//Family" + eOpposite="#//Family/father"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="familySon" eType="#//Family" + eOpposite="#//Family/familySons"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="familyDaughter" eType="#//Family" + eOpposite="#//Family/familyDaugthers"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Family"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="lastName" unique="false" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="mother" eType="#//Member" + containment="true" eOpposite="#//Member/familyMother"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="father" eType="#//Member" + containment="true" eOpposite="#//Member/familyFather"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="familyDaugthers" upperBound="-1" + eType="#//Member" containment="true" eOpposite="#//Member/familyDaughter"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="familySons" upperBound="-1" + eType="#//Member" containment="true" eOpposite="#//Member/familySon"/> + </eClassifiers> +</ecore:EPackage> diff --git a/assets/models/Family.png b/assets/models/Family.png new file mode 100644 index 0000000000000000000000000000000000000000..c69c975b06872def2dc68f2e3a58f9a3f39bc7c3 Binary files /dev/null and b/assets/models/Family.png differ diff --git a/assets/models/Family.sync.json b/assets/models/Family.sync.json new file mode 100644 index 0000000000000000000000000000000000000000..202c10d84384bf8d1509c8e0b4a9cca6927a774a --- /dev/null +++ b/assets/models/Family.sync.json @@ -0,0 +1 @@ +{"name":"Family","init":{"name":"FamilyModel","primaryClass":"Family.Family","image":"Family.png","nested":[{"name":"MemberModel","primaryClass":"Family.Member"}]}} \ No newline at end of file diff --git a/assets/models/IMDBDatabase.ecore b/assets/models/IMDBDatabase.ecore new file mode 100644 index 0000000000000000000000000000000000000000..e97c1c4f8c409e15d51506b80cadaea050dcec16 --- /dev/null +++ b/assets/models/IMDBDatabase.ecore @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="IMDBdatabase" nsURI="http://www.example.org/database" nsPrefix="imdbdatabase"> + <eClassifiers xsi:type="ecore:EClass" name="IMDB"> + <eStructuralFeatures xsi:type="ecore:EReference" name="users" upperBound="-1" + eType="#//User" containment="true" eOpposite="#//User/library"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="actors" upperBound="-1" + eType="#//Actor" containment="true" eOpposite="#//Actor/library"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="films" upperBound="-1" + eType="#//Film" containment="true" eOpposite="#//Film/library"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="votes" upperBound="-1" + eType="#//Vote" containment="true" eOpposite="#//Vote/library"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Film"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="title" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="year" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="library" eType="#//IMDB" + eOpposite="#//IMDB/films"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="figures" lowerBound="1" + upperBound="-1" eType="#//Figure" containment="true" eOpposite="#//Figure/film"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="votes" upperBound="-1" + eType="#//Vote" eOpposite="#//Vote/film"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Vote"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="score" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="library" lowerBound="1" + eType="#//IMDB" eOpposite="#//IMDB/votes"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="film" lowerBound="1" eType="#//Film" + eOpposite="#//Film/votes"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="user" lowerBound="1" eType="#//User"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Figure"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="film" eType="#//Film" eOpposite="#//Film/figures"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="playedBy" lowerBound="1" + upperBound="-1" eType="#//Actor" eOpposite="#//Actor/playsIn"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Person"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="dob" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDouble"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Actor" eSuperTypes="#//Person"> + <eStructuralFeatures xsi:type="ecore:EReference" name="playsIn" upperBound="-1" + eType="#//Figure" eOpposite="#//Figure/playedBy"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="library" eType="#//IMDB" + eOpposite="#//IMDB/actors"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="User" eSuperTypes="#//Person"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="userName" lowerBound="1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="email" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="library" lowerBound="1" + eType="#//IMDB" eOpposite="#//IMDB/users"/> + </eClassifiers> +</ecore:EPackage> diff --git a/assets/models/IMDBDatabase.png b/assets/models/IMDBDatabase.png new file mode 100644 index 0000000000000000000000000000000000000000..72a34d444e259f6bff9dc2b43565511c599740d4 Binary files /dev/null and b/assets/models/IMDBDatabase.png differ diff --git a/assets/models/JavaSourceCode.ecore b/assets/models/JavaSourceCode.ecore new file mode 100644 index 0000000000000000000000000000000000000000..053bc0ec25186580a8109aed96da82b242c3b73a --- /dev/null +++ b/assets/models/JavaSourceCode.ecore @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="javasourcecode" nsURI="http://www.example.org/develop" nsPrefix="dev"> + <eClassifiers xsi:type="ecore:EClass" name="Method"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" unique="false" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="class" lowerBound="1" eType="#//ClassType" + eOpposite="#//ClassType/methods"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="calling" upperBound="-1" + eType="#//Method" eOpposite="#//Method/calledBy"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="calledBy" upperBound="-1" + eType="#//Method" eOpposite="#//Method/calling"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ClassType"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" unique="false" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="asg" lowerBound="1" eType="#//JavaASG" + eOpposite="#//JavaASG/classes"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="methods" upperBound="-1" + eType="#//Method" containment="true" eOpposite="#//Method/class"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="JavaASG"> + <eStructuralFeatures xsi:type="ecore:EReference" name="classes" upperBound="-1" + eType="#//ClassType" containment="true" eOpposite="#//ClassType/asg"/> + </eClassifiers> +</ecore:EPackage> diff --git a/assets/models/JavaSourceCode.png b/assets/models/JavaSourceCode.png new file mode 100644 index 0000000000000000000000000000000000000000..76ff96ce43f8956fd24cbcd4e6bc7776bfb600b9 Binary files /dev/null and b/assets/models/JavaSourceCode.png differ diff --git a/assets/models/Library.ecore b/assets/models/Library.ecore new file mode 100644 index 0000000000000000000000000000000000000000..c281ccd51d05716e4033331b02b2f4ee4bc561ce --- /dev/null +++ b/assets/models/Library.ecore @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="Library" nsURI="http://www.example.org/library" nsPrefix="lib"> + <eClassifiers xsi:type="ecore:EClass" name="Library"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" unique="false" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="employees" upperBound="-1" + eType="#//Employee" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Employee" eSuperTypes="#//Person"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="salary" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDouble"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="manager" eType="#//Employee"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Person" abstract="true"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> +</ecore:EPackage> diff --git a/assets/models/Library.png b/assets/models/Library.png new file mode 100644 index 0000000000000000000000000000000000000000..8216f945be7da29639bf2b3f56d4f8a5189de6e0 Binary files /dev/null and b/assets/models/Library.png differ diff --git a/assets/models/Library.sync.json b/assets/models/Library.sync.json new file mode 100644 index 0000000000000000000000000000000000000000..99a95134654a9aa038ce37aa92e3d92283222794 --- /dev/null +++ b/assets/models/Library.sync.json @@ -0,0 +1 @@ +{"name":"Library","init":{"name":"Library","primaryClass":"sync.lib.Library","image":"Library.png","nested":[{"name":"Person","primaryClass":"sync.lib.Person","additionalClasses":["sync.lib.Employee"]}]}} \ No newline at end of file diff --git a/assets/models/ModelJoinLibrary.ecore b/assets/models/ModelJoinLibrary.ecore new file mode 100644 index 0000000000000000000000000000000000000000..e5669ac1ca777b8cc9bd5df581aba778559cd473 --- /dev/null +++ b/assets/models/ModelJoinLibrary.ecore @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="Eclipselibrary" nsURI="http://www.example.org/eclipselibrary" + nsPrefix="elib"> + <eClassifiers xsi:type="ecore:EClass" name="Item" abstract="true"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="publicationDate" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDate"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="title" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Periodical" eSuperTypes="#//Item"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="issuesPerYear" lowerBound="1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EEnum" name="BookCategory"> + <eLiterals name="Mystery"/> + <eLiterals name="ScienceFiction" value="1"/> + <eLiterals name="Biography" value="2"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="CirculatingItem" abstract="true" eSuperTypes="#//Item"/> + <eClassifiers xsi:type="ecore:EClass" name="Book" eSuperTypes="#//CirculatingItem"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="pages" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="category" eType="#//BookCategory"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="author" lowerBound="1" + eType="#//Writer" eOpposite="#//Writer/books"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="AudioVisualItem" abstract="true" eSuperTypes="#//CirculatingItem"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="minutesLength" lowerBound="1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="damaged" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="VideoCassette" eSuperTypes="#//AudioVisualItem"> + <eStructuralFeatures xsi:type="ecore:EReference" name="cast" upperBound="-1" eType="#//Person"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="BookOnTape" eSuperTypes="#//AudioVisualItem"> + <eStructuralFeatures xsi:type="ecore:EReference" name="reader" eType="#//Person"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="author" eType="#//Writer"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Person"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="firstName" lowerBound="1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="lastName" lowerBound="1" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Writer" eSuperTypes="#//Person"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="books" upperBound="-1" + eType="#//Book" eOpposite="#//Book/author"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Library"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="stock" upperBound="-1" + eType="#//Item" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="books" upperBound="-1" + eType="#//Book"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="writers" upperBound="-1" + eType="#//Writer" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="borrowers" upperBound="-1" + eType="#//Borrower" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="employees" upperBound="-1" + eType="#//Employee" containment="true"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="branches" upperBound="-1" + eType="#//Library" containment="true" eOpposite="#//Library/parentBranch"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="parentBranch" eType="#//Library" + eOpposite="#//Library/branches"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Borrower" eSuperTypes="#//Person"/> + <eClassifiers xsi:type="ecore:EClass" name="Employee" eSuperTypes="#//Person"> + <eStructuralFeatures xsi:type="ecore:EReference" name="manager" eType="#//Employee"/> + </eClassifiers> +</ecore:EPackage> diff --git a/assets/models/ModelJoinLibrary.png b/assets/models/ModelJoinLibrary.png new file mode 100644 index 0000000000000000000000000000000000000000..7ce2618b59b87a2db3858a8163f776d01d25de08 Binary files /dev/null and b/assets/models/ModelJoinLibrary.png differ diff --git a/assets/models/Person.ecore b/assets/models/Person.ecore new file mode 100644 index 0000000000000000000000000000000000000000..73f31165bb4ea87cd28a9bf068d6b6790513f440 --- /dev/null +++ b/assets/models/Person.ecore @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="Person" nsURI="http://www.example.org/ttc17" nsPrefix="ttc17"> + <eClassifiers xsi:type="ecore:EClass" name="Person" abstract="true"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="fullName" unique="false" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="birthday" unique="false" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDate"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Male" eSuperTypes="#//Person"/> + <eClassifiers xsi:type="ecore:EClass" name="Female" eSuperTypes="#//Person"/> +</ecore:EPackage> diff --git a/assets/models/Person.png b/assets/models/Person.png new file mode 100644 index 0000000000000000000000000000000000000000..d314a2f697308b0274dc7a2afba6e8bcc02701cf Binary files /dev/null and b/assets/models/Person.png differ diff --git a/assets/models/Person.sync.json b/assets/models/Person.sync.json new file mode 100644 index 0000000000000000000000000000000000000000..89261e87d297cef41b2e778c0abe059170882ce4 --- /dev/null +++ b/assets/models/Person.sync.json @@ -0,0 +1,12 @@ +{ + "name":"Person", + "init": { + "name": "PersonModel", + "primaryClass": "Person.Person", + "additionalClasses": [ + "Person.Female", + "Person.Male" + ], + "image": "Person.png" + } + } diff --git a/assets/models/Requirements.ecore b/assets/models/Requirements.ecore new file mode 100644 index 0000000000000000000000000000000000000000..17e6976840685f233b603a091c8b029b1960f054 --- /dev/null +++ b/assets/models/Requirements.ecore @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="requirement" nsURI="http://www.example.org/develop" nsPrefix="dev"> + <eClassifiers xsi:type="ecore:EClass" name="RequirementsSpecification"> + <eStructuralFeatures xsi:type="ecore:EReference" name="content" upperBound="-1" + eType="#//Requirement" containment="true" eOpposite="#//Requirement/container"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Requirement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="id" unique="false" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="author" unique="false" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="text" unique="false" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="container" lowerBound="1" + eType="#//RequirementsSpecification" eOpposite="#//RequirementsSpecification/content"/> + </eClassifiers> +</ecore:EPackage> diff --git a/assets/models/Requirements.png b/assets/models/Requirements.png new file mode 100644 index 0000000000000000000000000000000000000000..a1209c325f357267ab95f7c52ed178322f8181c3 Binary files /dev/null and b/assets/models/Requirements.png differ diff --git a/assets/models/SUMM.ecore b/assets/models/SUMM.ecore new file mode 100644 index 0000000000000000000000000000000000000000..e499ca3b6a09510e6b958ed7f84a6e4eab803829 --- /dev/null +++ b/assets/models/SUMM.ecore @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="summ" nsURI="http://www.example.org/develop" nsPrefix="dev"> + <eClassifiers xsi:type="ecore:EClass" name="Class"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="className" unique="false" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="associations" upperBound="-1" + eType="#//ClassUseClass" containment="true" eOpposite="#//ClassUseClass/class"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="usedBy" upperBound="-1" + eType="#//ClassUseClass" eOpposite="#//ClassUseClass/type"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="methods" upperBound="-1" + eType="#//Method" containment="true" eOpposite="#//Method/class"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ClassUseClass"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" unique="false" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="lowerBound" unique="false" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="upperBound" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="class" lowerBound="1" eType="#//Class" + eOpposite="#//Class/associations"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="type" lowerBound="1" eType="#//Class" + eOpposite="#//Class/usedBy"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Requirement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="id" unique="false" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="author" unique="false" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="text" unique="false" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="fullfilledBy" upperBound="-1" + eType="#//Method" eOpposite="#//Method/fulfills"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Method"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" unique="false" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="fulfills" upperBound="-1" + eType="#//Requirement" eOpposite="#//Requirement/fullfilledBy"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="class" lowerBound="1" eType="#//Class" + eOpposite="#//Class/methods"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="calling" upperBound="-1" + eType="#//Method" eOpposite="#//Method/calledBy"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="calledBy" upperBound="-1" + eType="#//Method" eOpposite="#//Method/calling"/> + </eClassifiers> +</ecore:EPackage> diff --git a/assets/models/SUMM.png b/assets/models/SUMM.png new file mode 100644 index 0000000000000000000000000000000000000000..fa373bdda84fb922581b4c5dbfa9cebc9ca81096 Binary files /dev/null and b/assets/models/SUMM.png differ diff --git a/assets/models/ShrinkingModel.ecore b/assets/models/ShrinkingModel.ecore new file mode 100644 index 0000000000000000000000000000000000000000..d44b9ff720cb84f014937ec94e9ccaa3fbfad0bd --- /dev/null +++ b/assets/models/ShrinkingModel.ecore @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="shrinking" nsURI="http://www.example.org/shrinking" nsPrefix="shr"> + <eClassifiers xsi:type="ecore:EClass" name="Classifier" abstract="true"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="StructuredClassifier" eSuperTypes="#//Classifier"> + <eStructuralFeatures xsi:type="ecore:EReference" name="part" upperBound="-1" eType="#//Property"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="ownedAttribute" upperBound="-1" + eType="#//Property" containment="true"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="EncapsulatedClassifier" abstract="true" + eSuperTypes="#//StructuredClassifier"/> + <eClassifiers xsi:type="ecore:EClass" name="Class" eSuperTypes="#//EncapsulatedClassifier #//BehavioredClassifier"> + <eStructuralFeatures xsi:type="ecore:EReference" name="superClass" eType="#//Class"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ConnectableElement" abstract="true"> + <eStructuralFeatures xsi:type="ecore:EReference" name="role" eType="#//StructuredClassifier"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="BehavioredClassifier" interface="true"/> + <eClassifiers xsi:type="ecore:EClass" name="Property" eSuperTypes="#//ConnectableElement"/> +</ecore:EPackage> diff --git a/assets/models/ShrinkingModel.sync.json b/assets/models/ShrinkingModel.sync.json new file mode 100644 index 0000000000000000000000000000000000000000..e6dcdcf38101f8ee3d5ce4ce3d346c5206a3ca04 --- /dev/null +++ b/assets/models/ShrinkingModel.sync.json @@ -0,0 +1 @@ +{"name":"ShrinkingModel","init":{"name":"Classifier","primaryClass":"ShrinkingExample.Classifier","additionalClasses":["ShrinkingExample.StructuredClassifier","ShrinkingExample.EncapsulatedClassifier","ShrinkingExample.Class"],"image":"Library.png","nested":[{"name":"ConnectableElement","primaryClass":"ShrinkingExample.ConnectableElement","additionalClasses":["ShrinkingExample.Property"]}]}} \ No newline at end of file diff --git a/assets/models/SimplePerson.ecore b/assets/models/SimplePerson.ecore new file mode 100644 index 0000000000000000000000000000000000000000..cb4f8dc86b28fe96760c3ee294a14c8efbd5591c --- /dev/null +++ b/assets/models/SimplePerson.ecore @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="SimplePerson" nsURI="http://www.example.org/ttc17" nsPrefix="ttc17"> + <eClassifiers xsi:type="ecore:EClass" name="SimplePerson"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="completeName" unique="false" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="address" unique="false" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="male" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"/> + </eClassifiers> +</ecore:EPackage> diff --git a/assets/models/SimplePerson.png b/assets/models/SimplePerson.png new file mode 100644 index 0000000000000000000000000000000000000000..c2c5139e37949c47f9dea1a042ecdb2659131de1 Binary files /dev/null and b/assets/models/SimplePerson.png differ diff --git a/assets/models/SimplePerson.sync.json b/assets/models/SimplePerson.sync.json new file mode 100644 index 0000000000000000000000000000000000000000..b6900ae53c4feeb6c35c8a27fa4f18993ec9dc19 --- /dev/null +++ b/assets/models/SimplePerson.sync.json @@ -0,0 +1 @@ +{"name":"SimplePerson","init":{"name":"SimplePersonModel","primaryClass":"SimplePerson.SimplePerson","image":"SimplePerson.png"}} \ No newline at end of file diff --git a/assets/models/TT.ecore b/assets/models/TT.ecore new file mode 100644 index 0000000000000000000000000000000000000000..14372089b3c2543ab0d6338499ab14d4cf9421dc --- /dev/null +++ b/assets/models/TT.ecore @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> + <ecore:EPackage name="TT" nsURI="https://www.transformation-tool-contest.eu/2019/tt" xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" + nsPrefix="tt"> + <eClassifiers xsi:type="ecore:EClass" name="LocatedElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="location" ordered="false" + unique="false" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="TruthTable" eSuperTypes="#/0/LocatedElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" ordered="false" + unique="false" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="ports" ordered="false" + lowerBound="1" upperBound="-1" eType="#/0/Port" containment="true" eOpposite="#/0/Port/owner"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="rows" ordered="false" + lowerBound="2" upperBound="-1" eType="#/0/Row" containment="true" eOpposite="#/0/Row/owner"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Port" abstract="true" eSuperTypes="#/0/LocatedElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" ordered="false" + unique="false" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="owner" ordered="false" + lowerBound="1" eType="#/0/TruthTable" eOpposite="#/0/TruthTable/ports"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="cells" ordered="false" + upperBound="-1" eType="#/0/Cell" eOpposite="#/0/Cell/port"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="InputPort" eSuperTypes="#/0/Port"/> + <eClassifiers xsi:type="ecore:EClass" name="OutputPort" eSuperTypes="#/0/Port"/> + <eClassifiers xsi:type="ecore:EClass" name="Row" eSuperTypes="#/0/LocatedElement"> + <eStructuralFeatures xsi:type="ecore:EReference" name="owner" ordered="false" + lowerBound="1" eType="#/0/TruthTable" eOpposite="#/0/TruthTable/rows"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="cells" ordered="false" + lowerBound="1" upperBound="-1" eType="#/0/Cell" containment="true" eOpposite="#/0/Cell/owner"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Cell" eSuperTypes="#/0/LocatedElement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" ordered="false" + unique="false" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="owner" ordered="false" + lowerBound="1" eType="#/0/Row" eOpposite="#/0/Row/cells"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="port" ordered="false" + lowerBound="1" eType="#/0/Port" eOpposite="#/0/Port/cells"/> + </eClassifiers> + </ecore:EPackage> diff --git a/assets/models/TTC 17.sync.json b/assets/models/TTC 17.sync.json new file mode 100644 index 0000000000000000000000000000000000000000..37cd3aa9ec431bfc1458019efa7652eee1dcb1b7 --- /dev/null +++ b/assets/models/TTC 17.sync.json @@ -0,0 +1 @@ +{"name":"TTC 17","init":{"name":"ModelB","primaryClass":"ttc17.Family","image":"family.png","nested":[{"name":"Model B - members","primaryClass":"ttc17.Member"}]},"integration":[{"name":"ModelA","primaryClass":"ttc17.Person","additionalClasses":["ttc17.Female","ttc17.Male"],"rule":"person.atl"},{"name":"ModelC","primaryClass":"ttc17.SimplePerson"}]} \ No newline at end of file diff --git a/assets/models/oldSUMM.ecore b/assets/models/oldSUMM.ecore new file mode 100644 index 0000000000000000000000000000000000000000..3a497027f4682eb2c58f1d672bfa598a92fcc1ba --- /dev/null +++ b/assets/models/oldSUMM.ecore @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="oldSUMM" nsURI="http://www.example.org/develop" nsPrefix="dev"> + <eClassifiers xsi:type="ecore:EClass" name="Method"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" unique="false" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="class" lowerBound="1" eType="#//ClassType" + eOpposite="#//ClassType/methods"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="calling" upperBound="-1" + eType="#//Method" eOpposite="#//Method/calledBy"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="calledBy" upperBound="-1" + eType="#//Method" eOpposite="#//Method/calling"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="fulfilled" upperBound="-1" + eType="#//Requirement" eOpposite="#//Requirement/fulfilledBy"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ClassType"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" unique="false" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="asg" eType="#//JavaASG" + eOpposite="#//JavaASG/classes"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="methods" upperBound="-1" + eType="#//Method" containment="true" eOpposite="#//Method/class"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="diagram" eType="#//ClassDiagram" + eOpposite="#//ClassDiagram/classes"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="associations" upperBound="-1" + eType="#//Association" containment="true" eOpposite="#//Association/class"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="usedBy" upperBound="-1" + eType="#//Association" eOpposite="#//Association/type"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="JavaASG"> + <eStructuralFeatures xsi:type="ecore:EReference" name="classes" upperBound="-1" + eType="#//ClassType" containment="true" eOpposite="#//ClassType/asg"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="integrator" eType="#//ProjectData" + eOpposite="#//ProjectData/containsJavaASG"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="RequirementsSpecification"> + <eStructuralFeatures xsi:type="ecore:EReference" name="content" upperBound="-1" + eType="#//Requirement" containment="true" eOpposite="#//Requirement/container"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="integrator" eType="#//ProjectData" + eOpposite="#//ProjectData/containsRequirements"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Requirement"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="id" unique="false" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="author" unique="false" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="text" unique="false" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="container" lowerBound="1" + eType="#//RequirementsSpecification" eOpposite="#//RequirementsSpecification/content"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="fulfilledBy" upperBound="-1" + eType="#//Method" eOpposite="#//Method/fulfilled"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ClassDiagram"> + <eStructuralFeatures xsi:type="ecore:EReference" name="classes" upperBound="-1" + eType="#//ClassType" containment="true" eOpposite="#//ClassType/diagram"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="integrator" eType="#//ProjectData" + eOpposite="#//ProjectData/containsClassDiagram"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="Association"> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" unique="false" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="lowerBound" unique="false" + eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/> + <eStructuralFeatures xsi:type="ecore:EAttribute" name="upperBound" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="class" lowerBound="1" eType="#//ClassType" + eOpposite="#//ClassType/associations"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="type" lowerBound="1" eType="#//ClassType" + eOpposite="#//ClassType/usedBy"/> + </eClassifiers> + <eClassifiers xsi:type="ecore:EClass" name="ProjectData"> + <eStructuralFeatures xsi:type="ecore:EReference" name="containsRequirements" upperBound="-1" + eType="#//RequirementsSpecification" containment="true" eOpposite="#//RequirementsSpecification/integrator"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="containsJavaASG" upperBound="-1" + eType="#//JavaASG" containment="true" eOpposite="#//JavaASG/integrator"/> + <eStructuralFeatures xsi:type="ecore:EReference" name="containsClassDiagram" upperBound="-1" + eType="#//ClassDiagram" containment="true" eOpposite="#//ClassDiagram/integrator"/> + </eClassifiers> +</ecore:EPackage> diff --git a/assets/models/oldSUMM.png b/assets/models/oldSUMM.png new file mode 100644 index 0000000000000000000000000000000000000000..75b79b7d7a6fa7a044d07e6ca53e26e7708d32e7 Binary files /dev/null and b/assets/models/oldSUMM.png differ diff --git a/assets/ttc17.modeljoin b/assets/ttc17.modeljoin new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/build.sbt b/build.sbt index 39aae81e9e9a67cb23e38f3459c7d59f7f2fe092..674c017ea6bfa76b4ab3825761a22ee43e7cb797 100644 --- a/build.sbt +++ b/build.sbt @@ -5,8 +5,14 @@ val emfecoreVersion = "2.12.0" val scrollVersion = "1.8" val scoptVersion = "3.7.0" val liftVersion = "3.3.0" +val gsonVersion = "2.8.5" -val syncProvider = RootProject(file("lib/ModelSyncProvider")) +val modelmanagementprovider = ProjectRef(uri("https://git-st.inf.tu-dresden.de/cwerner/role_model_management_provider.git#master"), "modelmanagementprovider") +val uiProvider = ProjectRef(uri("https://git-st.inf.tu-dresden.de/cwerner/role_ui_provider.git#master"), "uiprovider") +//val modeljoin = ProjectRef(uri("https://git-st.inf.tu-dresden.de/cwerner/model_join.git#master"), "model_join") + + +javacOptions ++= Seq("-encoding", "UTF-8") lazy val generator = (project in file(".")) .settings( @@ -20,7 +26,17 @@ lazy val generator = (project in file(".")) "org.eclipse.emf" % "org.eclipse.emf.common" % emfcommonVersion, "org.eclipse.emf" % "org.eclipse.emf.ecore" % emfecoreVersion, "com.github.scopt" %% "scopt" % scoptVersion, - "net.liftweb" %% "lift-json" % liftVersion + "net.liftweb" %% "lift-json" % liftVersion, + "com.google.code.gson" % "gson" % gsonVersion, + + //"org.antlr" % "antlr4-runtime" % "4.7.2", + + "org.junit.platform" % "junit-platform-runner" % "1.0.0" % "test", + "org.junit.jupiter" % "junit-jupiter-engine" % "5.0.0" % "test", + "org.junit.vintage" % "junit-vintage-engine" % "4.12.0" % "test", + "org.assertj" % "assertj-core" % "3.12.2" % "test", + + "net.aichler" % "jupiter-interface" % JupiterKeys.jupiterVersion.value % Test ), scalacOptions ++= Seq( "-language:implicitConversions" @@ -37,5 +53,9 @@ lazy val generator = (project in file(".")) case x => val oldStrategy = (assemblyMergeStrategy in assembly).value oldStrategy(x) - } - ).dependsOn(syncProvider) + }, + ).dependsOn( + //modeljoin, + modelmanagementprovider, + uiProvider + ) diff --git a/lib/ModelSyncProvider b/lib/ModelSyncProvider deleted file mode 160000 index 619bbf1efcfee406a134412275928322d9d28e05..0000000000000000000000000000000000000000 --- a/lib/ModelSyncProvider +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 619bbf1efcfee406a134412275928322d9d28e05 diff --git a/project/build.properties b/project/build.properties index 8db5ca22266ea113c2b39c92dddb73c83e61ffee..cabf73b45107a5feb964e2c564c9687faafffdbe 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version = 1.2.1 \ No newline at end of file +sbt.version = 1.2.7 diff --git a/project/plugins.sbt b/project/plugins.sbt index 45a6f02d1880ea4c9bff889a194ab87adf467611..4a65abadaf7e792155072db22cce49a4abbf4d54 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,2 +1,6 @@ + +resolvers += Resolver.jcenterRepo + +addSbtPlugin("net.aichler" % "sbt-jupiter-interface" % "0.8.2") addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "5.2.4") addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "1.0.0") diff --git a/src/main/doc b/src/main/doc index 89e2af4e060ae7c39c261fde55ba9140caf85853..ab624d1ae7196ac06fb3e9cef2f585552bee38e9 160000 --- a/src/main/doc +++ b/src/main/doc @@ -1 +1 @@ -Subproject commit 89e2af4e060ae7c39c261fde55ba9140caf85853 +Subproject commit ab624d1ae7196ac06fb3e9cef2f585552bee38e9 diff --git a/src/main/java/org/rosi_project/model_sync/modelrepresentation/JCreateJSONModels.java b/src/main/java/org/rosi_project/model_sync/modelrepresentation/JCreateJSONModels.java new file mode 100644 index 0000000000000000000000000000000000000000..c946e9442f0e60113cd69b12f5b1d7b09a249316 --- /dev/null +++ b/src/main/java/org/rosi_project/model_sync/modelrepresentation/JCreateJSONModels.java @@ -0,0 +1,144 @@ +package org.rosi_project.model_sync.modelrepresentation; + +import java.io.FileNotFoundException; +import java.io.PrintWriter; + +import com.google.gson.Gson; + +public class JCreateJSONModels { + + private static Gson gson = new Gson(); + + public static void main(String[] args) { + //Type t = gson.fromJson(bytesRead, Type.class); + JCreateJSONModels creation = new JCreateJSONModels(); + + //Create old TTC Model + JModelConfig ttc = creation.createOldTTCModel(); + creation.writeJModelConfigToFile(ttc); + + //Create Family Model + JModelConfig family = creation.createFamilyModel(); + creation.writeJModelConfigToFile(family); + + //Create Person Model + JModelConfig person = creation.createPersonModel(); + creation.writeJModelConfigToFile(person); + + //Create SimplePerson Model + JModelConfig simplePerson = creation.createSimplePersonModel(); + creation.writeJModelConfigToFile(simplePerson); + + //Create Library Model + JModelConfig library = creation.createLibraryModel(); + creation.writeJModelConfigToFile(library); + + //Create Shrinking Model + JModelConfig shrinking = creation.createShrinkingModel(); + creation.writeJModelConfigToFile(shrinking); + + } + + public void writeJModelConfigToFile (JModelConfig value) { + String s = gson.toJson(value); + //System.out.println(s); + try { + PrintWriter p = new PrintWriter("assets/models/" + value.getName() + ".sync.json"); + p.write(s); + p.flush(); + p.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + + public JModelConfig createShrinkingModel () { + JModelConfig conf = new JModelConfig("ShrinkingModel"); + + JModel classifier = new JModel("Classifier", "ShrinkingExample.Classifier"); + classifier.setImage("Library.png"); + classifier.addAdditionalClass("ShrinkingExample.StructuredClassifier"); + classifier.addAdditionalClass("ShrinkingExample.EncapsulatedClassifier"); + classifier.addAdditionalClass("ShrinkingExample.Class"); + + JModel element = new JModel("ConnectableElement", "ShrinkingExample.ConnectableElement"); + element.addAdditionalClass("ShrinkingExample.Property"); + classifier.addNested(element); + + conf.setInit(classifier); + return conf; + } + + public JModelConfig createLibraryModel () { + JModelConfig conf = new JModelConfig("Library"); + + JModel library = new JModel("Library", "LibraryExample.Library"); + library.setImage("Library.png"); + + JModel person = new JModel("Person", "LibraryExample.Person"); + person.addAdditionalClass("LibraryExample.Employee"); + library.addNested(person); + + conf.setInit(library); + return conf; + } + + public JModelConfig createOldTTCModel () { + JModelConfig conf = new JModelConfig("TTC 17"); + + JModel family = new JModel("ModelB", "ttc17.Family"); + family.setImage("family.png"); + JModel member = new JModel("Model B - members", "ttc17.Member"); + family.addNested(member); + + JModel person = new JModel("ModelA", "ttc17.Person"); + person.setRule("person.atl"); + person.addAdditionalClass("ttc17.Female"); + person.addAdditionalClass("ttc17.Male"); + + JModel simpleperson = new JModel("ModelC", "ttc17.SimplePerson"); + + conf.setInit(family); + conf.addIntegration(person); + conf.addIntegration(simpleperson); + return conf; + } + + public JModelConfig createFamilyModel () { + JModelConfig conf = new JModelConfig("Family"); + + JModel family = new JModel("FamilyModel", "Family.Family"); + family.setImage("Family.png"); + + //family.addAdditionalClass("Family.Member"); + JModel member = new JModel("MemberModel", "Family.Member"); + family.addNested(member); + + conf.setInit(family); + return conf; + } + + public JModelConfig createPersonModel () { + JModelConfig conf = new JModelConfig("Person"); + + JModel person = new JModel("PersonModel", "Person.Person"); + person.setImage("Person.png"); + person.addAdditionalClass("Person.Female"); + person.addAdditionalClass("Person.Male"); + + conf.setInit(person); + return conf; + } + + public JModelConfig createSimplePersonModel () { + JModelConfig conf = new JModelConfig("SimplePerson"); + + JModel simpleperson = new JModel("SimplePersonModel", "SimplePerson.SimplePerson"); + simpleperson.setImage("SimplePerson.png"); + + conf.setInit(simpleperson); + return conf; + } + + +} diff --git a/src/main/java/org/rosi_project/model_sync/modelrepresentation/JModel.java b/src/main/java/org/rosi_project/model_sync/modelrepresentation/JModel.java new file mode 100644 index 0000000000000000000000000000000000000000..878e3e83870454a8a1840b73cfbf2bf9ce63397c --- /dev/null +++ b/src/main/java/org/rosi_project/model_sync/modelrepresentation/JModel.java @@ -0,0 +1,69 @@ +package org.rosi_project.model_sync.modelrepresentation; + +import java.util.LinkedList; +import java.util.List; + +public class JModel { + + public JModel(String name, String primaryClass) { + this.name = name; + this.primaryClass = primaryClass; + } + + private String name; + private String primaryClass; + private List<String> additionalClasses; + private String image; + private List<JModel> nested; + private String rule; + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public String getPrimaryClass() { + return primaryClass; + } + public void setPrimaryClass(String primaryClass) { + this.primaryClass = primaryClass; + } + + public String getImage() { + return image; + } + public void setImage(String image) { + this.image = image; + } + + public List<String> getAdditionalClasses() { + return additionalClasses; + } + public boolean addAdditionalClass(String value) { + if (value == null) + return false; + if (additionalClasses == null) + this.additionalClasses = new LinkedList<String>(); + return additionalClasses.add(value); + } + + public List<JModel> getNested() { + return nested; + } + public boolean addNested(JModel value) { + if (value == null) + return false; + if (nested == null) + this.nested = new LinkedList<JModel>(); + return nested.add(value); + } + + public String getRule() { + return rule; + } + public void setRule(String rule) { + this.rule = rule; + } +} diff --git a/src/main/java/org/rosi_project/model_sync/modelrepresentation/JModelConfig.java b/src/main/java/org/rosi_project/model_sync/modelrepresentation/JModelConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..e65900a57a2f36d6f2553595c94950cf376089a9 --- /dev/null +++ b/src/main/java/org/rosi_project/model_sync/modelrepresentation/JModelConfig.java @@ -0,0 +1,41 @@ +package org.rosi_project.model_sync.modelrepresentation; + +import java.util.LinkedList; +import java.util.List; + +public class JModelConfig { + + public JModelConfig(String name) { + this.name = name; + } + + private String name; + private JModel init; + private List<JModel> integration; + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + + public JModel getInit() { + return init; + } + public void setInit(JModel init) { + this.init = init; + } + + public List<JModel> getIntegration() { + return integration; + } + public boolean addIntegration(JModel value) { + if (value == null) + return false; + if (integration == null) + this.integration = new LinkedList<JModel>(); + return integration.add(value); + } + +} diff --git a/src/main/java/org/rosi_project/model_sync/util/EMFUtilForGenerator.java b/src/main/java/org/rosi_project/model_sync/util/EMFUtilForGenerator.java new file mode 100644 index 0000000000000000000000000000000000000000..7038aa7e14f0a0fc5aac84e39765ebe4223415f4 --- /dev/null +++ b/src/main/java/org/rosi_project/model_sync/util/EMFUtilForGenerator.java @@ -0,0 +1,20 @@ +package org.rosi_project.model_sync.util; + +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.EcoreEList; + +public class EMFUtilForGenerator { + + static public List<EObject> getList(Object obj) { + List<EObject> newList = new LinkedList<EObject>(); + EcoreEList<EObject> list = (EcoreEList<EObject>) obj; + for (EObject l : list) { + newList.add(l); + } + return newList; + } + +} diff --git a/src/main/scala/org/rosi_project/model_sync/generator/CLIGenerator.scala b/src/main/scala/org/rosi_project/model_sync/generator/CLIGenerator.scala index 9f6af4d784e94a44459d35eb17e5c33159c54a02..fce0ed34bb6d2b532cfa870975a0cae31810c3d1 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/CLIGenerator.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/CLIGenerator.scala @@ -20,8 +20,8 @@ object CLIGenerator extends App { val parser = new OptionParser[GeneratorConfig](programName="modelgen") { head("modelgen", "0.1") - arg[jio.File]("ecore").required().action( (ef, conf) => - conf.copy(source = ef.getAbsolutePath) + arg[Seq[jio.File]]("ecore").required().action( (ef, conf) => + conf.copy(sources = ef.map(f => f.getAbsolutePath)) ).text("The ecore (XML) file of the model") opt[jio.File]('o', "outdir").optional().action( (dir, conf) => @@ -32,13 +32,17 @@ object CLIGenerator extends App { conf.copy(workDir = dir) ).text("The directory to place the generated .scala files in (temp dir by default)") - opt[jio.File]('m', "model").optional().action( (mj, conf) => - conf.copy(modelFile = mj.getAbsolutePath) - ).text("The description of the model's components (mapped to the name of the ecore with .sync.json extension by default)") - - opt[Unit]('c', "cleanup").optional().action( (_, conf) => - conf.copy(cleanUp = true) + opt[Boolean]('c', "cleanup").optional().action( (c, conf) => + conf.copy(cleanUp = c) ).text("Remove the generated .scala files and only keep the compiled .class files") + + opt[jio.File]('j', "modelJoin").optional().action( (m, conf) => + conf.copy(modelJoin = m.getAbsolutePath) + ).text("The description of a model join query to generate a view from.") + + opt[jio.File]('s', "syncLanguage").optional().action( (s, conf) => + conf.copy(syncLanguage = s.getAbsolutePath) + ).text("The description of a synchronisation query to generate a synchronization behaviour from.") } parser.parse(args, GeneratorConfig()) match { diff --git a/src/main/scala/org/rosi_project/model_sync/generator/Creation.scala b/src/main/scala/org/rosi_project/model_sync/generator/Creation.scala new file mode 100644 index 0000000000000000000000000000000000000000..c4813104f105308fdb226c38d8164855b4aaae96 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/Creation.scala @@ -0,0 +1,6 @@ +package org.rosi_project.model_sync.generator + +object Creation extends Enumeration { + val rolesum, rolesync, rolecomb = Value + //val rsum, rsync = Value +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/EcoreLoader.scala b/src/main/scala/org/rosi_project/model_sync/generator/EcoreLoader.scala index 350de718158c9b7cd5516c26ebca0695ac1a80e5..9824ab763b0c5e02f0e62bb6dd6a7abfecdfe3e3 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/EcoreLoader.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/EcoreLoader.scala @@ -4,34 +4,53 @@ import org.eclipse.emf.common.util.URI import org.eclipse.emf.ecore.resource.Resource import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl -import org.eclipse.emf.ecore.{EObject, EPackage} +import org.eclipse.emf.ecore.{ EObject, EPackage } +import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl +import scala.collection.JavaConverters._ +import java.io.File +import org.rosi_project.model_sync.generator.util.ClassAndInstance -/** Simple service to load an ECORE model from a file. - * - * @author Rico Bergmann - */ +/** + * Simple service to load an ECORE model from a file. + * + * @author Rico Bergmann + */ class EcoreLoader { - /** Fetches an ecore model from XML. - * - * @param path where to find the model - * @return the model described by the XML - */ - def loadEcore(path: String = "assets/ttc17.ecore"): EPackage = { - // see https://github.com/max-leuthaeuser/SCROLL/blob/dd269d5620257be1ea2f2044f398c090e9755fb3/core/src/main/scala/scroll/internal/ecore/ECoreImporter.scala + /** + * Fetches an ecore model from XML. + * + * @param path where to find the model + * @return the model described by the XML + */ + def loadEcore(path: String = "assets/ttc17.ecore"): ClassAndInstance = { require(null != path && path.nonEmpty) val resourceSet = new ResourceSetImpl() - val _ = resourceSet.getResourceFactoryRegistry.getExtensionToFactoryMap.put(Resource.Factory.Registry.DEFAULT_EXTENSION, new XMIResourceFactoryImpl()) + + resourceSet.getResourceFactoryRegistry.getExtensionToFactoryMap.put(Resource.Factory.Registry.DEFAULT_EXTENSION, new XMIResourceFactoryImpl()) + + //resourceSet.getResourceFactoryRegistry.getExtensionToFactoryMap.put("ecore", new EcoreResourceFactoryImpl()) + //resourceSet.getResourceFactoryRegistry.getExtensionToFactoryMap.put("xmi", new XMIResourceFactoryImpl()) val res = resourceSet.getResource(URI.createFileURI(path), true) require(null != res) require(!res.getContents.isEmpty) - res.getContents.toArray(new Array[EObject](0)).toList.find(_.isInstanceOf[EPackage]).map((p: EObject) => p.asInstanceOf[EPackage]).orNull + + val f = new File(path.replace(".ecore", ".ttmodel")) + if (f != null && f.exists()) { + val univEPackage = res.getContents().get(0); + resourceSet.getPackageRegistry().put("https://www.transformation-tool-contest.eu/2019/tt", univEPackage); + val myModel = resourceSet.getResource(URI.createURI(path.replace(".ecore", ".ttmodel")), true); + return new ClassAndInstance(res.getContents.toArray(new Array[EObject](0)).toList.find(_.isInstanceOf[EPackage]).map((p: EObject) => p.asInstanceOf[EPackage]).orNull, + myModel.getContents().toArray(new Array[EObject](0)).toList.head) + } + return new ClassAndInstance(res.getContents.toArray(new Array[EObject](0)).toList.find(_.isInstanceOf[EPackage]).map((p: EObject) => p.asInstanceOf[EPackage]).orNull, null) } } -/** Exception to indicate that the model images may not be copied into the JAR. - * - * @param cause the causing exception - */ +/** + * Exception to indicate that the model images may not be copied into the JAR. + * + * @param cause the causing exception + */ class EcoreLoadException(cause: Exception) extends RuntimeException(cause) diff --git a/src/main/scala/org/rosi_project/model_sync/generator/Generator.scala b/src/main/scala/org/rosi_project/model_sync/generator/Generator.scala index 69c91044992b22cb5d4733834f2136c4360e7409..e27f9fd70f612f009c9a7a37b35f564231a2d42a 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/Generator.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/Generator.scala @@ -1,72 +1,162 @@ package org.rosi_project.model_sync.generator -import net.liftweb.json._ import org.eclipse.emf.ecore._ import org.rosi_project.model_sync.generator.conversion.SModelGenerator -import org.rosi_project.model_sync.generator.env.{CompilationException, JarPackaginException} -import org.rosi_project.model_sync.generator.io.{ClassWritingException, ModelImagePreparationException, SModelFSWriter} +import org.rosi_project.model_sync.generator.env.{ CompilationException, JarPackaginException } +import org.rosi_project.model_sync.generator.io.{ ClassWritingException, ModelImagePreparationException, SModelFSWriter } -import scala.io.Source import scala.reflect.io.File +import org.rosi_project.model_sync.generator.acr_model.SModel +import org.rosi_project.model_sync.generator.acr_model.STypeRegistry +import org.rosi_project.model_sync.model_join.representation.parser.antlr.AntlrBackedModelJoinParser +import org.rosi_project.model_sync.generator.util.ClassAndInstance -/** The `Generator` runs the whole workflow of generating a JAR of compiled Scala source files - * based on an ECORE file of some sync model. - * - * @param config the configuration that tells the generator where to locate the necessary files. - * - * @author Rico Bergmann - */ +/** + * The `Generator` runs the whole workflow of generating a JAR of compiled Scala source files + * based on an ECORE file of some sync model. + * + * @param config the configuration that tells the generator where to locate the necessary files. + * + * @author Rico Bergmann + */ class Generator(config: GeneratorConfig) { /** - * Starts the generation. - */ + * Starts the generation. + */ def run(): Unit = { + //set package name of scala model files + if (config.create == Creation.rolesum) + PackageNames.sourcePkgPrefix = "sum." + if (config.create == Creation.rolesync) + PackageNames.sourcePkgPrefix = "sync." + if (config.create == Creation.rolecomb) + PackageNames.sourcePkgPrefix = "" + try { - val modelJson = Source.fromFile(config.getModelFile).getLines.mkString - implicit val jsonFormats: Formats = DefaultFormats - val modelCfg = parse(modelJson).extract[ModelConfig] + if (config.sources.isEmpty) { + println("Error: There must be any source file to generate something!!!") + return + } - var ecoreModel: EPackage = null + //read the ecore models + var ecoreModels: Map[String, ClassAndInstance] = Map.empty try { - ecoreModel = new EcoreLoader loadEcore config.source - } catch { + config.sources.foreach(s => { + ecoreModels = ecoreModels + (s -> (new EcoreLoader loadEcore s)) + }) + } catch { case e: Exception => throw new EcoreLoadException(e) } - val sModel = new SModelGenerator convert ecoreModel - new SModelSyncPreparationService prepareModel(sModel, modelCfg) + //create s models from the incoming ecore models + var sModels: Map[SModel, ClassAndInstance] = Map.empty + ecoreModels.foreach(ec => { + sModels = sModels + ((new SModelGenerator convert (ec._2.pkg, ec._1)) -> ec._2) + }) + + sModels.foreach(sm => { + /*general stuff, that should always be created */ + //create relational compartments (are only write out if not rolesync) + new SModelRelationalCompartmentPreparationService prepareModel (sm._1) + + //create the new classes for rsum and rsync + if (config.create == Creation.rolesync) { + //instance generation for rsync + if (sm._2.obj != null) { + new SModelSyncInstanceService prepareModel (sm._1, sm._2) + } + //add getter and setter for all methods + new SModelGetterSetterAllPreparationService prepareModel (sm._1) + //create the EMF Ecore reading models + new SModelSUMReadEMFService prepareModel (sm._1, config) + //add sync stuff + new SModelOnlySyncService prepareModel (sm._1) + //add ui provider stuff + new SModelSyncUiPreparationService prepareModel (sm._1, config.getModelConfigFromEcore(sm._1.getSourceName)) + } else { + //add basic setter and getter + new SModelGetterSetterAttrPreparationService prepareModel (sm._1) + if (config.create == Creation.rolecomb) { + //add sync stuff + new SModelOnlySyncService prepareModel (sm._1) + } + //create the EMF Ecore reading models + new SModelSUMReadEMFService prepareModel (sm._1, config) + //instance generation for combi means rsum + if (sm._2.obj != null) { + new SModelCombiInstanceService prepareModel (sm._1, sm._2) + } + if (config.create == Creation.rolecomb) { + //add ref methods + new SModelCombiRefMethodService prepareModel (sm._1) + } + //remove references + new SModelSUMRemoveRefService prepareModel (sm._1) + //create view and query stuff + new SModelSUMPreparationService prepareModel (sm._1) + } + + }) + // write the model and create the JAR println("... Writing model") + var finalModel: SModel = null + sModels.foreach(s => { + if (finalModel == null) { + finalModel = s._1 + } else { + finalModel.addOtherModel(s._1) + } + }) + + if (config.create != Creation.rolesync) { + //create join stuff + val modelJoinFile = config.getModelJoinFile + if (modelJoinFile != null && modelJoinFile.exists()) { + var modelJoin = new AntlrBackedModelJoinParser().readOrThrow(modelJoinFile); + println(modelJoin); + //val modelJoin = DefaultModelJoinParser.read(modelJoinFile).get + modelJoin.setName(config.getModelJoinName) + new SModelJoinPreparationService prepareModel (finalModel, modelJoin) + } + } + if (config.hasWorkDir) { - sModel.accept( + finalModel.accept( new SModelFSWriter( + config, outputDir = File(config.outDir).toDirectory, workingDir = File(config.workDir), keepClassFiles = !config.cleanUp, - modelCfg = modelCfg, - currentDir = config.getModelPath)) + modelCfgs = config.getAllModelConfigs, + currentDir = config.getModelPath(finalModel.getSourceName))) } else { - sModel.accept( + finalModel.accept( new SModelFSWriter( + config, outputDir = File(config.outDir).toDirectory, keepClassFiles = !config.cleanUp, - modelCfg = modelCfg, - currentDir = config.getModelPath)) + modelCfgs = config.getAllModelConfigs, + currentDir = config.getModelPath(finalModel.getSourceName))) } - - } - catch { + println("... Done") + } catch { case ele: EcoreLoadException => + throw ele println(s"** ERROR ** could not load ecore model: $ele") case mipe: ModelImagePreparationException => + throw mipe println(s"** ERROR ** could not prepare model images: $mipe") case cwe: ClassWritingException => + throw cwe println(s"** ERROR ** could not write classes: $cwe") case ce: CompilationException => + throw ce println(s"** ERROR ** could not compile classes: $ce") case jpe: JarPackaginException => + throw jpe println(s"** ERROR ** could not package JAR: $jpe") } } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/GeneratorConfig.scala b/src/main/scala/org/rosi_project/model_sync/generator/GeneratorConfig.scala index 2d1a971fc94cf9febb32cd153100518c26525d98..3a21bea23333ace6a4d033e7c7b4c7a291f02e92 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/GeneratorConfig.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/GeneratorConfig.scala @@ -1,17 +1,54 @@ package org.rosi_project.model_sync.generator import java.io.File +import scala.io.Source +import net.liftweb.json._ /** Wrapper for the different command line options for the [[Generator]] * * @author Rico Bergmann */ -case class GeneratorConfig(source: String = "", cleanUp: Boolean = false, outDir: File = new File(System.getProperty("user.dir")), workDir: File = null, modelFile: String = "") { - +case class GeneratorConfig(sources: Seq[String] = Seq(), + cleanUp: Boolean = false, + outDir: File = new File(System.getProperty("user.dir")), + workDir: File = null, + modelJoin: String = null, //can be more than one + syncLanguage: String = null, //can be more than one + create: Creation.Value = Creation.rolesync) { + def hasWorkDir: Boolean = workDir != null + + private def getEcoreNames: Seq[String] = sources.map(_.split("/").last.replace(".ecore", "")) + + def getCombinedEcoreName: String = getEcoreNames.mkString + + def getModelConfigFromEcore(source: String): ModelConfig = { + var modelCfgs: ModelConfig = null + var f = new File(source.replace(".ecore", ".sync.json")) + //println("---File: " + f.exists()) + if (f == null || !f.exists()) return null + val modelJson = Source.fromFile(f).getLines.mkString + implicit val jsonFormats: Formats = DefaultFormats + parse(modelJson).extract[ModelConfig] + } + + def getAllModelConfigs: Set[ModelConfig] = { + var configs: Set[ModelConfig] = Set.empty + sources.foreach(s => { + var modelCfg = getModelConfigFromEcore(s) + if (modelCfg != null) { + configs += modelCfg + } + }) + configs + } - def getModelFile: File = if (modelFile.isEmpty) new File(source.replace(".ecore", ".sync.json")) else new File(modelFile) - - def getModelPath: File = new File(source).getParentFile + def getModelPath(source: String): File = new File(source).getParentFile + + def getModelJoinFile: File = if(modelJoin == null) null else new File(modelJoin) + + def getModelJoinName: String = modelJoin.split("/").last.replace(".modeljoin", "").capitalize + + def getSnchronizationFile: File = if(syncLanguage == null) null else new File(syncLanguage) } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/ModelConfig.scala b/src/main/scala/org/rosi_project/model_sync/generator/ModelConfig.scala index abcd564426912f437e3bdb022225dcd0a16e372f..681ed98699eb040a9ee54995ed4e157c85fc167a 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/ModelConfig.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/ModelConfig.scala @@ -1,8 +1,5 @@ package org.rosi_project.model_sync.generator -import org.rosi_project.model_sync.provider.DisplayableModel -import org.rosi_project.model_sync.provider.ModelSyncProvider - /** Representation of a model configuration (i.e. a number of corresponding models). It tells the * generator how the model looks like, which types are needed, etc. * diff --git a/src/main/scala/org/rosi_project/model_sync/generator/PackageNames.scala b/src/main/scala/org/rosi_project/model_sync/generator/PackageNames.scala new file mode 100644 index 0000000000000000000000000000000000000000..60e87abbbfda997b4e850fba0f649a5c4985c1ef --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/PackageNames.scala @@ -0,0 +1,24 @@ +package org.rosi_project.model_sync.generator + +object PackageNames { + + val multiInhertitanceWithTraits = false + + var sourcePkgPrefix: String = "" //sync. , sum. + + val viewPkgName: String = "view" + val viewPostName: String = "View" + val viewRolePostName: String = "Role" + + val queryPkgName: String = "query" + val queryPostName: String = "Query" + val queryRolePostName: String = "Role" + val queryHelperPrefix: String = "Helper" + + val joinPkgName: String = "join" + + val examplePkgName: String = "example" + + val creationPkgName: String = "creation" + +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/SModelCombiInstanceService.scala b/src/main/scala/org/rosi_project/model_sync/generator/SModelCombiInstanceService.scala new file mode 100644 index 0000000000000000000000000000000000000000..348b2e34752a81d9d5115f95fc17c519ecc20ad6 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/SModelCombiInstanceService.scala @@ -0,0 +1,22 @@ +package org.rosi_project.model_sync.generator + +import org.rosi_project.model_sync.generator.acr_model.SModel +import org.rosi_project.model_sync.generator.util.ClassAndInstance +import org.rosi_project.model_sync.generator.sync.InstanceCombiGenerator + +/** Simple service to create instances. + * For the combination of sum and sync. + * + * @author Christopher Werner + */ +class SModelCombiInstanceService { + + /** Add a new class to the [[SModel]] to instantiate it. + * + * @param sModel the model to augment + */ + def prepareModel(sModel: SModel, clsAins: ClassAndInstance): Unit = { + val insgenerator = new InstanceCombiGenerator(clsAins) + sModel.accept(insgenerator) + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/SModelCombiRefMethodService.scala b/src/main/scala/org/rosi_project/model_sync/generator/SModelCombiRefMethodService.scala new file mode 100644 index 0000000000000000000000000000000000000000..e83e64902196fc30fbee8052a520ec9240f52819 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/SModelCombiRefMethodService.scala @@ -0,0 +1,23 @@ +package org.rosi_project.model_sync.generator + +import org.rosi_project.model_sync.generator.acr_model.SModel +import org.rosi_project.model_sync.generator.sync.ReferenceMethodCreationVisitor + +/** + * Add a method to get all references in the RSUM case. + * Sync functions necessary because we need compartment functions in the naturals. + * + * @author Christopher Werner + */ +class SModelCombiRefMethodService { + + /** + * Remove reference from model classes. + * + * @param sModel the model to augment + */ + def prepareModel(sModel: SModel): Unit = { + val refMethodVisitor = new ReferenceMethodCreationVisitor + sModel.accept(refMethodVisitor) + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/SModelGetterSetterAllPreparationService.scala b/src/main/scala/org/rosi_project/model_sync/generator/SModelGetterSetterAllPreparationService.scala new file mode 100644 index 0000000000000000000000000000000000000000..8978200b02c671162c24a2d813b21ae62ab2eb33 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/SModelGetterSetterAllPreparationService.scala @@ -0,0 +1,21 @@ +package org.rosi_project.model_sync.generator + +import org.rosi_project.model_sync.generator.acr_model.SModel +import org.rosi_project.model_sync.generator.sync.GetterSetterGeneratingVisitor + +/** Simple service that adds getter and setter for Attributes and References. + * + * @author Christopher Werner + */ +class SModelGetterSetterAllPreparationService { + + /** Adds getter and setter for Attributes and References. + * + * @param sModel the model to augment + */ + def prepareModel(sModel: SModel): Unit = { + val getterSetterVisitor = new GetterSetterGeneratingVisitor + sModel.accept(getterSetterVisitor) + } + +} diff --git a/src/main/scala/org/rosi_project/model_sync/generator/SModelGetterSetterAttrPreparationService.scala b/src/main/scala/org/rosi_project/model_sync/generator/SModelGetterSetterAttrPreparationService.scala new file mode 100644 index 0000000000000000000000000000000000000000..0826de0a411ce9cc99125f7f788d11a5764bf874 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/SModelGetterSetterAttrPreparationService.scala @@ -0,0 +1,16 @@ +package org.rosi_project.model_sync.generator + +import org.rosi_project.model_sync.generator.sync.BasicTypeGetterSetterGeneratingVisitor +import org.rosi_project.model_sync.generator.acr_model.SModel + +class SModelGetterSetterAttrPreparationService { + + /** Adds getter and setter for Attributes. + * + * @param sModel the model to augment + */ + def prepareModel(sModel: SModel): Unit = { + val getterSetterVisitor = new BasicTypeGetterSetterGeneratingVisitor + sModel.accept(getterSetterVisitor) + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/SModelJoinPreparationService.scala b/src/main/scala/org/rosi_project/model_sync/generator/SModelJoinPreparationService.scala new file mode 100644 index 0000000000000000000000000000000000000000..bef7cb7b7664f90a9990c21159f8c24ec4b70c1a --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/SModelJoinPreparationService.scala @@ -0,0 +1,26 @@ +package org.rosi_project.model_sync.generator + +import org.rosi_project.model_sync.model_join.representation.grammar.ModelJoinExpression +import org.rosi_project.model_sync.generator.acr_model.SModel +import org.rosi_project.model_sync.generator.sync.JoinGeneratingVisitor +import org.rosi_project.model_sync.generator.sync.ModelJoinViewGeneratingVisitor + +/** Simple service to create join classes and objects for ModelJoin. + * + * @author Christopher Werner + */ +class SModelJoinPreparationService { + + /** Augments a [[SModel]] with new JoinClasses and JoinObjects. + * + * @param sModel the model to augment + * modelJoin input + */ + def prepareModel(sModel: SModel, joinExpression: ModelJoinExpression): Unit = { + val joinVisitor = new JoinGeneratingVisitor(joinExpression) + val modelJoinVisitor = new ModelJoinViewGeneratingVisitor(joinExpression) + //order is important !!!! + sModel.accept(joinVisitor) + sModel.accept(modelJoinVisitor) + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/SModelOnlySyncService.scala b/src/main/scala/org/rosi_project/model_sync/generator/SModelOnlySyncService.scala new file mode 100644 index 0000000000000000000000000000000000000000..9963e8d0b122f566f5c7fe5a3e77f72ac674f249 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/SModelOnlySyncService.scala @@ -0,0 +1,21 @@ +package org.rosi_project.model_sync.generator + +import org.rosi_project.model_sync.generator.acr_model.SModel +import org.rosi_project.model_sync.generator.sync.SyncEnhancingVisitor + +/** Simple service to perform only extension and method statement add. + * + * @author Christopher Werner + */ +class SModelOnlySyncService { + + /** Augments a [[SModel]] with the necessary methods and statements to make it usable in a + * synchronization context. + * + * @param sModel the model to augment + */ + def prepareModel(sModel: SModel): Unit = { + val syncNotificationVisitor = new SyncEnhancingVisitor + sModel.accept(syncNotificationVisitor) + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/SModelRelationalCompartmentPreparationService.scala b/src/main/scala/org/rosi_project/model_sync/generator/SModelRelationalCompartmentPreparationService.scala new file mode 100644 index 0000000000000000000000000000000000000000..8efb2081eaf7c844d8c71024c0ff21c455f9056c --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/SModelRelationalCompartmentPreparationService.scala @@ -0,0 +1,20 @@ +package org.rosi_project.model_sync.generator + +import org.rosi_project.model_sync.generator.acr_model.SModel +import org.rosi_project.model_sync.generator.sync._ + +/** Simple service to create relational compartments for each relation. + * + * @author Christopher Werner + */ +class SModelRelationalCompartmentPreparationService { + + /** Create relational compartments for each relation. + * + * @param sModel the model to augment + */ + def prepareModel(sModel: SModel): Unit = { + val relationCompartmentVisitor = new RelationCompartmentGeneratingVisitor + sModel.accept(relationCompartmentVisitor) + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/SModelSUMPreparationService.scala b/src/main/scala/org/rosi_project/model_sync/generator/SModelSUMPreparationService.scala new file mode 100644 index 0000000000000000000000000000000000000000..9fb7454efa83d0739814bc265a87344a44c598e0 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/SModelSUMPreparationService.scala @@ -0,0 +1,26 @@ +package org.rosi_project.model_sync.generator + +import org.rosi_project.model_sync.generator.acr_model.SModel +import org.rosi_project.model_sync.generator.sync._ + +/** Add functionality for Queries and Views to the RSUM. + * + * @author Christopher Werner + */ +class SModelSUMPreparationService { + + /** Add functionality for Queries and Views to the RSUM. + * + * @param sModel the model to augment + */ + def prepareModel(sModel: SModel): Unit = { + val queryHelperVisitor = new GenerateQueryHelperVisitor + val viewGenerationVisitor = new ViewGeneratingVisitor + val queryGenerationVisitor = new QueryGeneratingVisitor + + //order is important !!!! + sModel.accept(viewGenerationVisitor) + sModel.accept(queryHelperVisitor) + sModel.accept(queryGenerationVisitor) + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/SModelSUMReadEMFService.scala b/src/main/scala/org/rosi_project/model_sync/generator/SModelSUMReadEMFService.scala new file mode 100644 index 0000000000000000000000000000000000000000..c23ffa0fc0094e3a3beccb31ec4ab0fd784bc6df --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/SModelSUMReadEMFService.scala @@ -0,0 +1,20 @@ +package org.rosi_project.model_sync.generator + +import org.rosi_project.model_sync.generator.sync.SumModelReadingVisitor +import org.rosi_project.model_sync.generator.acr_model.SModel + +/** Simple service to create the new emf ecore model instances. + * + * @author Christopher Werner + */ +class SModelSUMReadEMFService { + + /** Add classes to read emf and ecore models. + * + * @param sModel the model to augment + */ + def prepareModel(sModel: SModel, config: GeneratorConfig): Unit = { + val sumModelReadingVisitor = new SumModelReadingVisitor(config) + sModel.accept(sumModelReadingVisitor) + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/SModelSUMRemoveRefService.scala b/src/main/scala/org/rosi_project/model_sync/generator/SModelSUMRemoveRefService.scala new file mode 100644 index 0000000000000000000000000000000000000000..b389f9f65c9a28e0c9ba15e801c411fc448a29fd --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/SModelSUMRemoveRefService.scala @@ -0,0 +1,22 @@ +package org.rosi_project.model_sync.generator + +import org.rosi_project.model_sync.generator.acr_model.SModel +import org.rosi_project.model_sync.generator.sync.ReferenceRemoveVisitor + +/** Remove references from model classes. + * + * @author Christopher Werner + */ +class SModelSUMRemoveRefService { + + /** Remove reference from model classes. + * + * @param sModel the model to augment + */ + def prepareModel(sModel: SModel): Unit = { + val removeReferencesVisitor = new ReferenceRemoveVisitor + + //order is important !!!! + sModel.accept(removeReferencesVisitor) + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/SModelSyncInstanceService.scala b/src/main/scala/org/rosi_project/model_sync/generator/SModelSyncInstanceService.scala new file mode 100644 index 0000000000000000000000000000000000000000..7d7d7be4265f3c0451e55b8fbde053d8692a28b1 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/SModelSyncInstanceService.scala @@ -0,0 +1,21 @@ +package org.rosi_project.model_sync.generator + +import org.rosi_project.model_sync.generator.acr_model.SModel +import org.rosi_project.model_sync.generator.util.ClassAndInstance +import org.rosi_project.model_sync.generator.sync.InstanceGenerator + +/** Simple service to create instances. + * + * @author Christopher Werner + */ +class SModelSyncInstanceService { + + /** Add a new class to the [[SModel]] to instantiate it. + * + * @param sModel the model to augment + */ + def prepareModel(sModel: SModel, clsAins: ClassAndInstance): Unit = { + val insgenerator = new InstanceGenerator(clsAins) + sModel.accept(insgenerator) + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/SModelSyncPreparationService.scala b/src/main/scala/org/rosi_project/model_sync/generator/SModelSyncPreparationService.scala deleted file mode 100644 index 130f2527eae224b7fed30dcf4295e0b1ed7fa876..0000000000000000000000000000000000000000 --- a/src/main/scala/org/rosi_project/model_sync/generator/SModelSyncPreparationService.scala +++ /dev/null @@ -1,26 +0,0 @@ -package org.rosi_project.model_sync.generator - -import org.rosi_project.model_sync.generator.acr_model.SModel -import org.rosi_project.model_sync.generator.sync.{GetterSetterGeneratingVisitor, SyncEnhancingVisitor} - -/** Simple service to perform all the necessary adaptions of an [[SModel]] to make applicable for - * synchronization. - * - * @author Rico Bergmann - */ -class SModelSyncPreparationService { - - /** Augments a [[SModel]] with the necessary methods and statements to make it usable in a - * synchronization context. - * - * @param sModel the model to augment - */ - def prepareModel(sModel: SModel, modelCfg: ModelConfig): Unit = { - val getterSetterVisitor = new GetterSetterGeneratingVisitor - val syncNotificationVisitor = new SyncEnhancingVisitor(modelCfg) - - sModel.accept(getterSetterVisitor) - sModel.accept(syncNotificationVisitor) - } - -} diff --git a/src/main/scala/org/rosi_project/model_sync/generator/SModelSyncUiPreparationService.scala b/src/main/scala/org/rosi_project/model_sync/generator/SModelSyncUiPreparationService.scala new file mode 100644 index 0000000000000000000000000000000000000000..ec0615efb44ae122e3c9eb27d52edbe6947d6f2b --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/SModelSyncUiPreparationService.scala @@ -0,0 +1,24 @@ +package org.rosi_project.model_sync.generator + +import org.rosi_project.model_sync.generator.acr_model.SModel +import org.rosi_project.model_sync.generator.ui.SyncUiVisitor + +/** Simple service to add all the necessary adaption classes of an [[SModel]] to make applicable for + * synchronization user interface. + * + * @author Christopher Werner + */ +class SModelSyncUiPreparationService { + + /** Add UI provider functionality too a [[SModel]] with the necessary methods and statements to make it usable + * in the user interface. + * + * @param sModel the model to augment + */ + def prepareModel(sModel: SModel, modelCfg: ModelConfig): Unit = { + if (modelCfg != null) { + val syncUiVisitor = new SyncUiVisitor(modelCfg) + sModel.accept(syncUiVisitor) + } + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/ComplexSModel.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/ComplexSModel.scala new file mode 100644 index 0000000000000000000000000000000000000000..442b904cc1b67a5b1951d8db6bab0906f265e683 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/ComplexSModel.scala @@ -0,0 +1,133 @@ +package org.rosi_project.model_sync.generator.acr_model + +import org.rosi_project.model_sync.generator.support.Assert + +/** + * Complex implementation of the [[SModel]]. + * + * @author Christopher Werner + */ +class ComplexSModel(name: String, sourceName: String, nsUri: String) extends SModel(name, sourceName, nsUri) { + + private var modelClasses: Set[SClass] = Set.empty + private var providerClasses: Set[SClass] = Set.empty + private var relationalCompartments: Set[SClass] = Set.empty + private var viewCompartments: Set[SClass] = Set.empty + private var joinClasses: Set[SClass] = Set.empty + private var sEnums: Set[SEnum] = Set.empty + + /** Provides all model classes in `this` model. */ + override def getModelClasses: Set[SClass] = modelClasses + + /** Provides all provider classes in `this` model. */ + override def getProviderClasses: Set[SClass] = providerClasses + + /** Provides all relational compartments in `this` model. */ + override def getRelationalCompartments: Set[SClass] = relationalCompartments + + /** Provides all view compartments in `this` model. */ + override def getViewCompartments: Set[SClass] = viewCompartments + + /** Provides all the classes in `this` model. */ + override def getAllClasses: Set[SClass] = modelClasses ++ providerClasses ++ relationalCompartments ++ viewCompartments + + /** Provides all join classes in `this` model. */ + override def getJoinClasses: Set[SClass] = joinClasses + + /** Provides all model enums in `this` model. */ + override def getModelEnums: Set[SEnum] = sEnums + + /** + * Extends the model by a new provder class. + * + * @param mClass the class to add. May never `null`. + */ + override def addProviderClass(mClass: SClass): Unit = { + Assert.notNull(mClass, "Class may not be null") + providerClasses += mClass + } + + /** + * Extends the model by a new relational compartment. + * + * @param mClass the class to add. May never `null`. + */ + override def addRelationalCompartment(mClass: SClass): Unit = { + Assert.notNull(mClass, "Class may not be null") + relationalCompartments += mClass + } + + /** + * Extends the model by a new view compartment. + * + * @param mClass the class to add. May never `null`. + */ + override def addViewCompartment(mClass: SClass): Unit = { + Assert.notNull(mClass, "Class may not be null") + viewCompartments += mClass + } + + /** + * Extends the model by a new class. + * + * @param mClass the class to add. May never `null`. + */ + override def addModelClass(mClass: SClass): Unit = { + Assert.notNull(mClass, "Class may not be null") + modelClasses += mClass + } + + /** + * Extends the model by a new join class. + * + * @param mClass the class to add. May never `null`. + */ + override def addJoinClass(mClass: SClass): Unit = { + Assert.notNull(mClass, "Class may not be null") + joinClasses += mClass + } + + /** + * Extends the model by a new enum. + * + * @param mEnum the enum to add. May never `null`. + */ + override def addModelEnums(mEnum: SEnum): Unit = { + Assert.notNull(mEnum, "Enum may not be null") + sEnums += mEnum + } + + override def accept(visitor: SModelVisitor): Unit = { + getAllClasses.foreach(_.accept(visitor)) + visitor.visit(this) + } + + def canEqual(other: Any): Boolean = other.isInstanceOf[SimpleSModel] + + override def equals(other: Any): Boolean = other match { + case that: ComplexSModel => + (that canEqual this) && + modelClasses == that.modelClasses && + providerClasses == that.providerClasses && + relationalCompartments == that.relationalCompartments && + viewCompartments == that.viewCompartments && + joinClasses == that.joinClasses && + sEnums == that.sEnums + case _ => false + } + + override def addOtherModel(model: SModel): SModel = { + modelClasses = modelClasses ++ model.getModelClasses + providerClasses = providerClasses ++ model.getProviderClasses + relationalCompartments = relationalCompartments ++ model.getRelationalCompartments + viewCompartments = viewCompartments ++ model.getViewCompartments + joinClasses = joinClasses ++ model.getJoinClasses + sEnums = sEnums ++ model.getModelEnums + return this + } + + override def hashCode(): Int = { + val state = Seq(getAllClasses) + state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b) + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/GenericSType.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/GenericSType.scala index 0a1cb48ef2b5a2fbbf3b46639e6ffc2a0e6f81ab..e43dda49bd7ebf717667f51d26cc4fb28e3b7f2b 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/GenericSType.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/GenericSType.scala @@ -11,6 +11,8 @@ package org.rosi_project.model_sync.generator.acr_model class GenericSType(name: String, sPackage: String = "", val typeParam: STypedElement) extends SType(name, sPackage) { override def getName: String = s"$name[${typeParam.getName}]" + + override def getDeepName: String = s"$name[${typeParam.getDeepName}]" override def getNecessaryImports: Set[SImport] = if (typeParam.getPackage.isEmpty || typeParam.getPackage == sPackage) typeParam.getNecessaryImports + SImport(typeParam.getPackage, typeParam.getName) else typeParam.getNecessaryImports @@ -20,6 +22,6 @@ class GenericSType(name: String, sPackage: String = "", val typeParam: STypedEle */ object GenericSType { - def unapply(arg: GenericSType): Option[(String, String, STypedElement)] = Some((arg.name, arg.sPackage, arg.typeParam)) + def unapply(arg: GenericSType): Option[(String, String, STypedElement)] = Some((arg.getName, arg.sPackage, arg.typeParam)) } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/MethodVisibility.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/MethodVisibility.scala new file mode 100644 index 0000000000000000000000000000000000000000..f06d8cfb99145309fe34fe68aaf5213176e9aaaa --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/MethodVisibility.scala @@ -0,0 +1,5 @@ +package org.rosi_project.model_sync.generator.acr_model + +object MethodVisibility extends Enumeration { + val privateVis, protectedVis, publicVis, privateExternalClass = Value +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SAttribute.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SAttribute.scala index 72c7beaace32d66527a258b06268b1361bdb40dc..fb622e47c81e358fcc8f993fc97876542941c262 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SAttribute.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SAttribute.scala @@ -6,16 +6,10 @@ package org.rosi_project.model_sync.generator.acr_model * * @author Rico Bergmann */ -case class SAttribute(name: String, attrType: STypedElement) extends SModelElement { - - /** Provides the type of `this` attribute as a `String`. - * - * @return the type. Will never be `null` nor empty. - */ - def getType: String = attrType.getName +case class SAttribute(_name: String, _type: STypedElement, val unique: Boolean = false) extends SStructuralFeature(_name, _type) { override def accept(visitor: SModelVisitor): Unit = visitor.visit(this) - override def toString: String = s"$name: $getType" + override def toString: String = s"$getName: ${getTypeElement.getName} $unique" } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SClass.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SClass.scala index fe3882754e85ae49eef024d526df59bf15d71a73..8344eb7a214fe5c6e49f0bea675984bc107fb921 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SClass.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SClass.scala @@ -1,44 +1,101 @@ package org.rosi_project.model_sync.generator.acr_model import java.util.Objects +import org.rosi_project.model_sync.generator.acr_model.types.SSeq +import org.rosi_project.model_sync.generator.acr_model.types.GenericSequence +import org.rosi_project.model_sync.generator.acr_model.types.PredefTypes +import org.rosi_project.model_sync.generator.sync.ToStringMethods + +/** + * Representation of Scala classes. Attributes, methods, etc. have their own wrappers which should + * be used to modify these individual parts of the class. + * + * @see [[SType]] + * @author Rico Bergmann + */ +class SClass(_name: String, + _sPackage: String = "", + _sClassType: SClassType.Value = SClassType.normalClass) extends STypedElement(_name, _sPackage, _sClassType) { + + protected var parentClass: STypedElement = null + protected var parentInterfaces: Seq[STypedElement] = Seq.empty + protected var internalClasses: Seq[SInnerClass] = Seq.empty + + protected var attributes: Seq[SAttribute] = Seq.empty + protected var references: Seq[SReference] = Seq.empty + + protected var methods: Seq[SMethod] = Seq.empty + protected var constructorStatements: Seq[SMethodStatement] = Seq.empty -/** Representation of Scala classes. Attributes, methods, etc. have their own wrappers which should - * be used to modify these individual parts of the class. - * - * @see [[SType]] - * @author Rico Bergmann - */ -class SClass(val name: String, - val sPackage: String = "", - var attributes: Seq[SAttribute] = Seq.empty, - var parent: STypedElement = null, - protected var methods: Seq[SMethod] = Seq.empty) - extends STypedElement { + def getClassParent: STypedElement = parentClass - protected var constructorStatements: Seq[SMethodStatement] = Seq.empty + def getInterfaceParents: Seq[STypedElement] = parentInterfaces - /** Provides code that should be executed when invoking the constructor. - */ - def getAdditionalConstructorStatements: Seq[SMethodStatement] = constructorStatements + def getStructuralFeatures: Seq[SStructuralFeature] = attributes ++ references - /** Checks, whether `this` is part of the default package - */ - def isDefaultPackage: Boolean = sPackage == "" + def getInternalClasses: Seq[SInnerClass] = internalClasses - /** Checks, whether `this` extends any other classes. If this is the case, it is '''not''' - * considered a ''root class'', otherwise it is. - */ - def isRootClass: Boolean = parent == null + def getDeepStructuralFeatures: Seq[SStructuralFeature] = { + val cls = getClassParent + if (cls == null) { + attributes ++ references + } else { + cls match { + case parentAsSClass: SClass => + attributes ++ references ++ parentAsSClass.getDeepStructuralFeatures + case _ => + attributes ++ references + } + } + } - /** Provides the set of all symbols that have to be imported in order to use `this` complete - * class. - */ - def collectImports: Set[String] = getNecessaryImports.map(imp => s"${imp.pckg}.${imp.name}") + def getOnlyDeepAttributes: Seq[SAttribute] = { + val cls = getClassParent + if (cls == null) { + attributes + } else { + cls match { + case parentAsSClass: SClass => + attributes ++ parentAsSClass.getOnlyDeepAttributes + case _ => + attributes + } + } + } + + def getOnlyDeepReferences: Seq[SReference] = { + val cls = getClassParent + if (cls == null) { + references + } else { + cls match { + case parentAsSClass: SClass => + references ++ parentAsSClass.getOnlyDeepReferences + case _ => + references + } + } + } + + override def proofHierarchicalEquality(sType: STypedElement): Boolean = { + if (sType == this) { + return true + } else { + this.getAllParents().foreach(p => { + if (p.proofHierarchicalEquality(sType)) { + return true + } + }) + return false + } + + } - /** Augments `this` class with another method. - * - * @param m the additional method. May not be `null` - */ + /** + * Augments `this` class with another method. + * + * @param m the additional method. May not be `null` + */ def addMethod(m: SMethod): Unit = { Objects.requireNonNull(m, "Method to add may not be null") if (methods.contains(m)) { @@ -47,48 +104,96 @@ class SClass(val name: String, methods = methods :+ m } + /** + * Gets the methods of `this` class. + * And adds a to String if not exists. + */ def getMethods: Seq[SMethod] = { - if (methods.exists(_.name == "toString")) { + if (methods.exists(_.getName == "toString")) { methods } else { - methods :+ new SMethod( - name = "toString", - result = SType.String, - params = Seq.empty, - implementation = Seq(SMethodStatement((List(s""" "$name: " """) ++ attributes.map(attr => s""" "${attr.name}=" + ${attr.name} + " " """)).mkString(" + "))), - overrides = true - ) + methods :+ ToStringMethods.normalToStringMethod(this) } } - /** Augments the constructor by another statement. The statement will be executed lastly (though - * this may change due to further modifications of the constructor). - * - * @param statement the new statement. May not be `null` - */ - def augmentConstructor(statement: SMethodStatement): Unit = { - Objects.requireNonNull(statement, "Statement to add may not be null") - constructorStatements = constructorStatements :+ statement + /** Gets the parents of `this` class. */ + def getAllParents(): Seq[STypedElement] = { + if (parentInterfaces.isEmpty && parentClass == null) { + return Seq.empty + } + if (parentInterfaces.isEmpty) { + return Seq(parentClass) + } + if (parentClass == null) { + return parentInterfaces + } + parentInterfaces :+ parentClass + } + + /** + * Adds a internal class to `this` class. + * + * If `parent == this or null` nothing will happen. + */ + def addInternalClass(internal: SInnerClass): Unit = { + if (internal == null || internal == this) { + return + } + if (internalClasses.contains(internal)) { + return + } + internalClasses = internalClasses :+ internal } - /** Makes `this` class a subclass of `parent`. - * - * If `parent == this` nothing will happen. - * - * @param parent the superclass. May be `null` to indicate that there is no superclass (other - * than `AnyRef`) - */ - def setParent(parent: STypedElement): Unit = { - if (parent == this) { + /** + * Makes `this` class a subclass of `parent`. + * + * If `parent == this` nothing will happen. + * + * @param parent the superclass. May be `null` to indicate that there is no superclass (other + * than `AnyRef`) + */ + def addParent(parent: STypedElement): Unit = { + if (parent == null || parent == this || parentClass == parent || parentInterfaces.contains(parent)) { return } - this.parent = parent + if (parent.isInterface) { + parentInterfaces = parentInterfaces :+ parent + } else { + if (parentClass == null) { + parentClass = parent + } else { + //print error message here + println("!!!Cannot add parent because their is one parent that is no interface!!!") + } + } + + } + + /** Gets the references of `this` class. */ + def getReferences(): Seq[SReference] = references + + /** + * Sets the references of `this` class. + * + * @param refs the references. May be `null` to remove all current references. + */ + def setReferences(refs: Seq[SReference]): Unit = { + if (refs == null) { + this.references = Seq.empty + } else { + this.references = refs + } } - /** Sets the attributes of `this` class. - * - * @param attrs the attributes. May be `null` to remove all current attributes. - */ + /** Gets the attributes of `this` class. */ + def getAttributes(): Seq[SAttribute] = attributes + + /** + * Sets the attributes of `this` class. + * + * @param attrs the attributes. May be `null` to remove all current attributes. + */ def setAttributes(attrs: Seq[SAttribute]): Unit = { if (attrs == null) { this.attributes = Seq.empty @@ -97,123 +202,204 @@ class SClass(val name: String, } } - /** Provides all types `this` classes accesses in some way. - */ - def getUsedTypes: Set[STypedElement] = { - val parentImport: Seq[STypedElement] = if (isRootClass) List() else List(parent) + /** Provides code that should be executed when invoking the constructor. */ + def getAdditionalConstructorStatements: Seq[SMethodStatement] = constructorStatements - val parentConstructorParamImports: Seq[STypedElement] = if (isRootClass) List() else parent match { - case parent: SClass => parent.attributes.map(_.attrType) + /** + * Checks, whether `this` extends any other classes. If this is the case, it is '''not''' + * considered a ''root class'', otherwise it is. + * Interfaces are not checked. + */ + def isRootClass: Boolean = parentClass == null + + def isAbsoluteRootClassOrInterface: Boolean = parentClass == null && parentInterfaces.isEmpty + + def getRootClassWithNameAndPackage(n: String, p: String): SClass = { + var parent = this + while (!parent.isRootClass) { + if (parent.getClassParent.isInstanceOf[SClass]) { + parent = parent.getClassParent.asInstanceOf[SClass] + if (parent.getName == n && parent.getPackage == p) { + return parent + } + } + } + return null + } + + /** + * Provides the set of all symbols that have to be imported in order to use `this` complete + * class. + */ + def collectImports: Set[String] = getNecessaryImports.map(imp => s"${imp.pckg}.${imp.name}") + + /** + * Augments the constructor by another statement. The statement will be executed lastly (though + * this may change due to further modifications of the constructor). + * + * @param statement the new statement. May not be `null` + */ + def augmentConstructor(statement: SMethodStatement): Unit = { + Objects.requireNonNull(statement, "Statement to add may not be null") + constructorStatements = constructorStatements :+ statement + } + + override def getAllConstructorParameters: Seq[SMethodParameter] = { + val ownParams = getStructuralFeatures.map(attr => SMethodParameter(attr.getName, attr.getTypeElement)) + val parentParams = if (isRootClass) List() else getClassParent.getAllConstructorParameters + ownParams ++ parentParams + } + + override def getAttributeConstructorParameters: Seq[SMethodParameter] = { + val ownParams = getAttributes.map(attr => SMethodParameter(attr.getName, attr.getTypeElement)) + val parentParams = if (isRootClass) List() else getClassParent.getAttributeConstructorParameters + ownParams ++ parentParams + } + + override def getInheritanceHierarchy: Seq[STypedElement] = if (isRootClass) List(this) else this +: getClassParent.getInheritanceHierarchy + + /** Provides all types `this` classes accesses in some way. */ + def getUsedTypes: Set[STypedElement] = { + //iterate over construction features of parent types + val parentConstructorParamImports: Seq[STypedElement] = if (isRootClass) List() else getClassParent match { + case parent: SClass => + parent.getDeepStructuralFeatures.map(_.getTypeElement) case _ => List() } - val attrTypeImports: Seq[STypedElement] = attributes.map(_.attrType) + //attribute types + val attrTypeImports: Seq[STypedElement] = attributes.map(_.getTypeElement) + //reference types + val refTypeImports: Seq[STypedElement] = references.map(_.getTypeElement) + + //method types val methodResultImports: Seq[STypedElement] = methods.map(_.result) - val methodParamImports: Seq[STypedElement] = methods.flatMap(_.params).map(_.paramType) + val methodParamImports: Seq[STypedElement] = methods.flatMap(_.params).map(_.getType) val methodImplImports: Seq[STypedElement] = methods.flatMap(_.getUsedTypes.toList) - // create a set to eliminate duplicates - (parentImport + val allImports: Seq[STypedElement] = (getAllParents ++ parentConstructorParamImports ++ attrTypeImports + ++ refTypeImports ++ methodResultImports ++ methodParamImports - ++ methodImplImports).toSet - } + ++ methodImplImports) - override def getName: String = name + var allCleanImports: Seq[STypedElement] = Seq.empty - override def getPackage: String = sPackage + allImports.foreach(i => { + i match { + case seq: GenericSequence => + allCleanImports = allCleanImports :+ seq.typeParam + case t: STypedElement => + allCleanImports = allCleanImports :+ t + //case _ => + } + }) - override def getConstructorParameters: Seq[SMethodParameter] = { - val ownParams = attributes.map(attr => SMethodParameter(attr.name, attr.attrType)) - val parentParams = if (isRootClass) List() else parent.getConstructorParameters - ownParams ++ parentParams + // create a set to eliminate duplicates + allCleanImports.toSet } - override def getInheritanceHierarchy: Seq[STypedElement] = if (isRootClass) List(this) else this +: parent.getInheritanceHierarchy - override def getNecessaryImports: Set[SImport] = { - val parentImport: List[SImport] = if (isRootClass) List() else includeImportIfNecessary(parent.getPackage, parent.getName) - - val parentConstructorParamImports: List[SImport] = if (isRootClass) List() else parent match { - case parent: SClass => - parent.attributes - .map(attr => includeImportIfNecessary(attr.attrType.getPackage, attr.attrType.getName)) - .fold(List())((l1, l2) => l1 ++ l2) - case _ => List() + var allImports: List[SImport] = List.empty + //iterate over all parent types + getAllParents().foreach(p => { + allImports = includeImportIfNecessary(p, allImports) + }) + + //iterate over construction features of parent types + if (!isRootClass) { + getClassParent match { + case parent: SClass => + parent.getDeepStructuralFeatures.foreach(p => { + allImports = includeImportIfNecessary(p.getTypeElement, allImports) + }) + case _ => + } } - val attrTypeImports: List[SImport] = - attributes - .map(attr => includeImportIfNecessary(attr.attrType.getPackage, attr.getType)) - .fold(List())((l1, l2) => l1 ++ l2) - - val methodResultImports: List[SImport] = - methods - .map(_.result) - .map(res => includeImportIfNecessary(res.getPackage, res.getName)) - .fold(List())((l1, l2) => l1 ++ l2) - - val methodParamImports: List[SImport] = - methods - .map(_.params) - .fold(List())((l1, l2) => l1 ++ l2) - .map(param => includeImportIfNecessary(param.paramType.getPackage, param.paramType.getName)) - .fold(List())((l1, l2) => l1 ++ l2) - - val methodImplImports: List[SImport] = - methods - .map(_.getUsedTypes.toList) - .fold(List())((l1, l2) => l1 ++ l2) - .map(typ => includeImportIfNecessary(typ.getPackage, typ.getName)) - .fold(List())((l1, l2) => l1 ++ l2) + //iterate over all attributes + attributes.foreach(a => { + allImports = includeImportIfNecessary(a.getTypeElement, allImports) + }) + + //iterate over all references + references.foreach(r => { + allImports = includeImportIfNecessary(r.getTypeElement, allImports) + }) + + //iterated over all methods + methods.foreach(m => { + //iterate over result types + allImports = includeImportIfNecessary(m.result, allImports) + //iterate over parameter types + m.params.foreach(p => { + allImports = includeImportIfNecessary(p.getType, allImports) + }) + //iterate over used types in the method + m.getUsedTypes.foreach(t => { + allImports = includeImportIfNecessary(t, allImports) + }) + }) + + //iterate over all construction statements + constructorStatements.foreach(s => { + s.usedTypes.foreach(t => { + allImports = includeImportIfNecessary(t, allImports) + }) + }) // create a set to eliminate duplicates - (parentImport - ++ parentConstructorParamImports - ++ attrTypeImports - ++ methodResultImports - ++ methodParamImports - ++ methodImplImports).toSet + (allImports).toSet } override def accept(visitor: SModelVisitor): Unit = { attributes.foreach(_.accept(visitor)) + references.foreach(_.accept(visitor)) methods.foreach(_.accept(visitor)) visitor.visit(this) } protected def canEqual(other: Any): Boolean = other.isInstanceOf[SClass] - /** Checks if some class has to be imported in order to be usable from `this` class. If this - * is the case it will wrap the necessary import in a `List` for further usage. - * - * @param sPackage the package of the class - * @param sClass the class - * @return an empty list if the class does not need to be imported, or the necessary import - * otherwise - */ - private def includeImportIfNecessary(sPackage: String, sClass: String): List[SImport] = { - if (sPackage != this.sPackage && sPackage != "") List(SImport(sPackage, sClass)) else List() + /** + * Checks if some class has to be imported in order to be usable from `this` class. If this + * is the case it will wrap the necessary import in a `List` for further usage. + * + * @param sPackage the package of the class + * @param sClass the class + * @return an empty list if the class does not need to be imported, or the necessary import + * otherwise + */ + private def includeImportIfNecessary(sTypeElement: STypedElement, list: List[SImport]): List[SImport] = { + //catch GenericSequence types and there use internal type param + var t = sTypeElement + sTypeElement match { + case seq: GenericSequence => + t = seq.typeParam + case _ => + } + //return only if new package + if (t.sPackage != this.sPackage && t.sPackage != "") list :+ SImport(t.sPackage, t.getName) else list } override def equals(other: Any): Boolean = other match { case that: SClass => (that canEqual this) && - name == that.name && + getName == that.getName && sPackage == that.sPackage case _ => false } override def hashCode(): Int = { - val state = Seq(name, sPackage) + val state = Seq(getName, sPackage) state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b) } - override def toString: String = s"$name(${attributes.map(_.name).mkString(", ")})" + override def toString: String = s"SC: $getName($sPackage, ${attributes.map(_.getName).mkString(", ")} ## ${getOnlyDeepAttributes.map(_.getName).mkString(", ")} || $isAbstract, $isInterface)" } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SClassType.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SClassType.scala new file mode 100644 index 0000000000000000000000000000000000000000..50ad1d74a477abf4cd9106759470ce269141301a --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SClassType.scala @@ -0,0 +1,5 @@ +package org.rosi_project.model_sync.generator.acr_model + +object SClassType extends Enumeration { + val normalClass, caseClass, abstactClass, normalTrait, normalObject = Value +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SEnum.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SEnum.scala new file mode 100644 index 0000000000000000000000000000000000000000..a0f6271b6a30005d3e23ee878d1120bf79891e7b --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SEnum.scala @@ -0,0 +1,10 @@ +package org.rosi_project.model_sync.generator.acr_model + +class SEnum (_name: String, _sPackage: String, val enums: Set[String]) extends STypedElement(_name, _sPackage, SClassType.normalClass) { + + override def getDeepName: String = _name + ".Value" + + override def accept(visitor: SModelVisitor): Unit = { + //pass never change an incoming enum + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SGetter.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SGetter.scala index 3cb1dce28b2cca0c736031693bc0c10a392f6988..4adcadcceffcb876d0296d889f42e2ae78e9f009 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SGetter.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SGetter.scala @@ -7,10 +7,10 @@ import org.rosi_project.model_sync.generator.support.ExtendedString.stringToExte * * @author Rico Bergmann */ -class SGetter(attr: SAttribute) extends SMethod( - name = s"get${attr.name.firstLetterToUpperCase}", - result = attr.attrType, +class SGetter(struc: SStructuralFeature) extends SMethod( + name = s"get${struc.getName.firstLetterToUpperCase}", + result = struc.getTypeElement, params = Seq.empty, - implementation = Seq(SMethodStatement(content = attr.name, usedTypes = Set(attr.attrType)))) { + implementation = Seq(SMethodStatement(content = struc.getName, usedTypes = Set(struc.getTypeElement)))) { } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SInnerClass.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SInnerClass.scala new file mode 100644 index 0000000000000000000000000000000000000000..a9433f70e8a196db8ea96f576aac2dcf3e2eebe0 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SInnerClass.scala @@ -0,0 +1,13 @@ +package org.rosi_project.model_sync.generator.acr_model + +import java.util.Objects + +class SInnerClass(_name: String, + _sPackage: String = "", + _sClassType: SClassType.Value = SClassType.normalClass, + val externalClass: SClass) extends SClass(_name, _sPackage, _sClassType) { + + Objects.requireNonNull(externalClass, "External class may not be null") + + override def getDeepName: String = externalClass.getName + "#" + _name +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SInnerViewNaturalClass.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SInnerViewNaturalClass.scala new file mode 100644 index 0000000000000000000000000000000000000000..38fe319e6469452bec98b0b22d6773f8062eadbc --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SInnerViewNaturalClass.scala @@ -0,0 +1,13 @@ +package org.rosi_project.model_sync.generator.acr_model + +import java.util.Objects + +class SInnerViewNaturalClass(_name: String, + _sPackage: String = "", + _sClassType: SClassType.Value = SClassType.normalClass, + _externalClass: SClass, + val sumSource: SClass) extends SInnerClass(_name, _sPackage, _sClassType, _externalClass) { + + Objects.requireNonNull(sumSource, "SUM Source class may not be null") + +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SInnerViewRelationalClass.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SInnerViewRelationalClass.scala new file mode 100644 index 0000000000000000000000000000000000000000..97feb240a538d46c4b06bc042838070aee814b1d --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SInnerViewRelationalClass.scala @@ -0,0 +1,16 @@ +package org.rosi_project.model_sync.generator.acr_model + +import java.util.Objects + +class SInnerViewRelationalClass(_name: String, + _sPackage: String = "", + _sClassType: SClassType.Value = SClassType.normalClass, + _externalClass: SClass, + val sumSource: SRelationalCompartmentClass, + val viewSource: SInnerViewNaturalClass, + val viewTarget: SInnerViewNaturalClass) extends SInnerClass(_name, _sPackage, _sClassType, _externalClass) { + + Objects.requireNonNull(sumSource, "SUM Source class may not be null") + Objects.requireNonNull(viewSource, "View Source class may not be null") + Objects.requireNonNull(viewTarget, "View Target class may not be null") +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SJoinClass.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SJoinClass.scala new file mode 100644 index 0000000000000000000000000000000000000000..a9c9dcdc4185afe946ca50386ca9bb8b5ac9ba26 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SJoinClass.scala @@ -0,0 +1,23 @@ +package org.rosi_project.model_sync.generator.acr_model + +import org.rosi_project.model_management.sum.join.RsumJoinType + +class SJoinClass(_name: String, + _sPackage: String, + val base: SClass, + val other: SClass, + val joinType: RsumJoinType.Value, + val joinAttributes: Set[SStructuralFeature], + val innerAttributes: Set[SStructuralFeature], + val joinObject: SClass) extends SClass(_name, _sPackage) { + + override def getRootClassWithNameAndPackage(n: String, p: String): SClass = { + val bparent = base.getRootClassWithNameAndPackage(n, p) + val oparent = other.getRootClassWithNameAndPackage(n, p) + if (bparent != null) { + return bparent + } + oparent + } + +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SMethod.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SMethod.scala index e17dd79cbe0f5b8a3c2f1e88c1e14bc994cd9526..76e4cfec6e86a4d189a20406195270e1e34172b8 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SMethod.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SMethod.scala @@ -1,6 +1,7 @@ package org.rosi_project.model_sync.generator.acr_model import java.util.Objects +import org.rosi_project.model_sync.generator.acr_model.types.PredefTypes // TODO use a simple DSL to represent the method body? @@ -8,18 +9,26 @@ import java.util.Objects * * @author Rico Bergmann */ -class SMethod(val name: String, +class SMethod(name: String, val result: STypedElement, val params: Seq[SMethodParameter], var implementation: Seq[SMethodStatement], var overrides: Boolean = false) - extends SModelElement { + extends SNamedModelElement(name) { + + private var visibility = MethodVisibility.publicVis + + def setVisibility(v: MethodVisibility.Value): Unit = { + visibility = v + } + + def getVisibility: MethodVisibility.Value = visibility; /** Provides the return-type as a `String`. * * @return the type. Will never be `null` nor empty. */ - def getResultType: String = result.getName + def getResultType: String = result.getDeepName /** Replaces the current body of `this` method. * @@ -48,10 +57,10 @@ class SMethod(val name: String, def getUsedTypes: Set[STypedElement] = { val resultType = result match { case GenericSType(_, _, typeParam) => Seq(result, typeParam) - case SType.Unit => Seq.empty + case PredefTypes.Unit => Seq.empty case _ => Seq(result) } - val paramTypes = params.map(_.paramType) + val paramTypes = params.map(_.getType) val implementationTypes = implementation.map(_.usedTypes).fold(Set.empty)((s1, s2) => s1 ++ s2) (resultType ++ paramTypes).toSet ++ implementationTypes } @@ -63,17 +72,17 @@ class SMethod(val name: String, override def equals(other: Any): Boolean = other match { case that: SMethod => (that canEqual this) && - name == that.name && + getName == that.getName && result == that.result && params == that.params case _ => false } override def hashCode(): Int = { - val state = Seq(name, result, params) + val state = Seq(getName, result, params) state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b) } - override def toString: String = s"$name(${params.map(_.name).mkString(", ")}): $getResultType" + override def toString: String = s"$getName(${params.map(_.getName).mkString(", ")}): ${result.getName}" } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SMethodParameter.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SMethodParameter.scala index 6ac68dd5e24b1733742e43a3fbbf5f1dc7f2b3bb..ea4026309b5b80588b2887f0cf28635be599c5c4 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SMethodParameter.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SMethodParameter.scala @@ -4,14 +4,32 @@ package org.rosi_project.model_sync.generator.acr_model * * @author Rico Bergmann */ -case class SMethodParameter(name: String, paramType: STypedElement) { +case class SMethodParameter(private val name: String, private val paramType: STypedElement) { /** Provides the type of `this` parameter as a `String`. * * @return the type. Will never be `null` nor empty. */ - def getType: String = paramType.getName + def getTypeName: String = paramType.getName + + /** Provides the deep type name of `this` parameter as a `String`. + * + * @return the type. Will never be `null` nor empty. + */ + def getDeepTypeName: String = paramType.getDeepName + + /** Provides the type of `this` parameter as a `STypedElement`. + * + * @return the type. Will never be `null` nor empty. + */ + def getType: STypedElement = paramType + + /** Provides the name of `this` parameter as a `String`. + * + * @return the name. Will never be `null` nor empty. + */ + def getName: String = name - override def toString: String = s"$name: $getType" + override def toString: String = s"$getName: $getTypeName" } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SMethodStatement.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SMethodStatement.scala index c3b7c213d9fec9f83b1947f9d3b9c4dbf54b0677..294b33a4e2b71de878a86f64134fa322bacd5f15 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SMethodStatement.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SMethodStatement.scala @@ -12,7 +12,7 @@ package org.rosi_project.model_sync.generator.acr_model * * @author Rico Bergmann */ -case class SMethodStatement(content: String, usedTypes: Set[STypedElement] = Set.empty) { +case class SMethodStatement(private val content: String, usedTypes: Set[STypedElement] = Set.empty) { /** The actual statement as a `String`. * diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SModel.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SModel.scala index 280d69f0f4631ce8f75a2845ed3ec768d9fb7e5f..7412f6eb5b6d8072c7c697a4e0187bb1c04c4f5e 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SModel.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SModel.scala @@ -5,17 +5,80 @@ package org.rosi_project.model_sync.generator.acr_model * * @author Rico Bergmann */ -trait SModel extends SModelElement { - - /** Provides all the classes in `this` model. - */ +abstract class SModel(private val name: String, private val sourceName: String, private val nsUri: String) extends SModelElement { + + /** Get NsURI from the model. */ + def getNsURI: String = nsUri + + /** Get source name from the model. */ + def getSourceName: String = sourceName + + /** Get the name from the model. */ + def getName: String = name + + /** Provides all the classes in `this` model. */ def getAllClasses: Set[SClass] - + + /** Provides all model classes in `this` model. */ + def getModelClasses: Set[SClass] + + /** Provides all model enums in `this` model. */ + def getModelEnums: Set[SEnum] + + /** Provides all provider classes in `this` model. */ + def getProviderClasses: Set[SClass] + + /** Provides all relational compartments in `this` model. */ + def getRelationalCompartments: Set[SClass] + + /** Provides all view compartments in `this` model. */ + def getViewCompartments: Set[SClass] + + /** Provides all join classes in `this` model. */ + def getJoinClasses: Set[SClass] + + + + /** Extends the model by a new provder class. + * + * @param mClass the class to add. May never `null`. + */ + def addProviderClass(mClass: SClass): Unit + + /** Extends the model by a new relational compartment. + * + * @param mClass the class to add. May never `null`. + */ + def addRelationalCompartment(mClass: SClass): Unit + + /** Extends the model by a new view compartment. + * + * @param mClass the class to add. May never `null`. + */ + def addViewCompartment(mClass: SClass): Unit + /** Extends the model by a new class. * * @param mClass the class to add. May never `null`. */ def addModelClass(mClass: SClass): Unit + + /** Extends the model by a new join class. + * + * @param mClass the class to add. May never `null`. + */ + def addJoinClass(mClass: SClass): Unit + + /** Extends the model by a new enum. + * + * @param mEnum the enum to add. May never `null`. + */ + def addModelEnums(mEnum: SEnum): Unit + + /** + * Add another model to this on and return this one. + */ + def addOtherModel(model: SModel): SModel override def toString: String = s"SModel: classes=$getAllClasses" diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SModelVisitor.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SModelVisitor.scala index f4c43e6c3dbe89fdeadb23a54a2cedbad6d434ab..29eca86369976c4cb1350365d6b06a32010998ef 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SModelVisitor.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SModelVisitor.scala @@ -28,6 +28,13 @@ trait SModelVisitor { * specific. */ def visit(sAttr: SAttribute): Unit + + /** Runs the algorithm as appropriate for a reference of a model class. + * + * @param sRef the reference to run the algorithm on. Whether it may be `null` is implementation + * specific. + */ + def visit(sRef: SReference): Unit /** Runs the algorithm as appropriate for a method of a model class. * diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SNamedModelElement.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SNamedModelElement.scala new file mode 100644 index 0000000000000000000000000000000000000000..4c2251540517110826a720c35754b1e75e32d53b --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SNamedModelElement.scala @@ -0,0 +1,21 @@ +package org.rosi_project.model_sync.generator.acr_model + +/** Representation of named element like class, types, attributes and references. + * + * @author Christopher Werner + */ +abstract class SNamedModelElement (name: String) extends SModelElement { + + /** The name of 'this' element. + * + * @return the name. Will never be `null` nor empty. + */ + def getName: String = name + + /** The deep name with external class name + # + this class name. + * If there is no external class then only the name is returned. + * + * @return the name. Will never be `null` nor empty. + */ + def getDeepName: String = name +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SReference.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SReference.scala new file mode 100644 index 0000000000000000000000000000000000000000..275337162cae16c2847db9a45f4f149db661e895 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SReference.scala @@ -0,0 +1,55 @@ +package org.rosi_project.model_sync.generator.acr_model + +/** Representation of class reference. This abstraction is a simplification of an actual scala + * reference: it is impossible to distinguish between ''final'' and ''non-final'' fields. Instead, + * all attributes will be treated mutable. + * + * @author Christopher Werner + */ +case class SReference(_name: String, /*val stype: STypedElement,*/ _ttype: STypedElement, upperBound: Int, lowerBound: Int, containment: Boolean = false, var oppositeRef: SReference = null) extends SStructuralFeature (_name, _ttype) { + + def hasOpposite: Boolean = oppositeRef != null + + def getImportant: SReference = { + //return if one is containment + if (containment) { + return this + } + if (oppositeRef.containment) { + return oppositeRef + } + //return if one has bigger lowerBound + if (lowerBound > oppositeRef.lowerBound) { + return this + } + if (lowerBound < oppositeRef.lowerBound) { + return oppositeRef + } + //return if one has smaller upperBound but bigger than -1 + if (upperBound > -1 && oppositeRef.upperBound > -1 && upperBound > oppositeRef.upperBound) { + return oppositeRef + } + this + } + + def getMinimalConnection: SReference = { + if (lowerBound == 0 && upperBound == 1) { + return this + } + if (hasOpposite && oppositeRef.lowerBound == 0 && oppositeRef.upperBound == 1) { + return oppositeRef + } + if (lowerBound == 1 && upperBound == 1) { + return this + } + if (hasOpposite && oppositeRef.lowerBound == 1 && oppositeRef.upperBound == 1) { + return oppositeRef + } + return null + } + + override def accept(visitor: SModelVisitor): Unit = visitor.visit(this) + + override def toString: String = s"$getName: ${getTypeElement.getName} $containment $lowerBound $upperBound" + +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SRelationalCompartmentClass.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SRelationalCompartmentClass.scala new file mode 100644 index 0000000000000000000000000000000000000000..2a311e6667394ce8b1ad6413dd0917abd625df69 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SRelationalCompartmentClass.scala @@ -0,0 +1,13 @@ +package org.rosi_project.model_sync.generator.acr_model + +import java.util.Objects + +class SRelationalCompartmentClass(_name: String, + _sPackage: String = "", + _sClassType: SClassType.Value = SClassType.normalClass, + val connectedRef: SReference, + val sClass: STypedElement, + val tClass: STypedElement) extends SClass(_name, _sPackage, _sClassType) { + + Objects.requireNonNull(connectedRef, "Connected Reference may not be null") +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SSetter.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SSetter.scala index 563c9a8d114b1d7752a059ae79dba181286885e4..1553ac043d83abb298b7322d66b5802b3069aab4 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SSetter.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SSetter.scala @@ -1,15 +1,22 @@ package org.rosi_project.model_sync.generator.acr_model import org.rosi_project.model_sync.generator.support.ExtendedString.stringToExtended +import org.rosi_project.model_sync.generator.acr_model.types.PredefTypes /** Simple representation of a setter method. * * @author Rico Bergmann */ -class SSetter(attr: SAttribute) extends SMethod( - name = s"set${attr.name.firstLetterToUpperCase}", - result = SType.Unit, - params = Seq(SMethodParameter(attr.name.head.toString, attr.attrType)), - implementation = Seq(SMethodStatement(content = s"${attr.name} = ${attr.name.head}", usedTypes = Set(attr.attrType)))) { +class SSetter(struc: SStructuralFeature) extends SMethod( + name = s"set${struc.getName.firstLetterToUpperCase}", + result = PredefTypes.Unit, + params = Seq(SMethodParameter(struc.getName.head.toString, struc.getTypeElement)), + implementation = Seq(SMethodStatement(content = s"${struc.getName} = ${struc.getName.head}", usedTypes = Set(struc.getTypeElement)))) { + /*if (!STypeRegistry.isDefaultNotNullType(struc.getTypeElement.getName)) { + implementation = Seq(SMethodStatement(content = s"require(${struc.getName.head} != null)"), + SMethodStatement(content = s"${struc.getName} = ${struc.getName.head}", usedTypes = Set(struc.getTypeElement))) + } else { + implementation = Seq(SMethodStatement(content = s"${struc.getName} = ${struc.getName.head}", usedTypes = Set(struc.getTypeElement))) + } */ } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SSetterAdd.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SSetterAdd.scala new file mode 100644 index 0000000000000000000000000000000000000000..ff9aa456fc1aa70bf9c2ee317be547f040f0260c --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SSetterAdd.scala @@ -0,0 +1,23 @@ +package org.rosi_project.model_sync.generator.acr_model + +import org.rosi_project.model_sync.generator.support.ExtendedString.stringToExtended +import org.rosi_project.model_sync.generator.acr_model.types.PredefTypes + +/** Add an element to a Set of elements. + * + * @author Christopher Werner + */ +class SSetterAdd(struc: SStructuralFeature, inner: STypedElement) extends SMethod( + name = s"add${struc.getName.firstLetterToUpperCase}", + result = PredefTypes.Unit, + params = Seq(SMethodParameter(struc.getName.head.toString, inner)), + implementation = Seq(SMethodStatement(content = s"${struc.getName} += ${struc.getName.head}", usedTypes = Set(struc.getTypeElement)))) { + + if (!STypeRegistry.isDefaultNotNullType(struc.getTypeElement.getName)) { + implementation = Seq(SMethodStatement(content = s"require(${struc.getName.head} != null)"), + SMethodStatement(content = s"require(!${struc.getName}.contains(${struc.getName.head}))"), + SMethodStatement(content = s"${struc.getName} += ${struc.getName.head}", usedTypes = Set(struc.getTypeElement))) + } else { + implementation = Seq(SMethodStatement(content = s"${struc.getName} += ${struc.getName.head}", usedTypes = Set(struc.getTypeElement))) + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SSetterRemove.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SSetterRemove.scala new file mode 100644 index 0000000000000000000000000000000000000000..7d2599fcf11c3167a9a8d9da10cc8123bc1a050f --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SSetterRemove.scala @@ -0,0 +1,23 @@ +package org.rosi_project.model_sync.generator.acr_model + +import org.rosi_project.model_sync.generator.support.ExtendedString.stringToExtended +import org.rosi_project.model_sync.generator.acr_model.types.PredefTypes + +/** Remove an element from a Set of elements. + * + * @author Christopher Werner + */ +class SSetterRemove(struc: SStructuralFeature, inner: STypedElement) extends SMethod( + name = s"remove${struc.getName.firstLetterToUpperCase}", + result = PredefTypes.Unit, + params = Seq(SMethodParameter(struc.getName.head.toString, inner)), + implementation = Seq(SMethodStatement(content = s"${struc.getName} -= ${struc.getName.head}", usedTypes = Set(struc.getTypeElement)))) { + + if (!STypeRegistry.isDefaultNotNullType(struc.getTypeElement.getName)) { + implementation = Seq(SMethodStatement(content = s"require(${struc.getName.head} != null)"), + SMethodStatement(content = s"require(${struc.getName}.contains(${struc.getName.head}))"), + SMethodStatement(content = s"${struc.getName} -= ${struc.getName.head}", usedTypes = Set(struc.getTypeElement))) + } else { + implementation = Seq(SMethodStatement(content = s"${struc.getName} -= ${struc.getName.head}", usedTypes = Set(struc.getTypeElement))) + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SStructuralFeature.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SStructuralFeature.scala new file mode 100644 index 0000000000000000000000000000000000000000..91afb3973a4760c887a671c36b32471246334af2 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SStructuralFeature.scala @@ -0,0 +1,24 @@ +package org.rosi_project.model_sync.generator.acr_model + +/** Representation of structural features like attributes and references. + * + * @author Christopher Werner + */ +abstract class SStructuralFeature (_name: String, private val sType: STypedElement) extends SNamedModelElement(_name) { + + var isFinal: Boolean = false + private var visibility = MethodVisibility.publicVis + + def setVisibility(v: MethodVisibility.Value): Unit = { + visibility = v + } + + def getVisibility: MethodVisibility.Value = visibility; + + /** The type of 'this' structural feature. + * + * @return + */ + def getTypeElement: STypedElement = sType + +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SType.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SType.scala index a3a15f4f511ef046fa9fad55d026a46c5566828f..ad0470e4e58497855daab94bd119517addf58f58 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SType.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SType.scala @@ -11,30 +11,9 @@ package org.rosi_project.model_sync.generator.acr_model * @see [[SClass]] * @author Rico Bergmann */ -case class SType(name: String, sPackage: String = "") extends STypedElement { - - override def getName: String = name - - override def getPackage: String = sPackage +case class SType(_name: String, _sPackage: String = "", _sClassType: SClassType.Value = SClassType.normalTrait) extends STypedElement (_name, _sPackage, _sClassType) { override def accept(visitor: SModelVisitor): Unit = visitor.visit(this) - -} - -/** The companion defines frequently used types. - */ -object SType { - - /** The empty type. - */ - val Unit = SType("Unit") - - /** Wrapper for `AnyRef`. - */ - val AnyRef = SType("AnyRef") - - /** Wrapper for `String`. - */ - val String = SType("String") - + + override def toString: String = s"ST: $getName($sPackage, $isInterface)" } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/STypeRegistry.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/STypeRegistry.scala index 345d9b8b7b13d8a2c53fdde1423736865ddad4f6..bfa7fefca86bec5b3e3b43a2723e89dba38783f0 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/STypeRegistry.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/STypeRegistry.scala @@ -1,5 +1,9 @@ package org.rosi_project.model_sync.generator.acr_model +import org.rosi_project.model_sync.generator.acr_model.types.PredefTypes +import org.eclipse.emf.ecore.EClass +import org.rosi_project.model_sync.generator.acr_model.types.PredefEcoreTypes + /** Repository to keep track of all types and classes of model. It ensures that all attributes, * methods, etc. reference the same type instances and thus prevent duplication and conflicting * states. The registry should be treated as "''single point of truth''". @@ -7,20 +11,88 @@ package org.rosi_project.model_sync.generator.acr_model * @author Rico Bergmann */ object STypeRegistry { + + private var registeredTypes: Map[STypedElement, EClass] = Map.empty + + private val defaultTypesNull: Map[STypedElement, EClass] = Map( + PredefTypes.Date -> null, + PredefTypes.Object -> null, + PredefTypes.String -> null, + ) + + private val defaultTypesNotNull: Map[STypedElement, EClass] = Map( + PredefTypes.Boolean -> null, + PredefTypes.Byte -> null, + PredefTypes.Char -> null, + PredefTypes.Double -> null, + PredefTypes.Float -> null, + PredefTypes.Integer -> null, + PredefTypes.Long -> null, + PredefTypes.Short -> null, + ) + + /*private val ecoreTypes: Map[STypedElement, EClass] = Map( + PredefEcoreTypes.EcoreObject -> null, + PredefEcoreTypes.EcoreStructuralFeature -> null, + )*/ + + def getFromClass(cls: EClass): STypedElement = { + registeredTypes.foreach(r => { + if (r._2 == cls) { + return r._1 + } + }) + null + } - private var registeredTypes: Set[STypedElement] = Set() - - registerDefaultTypes() + registeredTypes ++= defaultTypesNull + registeredTypes ++= defaultTypesNotNull + //registeredTypes ++= ecoreTypes + + /** + * Return true if this name comes from a standard null type. + * + * @param name the name that must be proven. + * @return `true` if it is a default type. Otherwise return false. + */ + def isDefaultNullType(name: String): Boolean = { + val existingNull: Option[STypedElement] = defaultTypesNull.keySet.find(existing => existing.getName == name) + return !existingNull.isEmpty + } + + /** + * Return true if this name comes from a standard not null type. + * + * @param name the name that must be proven. + * @return `true` if it is a default type. Otherwise return false. + */ + def isDefaultNotNullType(name: String): Boolean = { + val existingNotNull: Option[STypedElement] = defaultTypesNotNull.keySet.find(existing => existing.getName == name) + return !existingNotNull.isEmpty + } + + /** + * Return true if this name comes from a standard type. + * + * @param name the name that must be proven. + * @return `true` if it is a default type. Otherwise return false. + */ + def isDefaultType(name: String): Boolean = { + val existingNotNull: Option[STypedElement] = defaultTypesNotNull.keySet.find(existing => existing.getName == name) + val existingNull: Option[STypedElement] = defaultTypesNull.keySet.find(existing => existing.getName == name) + return !existingNotNull.isEmpty || !existingNull.isEmpty + } /** Registers a type if it is not already known. * * @param theType the new type. May never be `null`. * @return `theType` if it was indeed unknown before. Otherwise the currently registered type. */ - def addType(theType: STypedElement): STypedElement = { - val existing: Option[STypedElement] = registeredTypes.find(existing => existing.getName == theType.getName && existing.getPackage == theType.getPackage) + def addType(theType: STypedElement, cls: EClass): STypedElement = { + val existing: Option[STypedElement] = registeredTypes.keySet.find(existing => existing.getName == theType.getName && existing.getPackage == theType.getPackage) if (existing.isEmpty) { - registeredTypes += theType + registeredTypes = registeredTypes + (theType -> cls) + //registeredTypes += theType theType } else { existing.get @@ -33,36 +105,13 @@ object STypeRegistry { * @param sPackage the package that contains the type * @return the type if it was found */ - def query(name: String, sPackage: String): Option[STypedElement] = { - registeredTypes.find(t => t.getName == name && t.getPackage == sPackage) - } - - /** Searches for a type based on its name. It may reside in any package. - * - * @param name the type's name - * @return the type if it was found - */ - def queryForName(name: String): Option[STypedElement] = { - registeredTypes.find(_.getName == name) + def query(name: String, sPackage: String): Option[STypedElement] = { + registeredTypes.keySet.find(t => t.getName == name && t.getPackage == sPackage) } /** Provides all types that are currently in the repository. */ - def allTypes: Set[STypedElement] = registeredTypes - - private def registerDefaultTypes(): Unit = { - registeredTypes ++= Seq( - SType("Boolean"), - SType("Byte"), - SType("Short"), - SType("Integer"), - SType("Long"), - SType("Float"), - SType("Double"), - SType("String"), - ) - } + def allTypes: Set[STypedElement] = registeredTypes.keySet override def toString: String = s"Registry: $registeredTypes" - } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/STypedElement.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/STypedElement.scala index d89878c254515cac3bf962435253300052e1135f..0579ff7b2c1bc36bbd79bc8ecf2bc9c99e9f49a9 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/STypedElement.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/STypedElement.scala @@ -10,32 +10,50 @@ package org.rosi_project.model_sync.generator.acr_model * * @author Rico Bergmann */ -trait STypedElement extends SModelElement { - - /** The name of `this` type. - * - * @return the name. Will never be `null` nor empty. - */ - def getName: String +abstract class STypedElement (_name: String, + val sPackage: String, + val sClassType: SClassType.Value) extends SNamedModelElement(_name) { + + /** Checks, whether `this` is part of the default package */ + def isDefaultPackage: Boolean = sPackage == "" /** The package containing `this` type. * * @return */ - def getPackage: String + def getPackage: String = sPackage - /** The parameters necessary to create an instance of `this` type. - */ - def getConstructorParameters: Seq[SMethodParameter] = Seq.empty + /** The constructor with all parameters of `this` type for construction. */ + def getAllConstructorParameters: Seq[SMethodParameter] = Seq.empty + + /** The constructor with only attribute parameters of `this` type for construction. */ + def getAttributeConstructorParameters: Seq[SMethodParameter] = Seq.empty /** The inheritance hierarchy provides information about the types `this` extends. It will start * with `this` (thus the hierarchy will 'never' be empty) and end with the root type. `AnyRef` * will be ignored however. */ def getInheritanceHierarchy: Seq[STypedElement] = Seq.empty + + /** + * Proof the hierarchical equality between two STypedElement + */ + def proofHierarchicalEquality(sType: STypedElement): Boolean = sType == this /** Provides all classes that need to be imported for `this` type. */ def getNecessaryImports: Set[SImport] = Set.empty + + def isInterface: Boolean = sClassType == SClassType.normalTrait + + def isAbstract: Boolean = sClassType == SClassType.abstactClass + + def isObject: Boolean = sClassType == SClassType.normalObject + + def isCaseClass: Boolean = sClassType == SClassType.caseClass + + def isNormalClass: Boolean = sClassType == SClassType.normalClass + + override def toString: String = s"STE: $getName($sPackage, $isInterface)" } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SViewClass.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SViewClass.scala new file mode 100644 index 0000000000000000000000000000000000000000..fb2e69f86be8751677ad386d8ec6fbda67ad93e5 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SViewClass.scala @@ -0,0 +1,14 @@ +package org.rosi_project.model_sync.generator.acr_model + +class SViewClass(_name: String, + _sPackage: String) extends SClass(_name, _sPackage) { + + private var joinObjects: Set[SJoinClass] = Set.empty + + def getJoinObject(): Set[SJoinClass] = joinObjects + + def addJoinObject(v: SJoinClass): Unit = { + require(v != null) + joinObjects += v + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SimpleSModel.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SimpleSModel.scala index 4722a9ad758e180a69e4fc59cf9c92ffa927471c..c5ac6720b057b4d23be47ffe451d94beb4522977 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SimpleSModel.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/SimpleSModel.scala @@ -6,16 +6,82 @@ import org.rosi_project.model_sync.generator.support.Assert * * @author Rico Bergmann */ -class SimpleSModel extends SModel { - +class SimpleSModel(name: String, sourceName: String, nsUri: String) extends SModel(name, sourceName, nsUri) { + private var sClasses: Set[SClass] = Set.empty + private var sEnums: Set[SEnum] = Set.empty + + /** Provides all the classes in `this` model. */ + override def getAllClasses: Set[SClass] = sClasses + + /** Provides all model classes in `this` model. */ + override def getModelClasses: Set[SClass] = sClasses + + /** Provides all provider classes in `this` model. */ + override def getProviderClasses: Set[SClass] = sClasses + + /** Provides all relational compartments in `this` model. */ + override def getRelationalCompartments: Set[SClass] = sClasses + + /** Provides all view compartments in `this` model. */ + override def getViewCompartments: Set[SClass] = sClasses + + /** Provides all join classes in `this` model. */ + override def getJoinClasses: Set[SClass] = Set.empty + + /** Provides all model enums in `this` model. */ + override def getModelEnums: Set[SEnum] = sEnums + /** Extends the model by a new class. + * + * @param mClass the class to add. May never `null`. + */ override def addModelClass(mClass: SClass): Unit = { Assert.notNull(mClass, "Class may not be null") sClasses += mClass } - - override def getAllClasses: Set[SClass] = sClasses + + /** Extends the model by a new provder class. + * + * @param mClass the class to add. May never `null`. + */ + override def addProviderClass(mClass: SClass): Unit = { + Assert.notNull(mClass, "Class may not be null") + sClasses += mClass + } + + /** Extends the model by a new enum. + * + * @param mEnum the enum to add. May never `null`. + */ + override def addModelEnums(mEnum: SEnum): Unit = { + Assert.notNull(mEnum, "Enum may not be null") + sEnums += mEnum + } + + /** Extends the model by a new relational compartment. + * + * @param mClass the class to add. May never `null`. + */ + override def addRelationalCompartment(mClass: SClass): Unit = { + Assert.notNull(mClass, "Class may not be null") + sClasses += mClass + } + + /** Extends the model by a new view compartment. + * + * @param mClass the class to add. May never `null`. + */ + override def addViewCompartment(mClass: SClass): Unit = { + Assert.notNull(mClass, "Class may not be null") + sClasses += mClass + } + + /** Extends the model by a new join class. + * + * @param mClass the class to add. May never `null`. + */ + override def addJoinClass(mClass: SClass): Unit = {/*pass*/} override def accept(visitor: SModelVisitor): Unit = { sClasses.foreach(_.accept(visitor)) @@ -27,13 +93,19 @@ class SimpleSModel extends SModel { override def equals(other: Any): Boolean = other match { case that: SimpleSModel => (that canEqual this) && + sEnums == that.sEnums && sClasses == that.sClasses case _ => false } + + override def addOtherModel(model: SModel): SModel = { + sClasses = sClasses ++ model.getModelClasses + sEnums = sEnums ++ model.getModelEnums + return this + } override def hashCode(): Int = { val state = Seq(sClasses) state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b) } - } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/types/GenericSequence.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/types/GenericSequence.scala new file mode 100644 index 0000000000000000000000000000000000000000..aa964a5f65e14200879f657cd352c1e802d237e7 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/types/GenericSequence.scala @@ -0,0 +1,10 @@ +package org.rosi_project.model_sync.generator.acr_model.types + +import org.rosi_project.model_sync.generator.acr_model.{GenericSType, SMethodParameter, STypedElement} + +abstract class GenericSequence(name: String, elemType: STypedElement) extends GenericSType(name, typeParam = elemType) { + + override def getAllConstructorParameters: Seq[SMethodParameter] = Seq(SMethodParameter("elems", elemType)) + + override def toString: String = s"Generic Sequence: ${elemType}" +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/types/PredefEcoreTypes.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/types/PredefEcoreTypes.scala new file mode 100644 index 0000000000000000000000000000000000000000..34aff0138b75dc363d457eb8b449639770b01f60 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/types/PredefEcoreTypes.scala @@ -0,0 +1,33 @@ +package org.rosi_project.model_sync.generator.acr_model.types + +import org.rosi_project.model_sync.generator.acr_model.SType + +/** Contains a number of types that are part of the Ecore package. + * + * This should prevent creating them over and over again every time a `SType` should be set to any + * of these types. + * + * @author Christopher Werner + */ +object PredefEcoreTypes { + + /** `org.eclipse.emf.common.util.URI` */ + val URI = SType("URI", "org.eclipse.emf.common.util") + + /** `org.eclipse.emf.ecore.resource.Resource` */ + val Resource = SType("Resource", "org.eclipse.emf.ecore.resource") + + /** `org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl` */ + val XMIResourceFactoryImpl = SType("XMIResourceFactoryImpl", "org.eclipse.emf.ecore.xmi.impl") + + /** `org.eclipse.emf.ecore.EObject` */ + val EcoreObject = SType("EObject", "org.eclipse.emf.ecore") + + /** `org.eclipse.emf.ecore.EStructuralFeature` */ + val EcoreStructuralFeature = SType("EStructuralFeature", "org.eclipse.emf.ecore") + + /** `org.eclipse.emf.ecore.EOperation` */ + val EcoreOperation = SType("EOperation", "org.eclipse.emf.ecore") + + val ResourceSetImpl = SType("ResourceSetImpl", "org.eclipse.emf.ecore.resource.impl") +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/types/PredefTypes.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/types/PredefTypes.scala index d181569e09da6186cb0ba1aa877b4d1e4f586a3a..08cf1c007fe95beda2933b6fd0e1396b64abde48 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/types/PredefTypes.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/types/PredefTypes.scala @@ -10,18 +10,60 @@ import org.rosi_project.model_sync.generator.acr_model.{GenericSType, SType, STy * @author Rico Bergmann */ object PredefTypes { + + /** `Convert Java list to Scala listApp` */ + val ScalaConverter = SType("_", "scala.collection.JavaConverters") + + /** `App` */ + val App = SType("App") + + /** `Char` */ + val Char = SType("Char") + + /** `Byte` */ + val Byte = SType("Byte") + + /** `Short` */ + val Short = SType("Short") + + /** `Integer` */ + val Integer = SType("Int") + + /** `Long` */ + val Long = SType("Long") + + /** `Float` */ + val Float = SType("Float") + + /** `Double` */ + val Double = SType("Double") + + /** `Boolean` */ + val Boolean = SType("Boolean") + + /** `String` */ + val String = SType("String") - /** `java.lang.Object` - */ + /** `java.lang.Object` */ val Object = SType("Object") - /** `java.io.File` - */ + /** `java.io.File` */ val File = SType("File", "java.io") + + /** `java.util.Date` */ + val Date = SType("Date", "java.util") - /** `java.lang.reflect.Parameter` - */ + /** `java.lang.reflect.Parameter` */ val Parameter = SType("Parameter", "java.lang.reflect") + + /** `Unit` The empty type. */ + val Unit = SType("Unit") + + /** Wrapper for `AnyRef`. */ + val AnyRef = SType("AnyRef") + + /** Wrapper for `Any`. */ + val Any = SType("Any") /** `java.lang.Class[typ]` * diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/types/SList.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/types/SList.scala index a7d11b35fa3045539727f7d5ddc5df9ea01603f8..a8be05b28beecbe1e832611b57c40e78e675417b 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/types/SList.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/types/SList.scala @@ -4,9 +4,7 @@ import org.rosi_project.model_sync.generator.acr_model._ /** Wraps a Scala `List` for some type. */ -class SList(elemType: STypedElement) extends SSeq(elemType) { - - override def getConstructorParameters: Seq[SMethodParameter] = Seq(SMethodParameter("elems", elemType)) +class SList(elemType: STypedElement) extends GenericSequence("List", elemType) { } @@ -16,6 +14,6 @@ object SList { def apply(elemType: STypedElement): SList = new SList(elemType) - def unapply(arg: SList): Option[STypedElement] = Some(arg.elemType) + def unapply(arg: SList): Option[STypedElement] = Some(arg.typeParam) } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/types/SSeq.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/types/SSeq.scala index e6a9f5ded7b0d289ec384126b9a20c07481f26aa..ff4b3c58717872c813ae93991aa368d3ffdebba2 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/types/SSeq.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/types/SSeq.scala @@ -4,9 +4,7 @@ import org.rosi_project.model_sync.generator.acr_model.{GenericSType, SMethodPar /** Wraps a Scala `Seq` for some type. */ -class SSeq(val elemType: STypedElement) extends GenericSType(name = "Seq", sPackage = "", typeParam = elemType) { - - override def getConstructorParameters: Seq[SMethodParameter] = Seq(SMethodParameter("elems", elemType)) +class SSeq(elemType: STypedElement) extends GenericSequence("Seq", elemType) { } @@ -16,6 +14,6 @@ object SSeq { def apply(elemType: STypedElement): SSeq = new SSeq(elemType) - def unapply(arg: SSeq): Option[STypedElement] = Some(arg.elemType) + def unapply(arg: SSeq): Option[STypedElement] = Some(arg.typeParam) } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr_model/types/SSet.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/types/SSet.scala new file mode 100644 index 0000000000000000000000000000000000000000..64519bb45c73755e57532636d58f95f1a50925ea --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/acr_model/types/SSet.scala @@ -0,0 +1,19 @@ +package org.rosi_project.model_sync.generator.acr_model.types + +import org.rosi_project.model_sync.generator.acr_model._ + +/** Wraps a Scala `Set` for some type. + */ +class SSet(elemType: STypedElement) extends GenericSequence("Set", elemType) { + +} + +/** The companion provides `apply` and `unapply` methods. + */ +object SSet { + + def apply(elemType: STypedElement): SSet = new SSet(elemType) + + def unapply(arg: SSet): Option[STypedElement] = Some(arg.typeParam) + +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/conversion/Converter.scala b/src/main/scala/org/rosi_project/model_sync/generator/conversion/Converter.scala index 502465439eda93fe71934b67d95cc9eca6fd1d0e..b4aaa14268e7ec82018367ca28c7aa0d5f60384d 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/conversion/Converter.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/conversion/Converter.scala @@ -13,6 +13,6 @@ trait Converter[S, T] { * @param source the object to convert * @return the converted object */ - def convert(source: S): T + def convert(source: S, sourceName: String): T } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/conversion/EmfTypeTranslator.scala b/src/main/scala/org/rosi_project/model_sync/generator/conversion/EmfTypeTranslator.scala index 716e851ce938be96a22c2dc072cf257a0a29ce75..0fb4d447e4edf8c1181c9ba359f5d5168ee3392b 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/conversion/EmfTypeTranslator.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/conversion/EmfTypeTranslator.scala @@ -4,6 +4,8 @@ import java.util.Objects import org.eclipse.emf.ecore.EDataType import org.rosi_project.model_sync.generator.acr_model.SType +import org.rosi_project.model_sync.generator.acr_model.types.PredefTypes +import org.rosi_project.model_sync.generator.acr_model.types.PredefEcoreTypes /** Service to map an instance of [[EDataType]] to its corresponding [[SType]] (which wrap Scala's * native types). @@ -13,17 +15,29 @@ import org.rosi_project.model_sync.generator.acr_model.SType object EmfTypeTranslator { private val typeMap: Map[String, SType] = Map( - "EBoolean" -> SType("Boolean"), - "EByte" -> SType("Byte"), - "EChar" -> SType("Char"), - "EDate" -> SType(name = "Date", sPackage = "java.util"), - "EDouble" -> SType("Double"), - "EFloat" -> SType("Float"), - "EInt" -> SType("Int"), - "EJavaObject" -> SType("Object"), - "ELong" -> SType("Long"), - "EShort" -> SType("Short"), - "EString" -> SType("String"), + "Double" -> PredefTypes.Double, //map normal data types to its normal data types + "Float" -> PredefTypes.Float, + "Int" -> PredefTypes.Integer, + "Char" -> PredefTypes.Char, + "Byte" -> PredefTypes.Byte, + "Boolean" -> PredefTypes.Boolean, + "Long" -> PredefTypes.Long, + "Short" -> PredefTypes.Short, + "String" -> PredefTypes.String, + "EBoolean" -> PredefTypes.Boolean, //map EMF data types to its normal data types + "EByte" -> PredefTypes.Byte, + "EChar" -> PredefTypes.Char, + "EDate" -> PredefTypes.Date, + "EDouble" -> PredefTypes.Double, + "EFloat" -> PredefTypes.Float, + "EInt" -> PredefTypes.Integer, + "EJavaObject" -> PredefTypes.Object, + "ELong" -> PredefTypes.Long, + "EShort" -> PredefTypes.Short, + "EString" -> PredefTypes.String, + "EObject" -> PredefTypes.Object, + "EStructuralFeature" -> PredefEcoreTypes.EcoreStructuralFeature, + "EOperation" -> PredefEcoreTypes.EcoreOperation, ) /** Maps an EMF data type to its corresponding Scala type. diff --git a/src/main/scala/org/rosi_project/model_sync/generator/conversion/SClassConverter.scala b/src/main/scala/org/rosi_project/model_sync/generator/conversion/SClassConverter.scala index 76b10c5c96d06b597cdbe8ec78dbe3896b66e75a..34573306ef182f24140e1ed2e8fb9996eef3a613 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/conversion/SClassConverter.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/conversion/SClassConverter.scala @@ -3,6 +3,8 @@ package org.rosi_project.model_sync.generator.conversion import org.eclipse.emf.ecore.{EAttribute, EClass, EReference} import org.rosi_project.model_sync.generator.acr_model._ import org.rosi_project.model_sync.generator.acr_model.types.SList +import org.rosi_project.model_sync.generator.acr_model.types.SSet +import org.rosi_project.model_sync.generator.PackageNames /** Converter to generate instances of [[SClass]] based on [[EClass EClasses]]. * @@ -10,94 +12,105 @@ import org.rosi_project.model_sync.generator.acr_model.types.SList */ class SClassConverter extends Converter[EClass, SClass] { - override def convert(source: EClass): SClass = { + override def convert(source: EClass, sourceName: String): SClass = { var attrs: List[SAttribute] = List.empty + var refs: List[SReference] = List.empty + var pars: List[STypedElement] = List.empty // fetch the attributes of the SClass - (source.getEAttributes: List[EAttribute]).foreach(eAttr => { + (source.getEAttributes: List[EAttribute]).foreach(eAttr => { + //println("Attribute: " + eAttr.getEAttributeType.getName + " pkg: " + eAttr.getEAttributeType.getEPackage.getNsPrefix + " pre: " + PackageNames.sourcePkgPrefix) val attrType: STypedElement = STypeRegistry - // check if the attribute type is already known and registered - .query(eAttr.getEAttributeType.getName, eAttr.getEAttributeType.getEPackage.getName) - + .query(eAttr.getEAttributeType.getName, PackageNames.sourcePkgPrefix + eAttr.getEAttributeType.getEPackage.getNsPrefix) // otherwise create a new type .getOrElse { val newAttr = EmfTypeTranslator - // if the type is wrapped by EMF (such as EString), use the corresponding scala type .getSClassFromEmf(eAttr.getEAttributeType) - // otherwise create a new class (as the attribute should instance of a class rather than a type in this case) - .getOrElse(new SClass(eAttr.getEAttributeType.getName, sPackage = eAttr.getEAttributeType.getEPackage.getName)) + .getOrElse(new SClass(eAttr.getEAttributeType.getName, PackageNames.sourcePkgPrefix + eAttr.getEAttributeType.getEPackage.getNsPrefix)) // finally save the type - STypeRegistry.addType(newAttr) + STypeRegistry.addType(newAttr, null) } - - attrs ::= SAttribute(eAttr.getName, attrType) + + attrs ::= SAttribute(eAttr.getName, attrType, eAttr.isUnique()) }) - // TODO add support for multiple inheritance - + //fetch the references of the SClass (source.getEReferences: List[EReference]) - .filter(_.isContainment) .foreach(eRef => { - val attrName = eRef.getName - val attrType = eRef.getEReferenceType.getName - val attrPckg = eRef.getEReferenceType.getEPackage.getName - - var sAttrType: STypedElement = STypeRegistry - + val refName: String = eRef.getName //Attribute name + val refType: String = eRef.getEReferenceType.getName //Name of the attribute type + val refTypePckg: String = PackageNames.sourcePkgPrefix + eRef.getEReferenceType.getEPackage.getNsPrefix //Package name of the attribute type + val containment: Boolean = eRef.isContainment() //Containment relation or not + val oppositeERef: EReference = eRef.getEOpposite() //Opposite reference + var oppositeRef: SReference = null //Opposite reference + val upperBound: Int = eRef.getUpperBound() //Upper bound + val lowerBound: Int = eRef.getLowerBound() //Lower bound + + var newTypeCreated: Boolean = false + + //println("Referenz: " + refType + " pkg: " + refTypePckg) + + var sRefType: STypedElement = STypeRegistry // check if the attribute type is already known and registered - .query(attrType, attrPckg) - + .query(refType, refTypePckg) // otherwise create a new type .getOrElse { + newTypeCreated = true + val newAttr = EmfTypeTranslator - // if the type is wrapped by EMF (such as EString), use the corresponding scala type - .getSClassFromEmf(attrType) - + .getSClassFromEmf(refType) // otherwise create a new class (as the attribute should instance of a class rather than a type in this case) - .getOrElse(new SClass(attrType, sPackage = attrPckg)) - + .getOrElse(new SClass(refType, refTypePckg)) + // finally save the type - STypeRegistry.addType(newAttr) + STypeRegistry.addType(newAttr, null) + } + + //handle opposite ref + if (oppositeERef != null) { + //if the ref has an opposite + var classRef = sRefType.asInstanceOf[SClass] + if (!classRef.getReferences.isEmpty) { + //opposite class type exists and has references + classRef.getReferences.foreach { r => + if (r.getName == oppositeERef.getName) { + oppositeRef = r + } + } } + } if (eRef.getUpperBound > 1 || eRef.getUpperBound == -1) { - sAttrType = SList(sAttrType) + sRefType = SSet(sRefType) + } + + var newReference = SReference(refName, sRefType, upperBound, lowerBound, containment, oppositeRef) + if (oppositeRef != null) { + oppositeRef.oppositeRef = newReference } - - attrs ::= SAttribute(attrName, sAttrType) - + + refs ::= newReference }) - val parents: List[EClass] = source.getESuperTypes.toArray(new Array[EClass](0)).toList - - // we may not convert class hierarchies that utilize multiple inheritance yet - if (violatesSingleInheritance(parents)) { - throw new UnconvertibleEmfException(source.getEPackage, s"For class: $source") - } - - val parent: STypedElement = parents.headOption.map((p: EClass) => { - STypeRegistry - + val eClassParents: List[EClass] = source.getESuperTypes.toArray(new Array[EClass](0)).toList + + eClassParents.foreach { p => + pars ::= STypeRegistry // check if we already know the parent - .queryForName(p.getName) - + .query(p.getName, PackageNames.sourcePkgPrefix + p.getEPackage.getNsPrefix) // otherwise we need to create and register it .getOrElse { - val parentSClass: SClass = new SClass(p.getName, sPackage = p.getEPackage.getName) - + val parentSClass: SClass = new SClass(p.getName, PackageNames.sourcePkgPrefix + p.getEPackage.getNsPrefix) // register the parent (it will be visited and completely inflated later on) - STypeRegistry.addType(parentSClass) + STypeRegistry.addType(parentSClass, null) parentSClass } - }).orNull - - - // TODO add methods to SClass + } /* `convert` may be called on two different occasions: either for a completely new type or * for a type that was already created before when another type was being inflated by `convert`. @@ -109,18 +122,33 @@ class SClassConverter extends Converter[EClass, SClass] { * have the type known). Therefore we will set these now. */ - val currentClass: Option[STypedElement] = STypeRegistry.query(source.getName, source.getEPackage.getName) + val currentClass: Option[STypedElement] = STypeRegistry.query(source.getName, PackageNames.sourcePkgPrefix + source.getEPackage.getNsPrefix) currentClass.map { case clazz: SClass => - clazz.attributes = attrs - clazz.parent = parent + clazz.setAttributes(attrs) + clazz.setReferences(refs) + pars.foreach(p => { + clazz.addParent(p) + }) clazz case sType => sys.error(s"sType should have been a class: $sType") }.getOrElse { - val createdClass: SClass = new SClass(source.getName, source.getEPackage.getName, attrs, parent) - STypeRegistry.addType(createdClass) + var sClassType = SClassType.normalClass + if (source.isAbstract) { + sClassType = SClassType.abstactClass + } + if (source.isInterface) { + sClassType = SClassType.normalTrait + } + val createdClass: SClass = new SClass(source.getName, PackageNames.sourcePkgPrefix + source.getEPackage.getNsPrefix, sClassType) + createdClass.setAttributes(attrs) + createdClass.setReferences(refs) + pars.foreach(p => { + createdClass.addParent(p) + }) + STypeRegistry.addType(createdClass, null) createdClass } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/conversion/SEnumConverter.scala b/src/main/scala/org/rosi_project/model_sync/generator/conversion/SEnumConverter.scala new file mode 100644 index 0000000000000000000000000000000000000000..64578dfdc03267bff40e086168e94628fd54984c --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/conversion/SEnumConverter.scala @@ -0,0 +1,24 @@ +package org.rosi_project.model_sync.generator.conversion + +import org.eclipse.emf.ecore.EEnum +import org.rosi_project.model_sync.generator.acr_model.SEnum +import org.eclipse.emf.ecore.EEnumLiteral +import org.rosi_project.model_sync.generator.acr_model.STypeRegistry +import org.rosi_project.model_sync.generator.PackageNames + +class SEnumConverter extends Converter[EEnum, SEnum] { + + override def convert(source: EEnum, sourceName: String): SEnum = { + + var strings: Set[String] = Set.empty + + //fetch the name from the literals + (source.getELiterals: List[EEnumLiteral]).foreach(elit => { + strings += elit.getName + }) + + val createdEnum: SEnum = new SEnum(source.getName, PackageNames.sourcePkgPrefix + source.getEPackage.getNsPrefix, strings) + STypeRegistry.addType(createdEnum, null) + createdEnum + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/conversion/SModelGenerator.scala b/src/main/scala/org/rosi_project/model_sync/generator/conversion/SModelGenerator.scala index 51057830ce435267e5f7f8b15f34cb14b4ef870e..76a4cfeb57da0728560e252ccfefc55c0baf68f7 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/conversion/SModelGenerator.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/conversion/SModelGenerator.scala @@ -1,30 +1,53 @@ package org.rosi_project.model_sync.generator.conversion -import org.eclipse.emf.ecore.{EClass, EGenericType, EPackage} -import org.rosi_project.model_sync.generator.acr_model.{SModel, SType, STypeRegistry, SimpleSModel} +import org.eclipse.emf.ecore.{ EClass, EGenericType, EPackage } +import org.rosi_project.model_sync.generator.acr_model.{ SModel, SType, STypeRegistry, ComplexSModel } import scala.collection.JavaConverters._ - -/** Converter to generate an [[SModel]] from ecore. - * - * @author Rico Bergmann - */ +import org.rosi_project.model_sync.generator.acr_model.SClass +import org.eclipse.emf.ecore.EEnum +import org.rosi_project.model_sync.generator.PackageNames +import org.rosi_project.model_sync.generator.acr_model.SClassType + +/** + * Converter to generate an [[SModel]] from ecore. + * + * @author Rico Bergmann + */ class SModelGenerator extends Converter[EPackage, SModel] { - override def convert(source: EPackage): SModel = { - val packageName = if (source.getName != null) source.getName else "" - val contents = source.eAllContents().asScala - - val model = new SimpleSModel + override def convert(source: EPackage, sourceName: String): SModel = { + //val packageName = if (source.getName != null) source.getName else "" + var contents = source.eAllContents().asScala + val model = new ComplexSModel(source.getName, sourceName, source.getNsURI) println("... Converting ecore model") + println("First run creates all classes, important for abstract and interface relations") + contents.foreach { + case ec: EClass => + var sClassType = SClassType.normalClass + if (ec.isAbstract) { + sClassType = SClassType.abstactClass + } + if (ec.isInterface || PackageNames.multiInhertitanceWithTraits) { + sClassType = SClassType.normalTrait + } + STypeRegistry.addType(new SClass(ec.getName, PackageNames.sourcePkgPrefix + ec.getEPackage.getNsPrefix, sClassType), ec) + case ee: EEnum => + model.addModelEnums(new SEnumConverter convert (ee, sourceName)) + case _ => + // we only care about classes. Types will be registered as soon as they are needed as + // attributes + } + contents = source.eAllContents().asScala + println("Second run add references, attributes, and class hierarchies") contents.foreach { case ec: EClass => - model.addModelClass(new SClassConverter convert ec) - STypeRegistry.addType(SType(ec.getName, packageName)) + //println(ec) + model.addModelClass(new SClassConverter convert (ec, sourceName)) case _ => - // we only care about classes. Types will be registered as soon as they are needed as - // attributes + // we only care about classes. Types will be registered as soon as they are needed as + // attributes } println("... Conversion finished") println(s"Generated model: $model") diff --git a/src/main/scala/org/rosi_project/model_sync/generator/conversion/SModelGeneratorTest.scala b/src/main/scala/org/rosi_project/model_sync/generator/conversion/SModelGeneratorTest.scala deleted file mode 100644 index 16cee3fbd4f8dee34a5278703d94aa3dc352bc64..0000000000000000000000000000000000000000 --- a/src/main/scala/org/rosi_project/model_sync/generator/conversion/SModelGeneratorTest.scala +++ /dev/null @@ -1,21 +0,0 @@ -package org.rosi_project.model_sync.generator.conversion - -import org.eclipse.emf.ecore.{EObject, EPackage} -import org.eclipse.emf.ecore.resource.Resource -import scroll.internal.ecore.ECoreImporter - -/** - * @author Rico Bergmann - */ -object SModelGeneratorTest/* extends App */{ - - val importer = new ECoreImporter { - def lm(): Resource = loadModel() - } - importer.path = "assets/ttc17.ecore" - val res = importer.lm() - println(s"We done: $res") - - res.getContents.toArray(new Array[EObject](0)).toList.find(_.isInstanceOf[EPackage]).foreach(e => (new SModelGenerator).convert(e.asInstanceOf[EPackage])) - -} diff --git a/src/main/scala/org/rosi_project/model_sync/generator/env/FilesCompiler.scala b/src/main/scala/org/rosi_project/model_sync/generator/env/FilesCompiler.scala index 516f2859e01e910e66f57eaeef2d17b0a28f814c..706a6022af9788cad2a331bd737f4e56e7c4d2db 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/env/FilesCompiler.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/env/FilesCompiler.scala @@ -22,7 +22,7 @@ class FilesCompiler(outDir: File) { val compilationSettings: Settings = new GenericRunnerSettings(out.println) // just re-use the whole classpath compilationSettings.classpath.value = JClassPath.adaptClassPathToOSEnv(JClassPath.fetchCurrentClassPath).distinct.mkString(File.pathSeparator) - println(s"Using classpath ${compilationSettings.classpath.value}") + //println(s"Using classpath ${compilationSettings.classpath.value}") compilationSettings.outdir.value = outDir.toAbsolute.toString val reporter = new ConsoleReporter(compilationSettings) val compiler = new Global(compilationSettings, reporter) diff --git a/src/main/scala/org/rosi_project/model_sync/generator/env/JarPackager.scala b/src/main/scala/org/rosi_project/model_sync/generator/env/JarPackager.scala index 3d1478f542696ad245c92c73ba770637a9f0ad6b..4016620ae280d05834a40d38c9b54f34fc7b2278 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/env/JarPackager.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/env/JarPackager.scala @@ -30,7 +30,7 @@ class JarPackager(inputDir: File, outputDir: File, jarName: String = "model.jar" while (filesToAdd.nonEmpty) { val file = filesToAdd.head var fname = file.getAbsolutePath.replace(inputDir.jfile.getAbsolutePath + File.separator, "").replaceAll("\\\\", "/") - println(s"Adding to JAR: $fname") + //println(s"Adding to JAR: $fname") if (file.isDirectory) { if (!fname.endsWith("/")) { fname += "/" diff --git a/src/main/scala/org/rosi_project/model_sync/generator/io/SClassWriter.scala b/src/main/scala/org/rosi_project/model_sync/generator/io/SClassWriter.scala index ca1d49cefc4bcbb85b8656b7c42ac925366eb984..8609dbf491fe2587b18bcb6a66eb9cb316fbdfd5 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/io/SClassWriter.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/io/SClassWriter.scala @@ -1,71 +1,262 @@ package org.rosi_project.model_sync.generator.io -import org.rosi_project.model_sync.generator.acr_model.{SAttribute, SMethod, SClass} +import org.rosi_project.model_sync.generator.acr_model._ import org.rosi_project.model_sync.generator.support.ExtendedString.stringToExtended +import org.rosi_project.model_sync.generator.sync.PredefRsumTypes +import org.rosi_project.model_sync.generator.acr_model.types.GenericSequence +import org.rosi_project.model_sync.generator.sync.HelperFunctions +import org.rosi_project.model_sync.generator.PackageNames -/** The `Writer` generates the source code of a [[SClass]] and provides it as a `String`. - * - * @author Rico Bergmann - */ +/** + * The `Writer` generates the source code of a [[SClass]] and provides it as a `String`. + * + * @author Rico Bergmann + */ class SClassWriter(val modelClass: SClass) { + private val isView: Boolean = modelClass.isInstanceOf[SViewClass] private val pckg: String = if (modelClass.isDefaultPackage) "" else s"package ${modelClass.sPackage}" private val imports: Seq[String] = modelClass.collectImports.toSeq + private val viewImports: String = { + if (isView) { + s""" + | import ${PredefRsumTypes.VIEWTYPE_INFO_STYPE.getPackage}.${PredefRsumTypes.VIEWTYPE_INFO_STYPE.getName} + | import ${PredefRsumTypes.JOIN_INFO_STYPE.getPackage}.${PredefRsumTypes.JOIN_INFO_STYPE.getName} + | ${modelClass.asInstanceOf[SViewClass].getJoinObject().map(j => s"import ${j.joinObject.getPackage}.${j.joinObject.getName}").mkString(" \n")} + """.stripMargin + } else { + "" + } + } private val clazzFixture: String = generateClassFixture + private val internalClazzFixture: String = generateInternalClazzFixture + private val companionObject: String = generateCompanionFixture - /** Provides a source code representation of the `modelClass` as a `String`. - * - * When writing it to a file it will be able to be compiled with the `scalac` (assuming the - * ''classpath'' is set-up correctly). - */ + /** + * Provides a source code representation of the `modelClass` as a `String`. + * + * When writing it to a file it will be able to be compiled with the `scalac` (assuming the + * ''classpath'' is set-up correctly). + */ def stringify: String = { s"""$pckg | |${imports.map(i => s"import $i").mkString("\n")} + |${viewImports} + | + |/** + | * This file is automatically generated from the code generator + | * for the role-based model management framework. + | */ + |${clazzFixture} { | - |class $clazzFixture { + | ${if (PackageNames.multiInhertitanceWithTraits) s"${generateAttributeFixture}" else ""} | | ${modelClass.getAdditionalConstructorStatements.map(_.getContent).mkString("\n")} | | ${modelClass.getMethods.map(stringifyMethod).mkString("\n")} | + | ${internalClazzFixture} |} + | + |${if (isView) companionObject else ""} + | """.stripMargin } - /** Writes a method as source code. - * - * @param m the method to write - * @return the `String` representation of `m` - */ + /** + * Provides a source code representation of an internal class used as role in SCROLL. + */ + def internalStringify: String = { + s""" + |$clazzFixture { + | + | ${modelClass.getAdditionalConstructorStatements.map(_.getContent).mkString("\n")} + | + | ${modelClass.getMethods.map(stringifyMethod).mkString("\n")} + | + |} + """.stripMargin + } + + /** + * Writes a method as source code. + * + * @param m the method to write + * @return the `String` representation of `m` + */ protected def stringifyMethod(m: SMethod): String = { - s"""${if (m.overrides) "override" else ""} def ${m.name}(${m.params.map(param => s"${param.name}: ${param.getType}").mkString(", ")}): ${m.getResultType} = { - | ${m.implementation.map(_.getContent).mkString("\n")} + var result = s"""${if (m.overrides) "override " else ""}${getVisibilityString(m.getVisibility)}def ${m.getName}(${m.params.map(param => s"${param.getName}: ${param.getDeepTypeName}").mkString(", ")}): ${m.getResultType} """ + if (!m.implementation.isEmpty) { + result = result + s""" = { + | ${m.implementation.map(_.getContent).mkString("\n")} + |} + """ + } + result.stripMargin + } + + /** + * Writes the "''companion fixture''" for views. + */ + protected def generateCompanionFixture: String = { + if (isView) { + val viewClass = modelClass.asInstanceOf[SViewClass] + s""" + |/** + | * This file is automatically generated from the code generator + | * for the role-based model management framework. + | */ + |object ${modelClass.getName} extends ${PredefRsumTypes.VIEWTYPE_INFO_STYPE.getName} { + | + | override def getViewName(): String = "${modelClass.getName}" + | + | def getJoinInfos(): Set[${PredefRsumTypes.JOIN_INFO_STYPE.getName}] = ${if (viewClass.getJoinObject.isEmpty) "Set.empty" else s"Set(${viewClass.getJoinObject.map(_.joinObject.getName).mkString(", ")})"} + | + | protected def getNewInstance(): ${PredefRsumTypes.IVIEW_COMPARTMENT_STYPE.getName} = new ${modelClass.getName}() + | + | def getNewView(): ${modelClass.getName} = getNewViewTypeInstance().asInstanceOf[${modelClass.getName}] |} - """.stripMargin + """.stripMargin + } else { + "" + } + } + + /** + * Writes the internal classes. + */ + protected def generateInternalClazzFixture: String = { + var result = ""; + modelClass.getInternalClasses.foreach(intCls => { + var sw: SClassWriter = new SClassWriter(intCls) + var s = sw.internalStringify; + result = result + s + "\n"; + }) + result + } + + private def getVisibilityString(vis: MethodVisibility.Value): String = { + var visibility = "" + vis match { + case MethodVisibility.privateVis => visibility = "private " + case MethodVisibility.protectedVis => visibility = "protected " + case MethodVisibility.privateExternalClass => + if (modelClass.isInstanceOf[SInnerClass]) { + visibility = s"private[${modelClass.asInstanceOf[SInnerClass].externalClass.getName}] " + } + case _ => + } + visibility } - /** Writes the "''class fixture''", i.e. the `class` identifier followed by the constructor and - * optionally a parent class. The parent constructor will be called correctly. - */ + /** + * Generate the attribute fixtures to add them in the body. + */ + protected def generateAttributeFixture: String = { + modelClass.getStructuralFeatures.map(attr => { + val finalS: String = if (attr.isFinal) "val" else "var" + val instanziationS: String = if (attr.getTypeElement.isInstanceOf[GenericSequence]) "= Set.empty" else s"= ${HelperFunctions.classEmptyType(attr.getTypeElement.getName)}" + s"${getVisibilityString(attr.getVisibility)}${finalS} ${attr.getName}: ${attr.getTypeElement.getDeepName} ${instanziationS} \n" + }).mkString(" \n") + } + + /** + * Writes the "''class fixture''", i.e. the `class` identifier followed by the constructor and + * optionally a parent class. The parent constructor will be called correctly. + */ protected def generateClassFixture: String = { - var params: List[String] = modelClass.attributes.map(attr => s"var ${attr.name}: ${attr.getType}").toList - val parentConstructorParams: String = - if (modelClass.isRootClass) - "" - else - modelClass.parent.getConstructorParameters.map(param => s"${param.name}: ${param.getType}").mkString(", ") + //println("**************************************************") + var params: Seq[String] = modelClass.getStructuralFeatures.map(attr => { + val finalS: String = if (attr.isFinal) "val" else "var" + s"${getVisibilityString(attr.getVisibility)}${finalS} ${attr.getName}: ${attr.getTypeElement.getDeepName}" + }).toList + var baseFixture: String = "" + var parentConstructorParams: String = "" + var parentConstructor: String = "" + var allInterfaces: String = "" + val parent: STypedElement = modelClass.getClassParent + + if (!modelClass.isRootClass) { + parentConstructorParams = parent.getAllConstructorParameters.map(param => s"${constructorParamForParentConstructor(parent, param)}: ${param.getDeepTypeName}").mkString(", ") + parentConstructor = s"(${parent.getAllConstructorParameters.map(constructorParamForParentConstructor(parent, _)).mkString(", ")})" + } + + if (!modelClass.getInterfaceParents.isEmpty) { + allInterfaces = s"${modelClass.getInterfaceParents.map(namesOfInterfaces(_)).mkString(" with ")}" + } - val parentConstructor: String = if (modelClass.isRootClass) "" else s"(${modelClass.parent.getConstructorParameters.map(_.name).toList.mkString(", ")})" + if (parentConstructorParams != "") { + params = params :+ parentConstructorParams + } - if (parentConstructorParams != "") - params ::= parentConstructorParams + val constructor: String = if (params.isEmpty) "" else s"(${params.mkString(", ")})" - val constructor = s"(${params.mkString(", ")})" - val baseFixture = s"${modelClass.getName}$constructor" + if (modelClass.isInterface) { + baseFixture = s"trait ${modelClass.getName}" + } else if (modelClass.isObject) { + baseFixture = s"object ${modelClass.getName}" + } else { + baseFixture = s"class ${modelClass.getName}" + if (!PackageNames.multiInhertitanceWithTraits) { + baseFixture = s"$baseFixture$constructor" + } + if (modelClass.isAbstract) { + baseFixture = s"abstract $baseFixture" + } + } + + if (modelClass.isRootClass) { + if (allInterfaces != "") { + if (isView) { + baseFixture = s"$baseFixture private" + } + baseFixture = s"$baseFixture extends $allInterfaces" + } + } else { + baseFixture = s"$baseFixture extends ${parent.getName}" + if (!PackageNames.multiInhertitanceWithTraits) { + baseFixture = s"${baseFixture}${parentConstructor}" + } + if (allInterfaces != "") { + baseFixture = s"$baseFixture with $allInterfaces" + } + } + baseFixture + } + + /** + * Generates a ''class parameter's'' name that will be used to initialize a field of the super class. + * + * This is purely to prevent naming conflicts and shadowing when trying to access a parent's field + * from the subclass. + */ + private def constructorParamForParentConstructor(parent: STypedElement, param: SMethodParameter): String = { + var parName = s"${parent.getName.head.toLower}_${param.getName.firstLetterToUpperCase}" + + // we need to make sure that the generate name does not by chance appear as a regular attribute + // of the model class. If this is the case we add some number to make it unique again. + if (modelClass.getDeepStructuralFeatures.exists(_.getName == parName)) { + var uniqueIdx = 2 + var uniqueParName = parName + uniqueIdx + + while (modelClass.getDeepStructuralFeatures.exists(_.getName == uniqueParName)) { + uniqueIdx += 1 + uniqueParName = parName + uniqueIdx + } + + parName = uniqueParName + } + + parName + } - if (modelClass.isRootClass) baseFixture else s"$baseFixture extends ${modelClass.parent.getName}$parentConstructor" + /** + * Returns the name of the interface. + */ + private def namesOfInterfaces(interface: STypedElement): String = { + interface.getName } } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/io/SEnumWriter.scala b/src/main/scala/org/rosi_project/model_sync/generator/io/SEnumWriter.scala new file mode 100644 index 0000000000000000000000000000000000000000..b9e21dc5fccb925f2a6a86c0483267cebc0a4034 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/io/SEnumWriter.scala @@ -0,0 +1,28 @@ +package org.rosi_project.model_sync.generator.io + +import org.rosi_project.model_sync.generator.acr_model.SEnum + +class SEnumWriter(val modelEnum: SEnum) { + + private val pckg: String = if (modelEnum.isDefaultPackage) "" else s"package ${modelEnum.sPackage}" + + /** Provides a source code representation of the `modelEnums` as a `String`. + * + * When writing it to a file it will be able to be compiled with the `scalac` (assuming the + * ''classpath'' is set-up correctly). + */ + def stringify: String = { + s"""$pckg + | + |/** + | * This file is automatically generated from the code generator + | * for the role-based model management framework. + | */ + |object ${modelEnum.getName} extends Enumeration { + | + | val ${modelEnum.enums.mkString(", ")} = Value + |} + | + """.stripMargin + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/io/SModelFSWriter.scala b/src/main/scala/org/rosi_project/model_sync/generator/io/SModelFSWriter.scala index 5a42da3e582afb901a5f5bcca1955b888d58f829..b63bda8d1453df724e9482ce7cb71f4ae7c9a139 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/io/SModelFSWriter.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/io/SModelFSWriter.scala @@ -8,6 +8,8 @@ import org.rosi_project.model_sync.generator.acr_model._ import org.rosi_project.model_sync.generator.env.{FilesCompiler, JarPackager} import scala.reflect.io.{Directory, File, Path} +import org.rosi_project.model_sync.generator.GeneratorConfig +import org.rosi_project.model_sync.generator.Creation /** The `FSWriter` writes a [[SModel]] as a single compiled ''JAR'' file to the File System. * @@ -18,10 +20,11 @@ import scala.reflect.io.{Directory, File, Path} * @author Rico Bergmann */ class SModelFSWriter( + generatorConfig: GeneratorConfig, workingDir: File = File(Files.createTempDirectory("model").toFile), outputDir: Directory = File("output").toDirectory, keepClassFiles: Boolean = false, - modelCfg: ModelConfig, + modelCfgs: Set[ModelConfig], currentDir: jio.File = new jio.File("").getAbsoluteFile) extends SModelVisitor { workingDir.jfile.mkdirs() @@ -33,13 +36,21 @@ class SModelFSWriter( println(s"Output dir is $outputDir") println("... Copying model images") - private var images: List[jio.File] = _ + private var images: List[jio.File] = List.empty private var imagesTargetDir: jio.File = _ - try { - images = collectAllModelImages(modelCfg, currentDir) + try { + if (modelCfgs.isEmpty) { + //TODO: get files with same source Name + images = List.empty + } else { + modelCfgs.foreach(con => { + images = images ++ collectAllModelImages(con, currentDir) + }) + } imagesTargetDir = new jio.File(workingDir.toAbsolute.toString() + File.separator + "res") imagesTargetDir.mkdirs() images.foreach(img => { + //println("##########Images: " + img.getName) Files.copy(img.toPath, imagesTargetDir.toPath.resolve(img.getName), StandardCopyOption.REPLACE_EXISTING) }) } catch { @@ -48,7 +59,15 @@ class SModelFSWriter( override def visit(sModel: SModel): Unit = { - println(s"... Wrote files (sources) $sFilesToCompile") + sModel.getModelEnums.foreach(writeEnum(_)) + sModel.getModelClasses.foreach(writeClass(_)) + sModel.getProviderClasses.foreach(writeClass(_)) + if (generatorConfig.create != Creation.rolesync) { + sModel.getJoinClasses.foreach(writeClass(_)) + sModel.getRelationalCompartments.foreach(writeClass(_)) + sModel.getViewCompartments.foreach(writeClass(_)) + } + //println(s"... Wrote files (sources) $sFilesToCompile") println("... Starting compilation") new FilesCompiler(workingDir).run(sFilesToCompile) @@ -64,14 +83,31 @@ class SModelFSWriter( } println("... Generating JAR") - new JarPackager(workingDir, outputDir.toFile).run() - println("... Done") + println(s"... Successfully wrote JAR ${outputDir + File.separator + generatorConfig.getCombinedEcoreName + ".jar"}") + new JarPackager(workingDir, outputDir.toFile, generatorConfig.getCombinedEcoreName + ".jar").run() + println(s"... Successfully wrote JAR ${outputDir + File.separator + generatorConfig.getCombinedEcoreName + ".jar"}") } + + private def writeEnum(sEnum: SEnum): Unit = { + try { + println(s"Writing class $sEnum") + val classNameWithPath = workingDir.toAbsolute.toString() + File.separator + pckg2Path(sEnum.getPackage) + File.separator + s"${sEnum.getName}.scala" + val writer = new SEnumWriter(sEnum) - override def visit(sClass: SClass): Unit = { + val classFile = File(classNameWithPath) + + classFile.jfile.getParentFile.mkdirs() + classFile.writeAll(writer.stringify) + sFilesToCompile ::= classFile + } catch { + case e: Exception => throw new ClassWritingException(e) + } + } + + private def writeClass(sClass: SClass): Unit = { try { println(s"Writing class $sClass") - val classNameWithPath = workingDir.toAbsolute.toString() + File.separator + pckg2Path(sClass.getPackage) + File.separator + s"${sClass.name}.scala" + val classNameWithPath = workingDir.toAbsolute.toString() + File.separator + pckg2Path(sClass.getPackage) + File.separator + s"${sClass.getName}.scala" val writer = new SClassWriter(sClass) val classFile = File(classNameWithPath) @@ -84,9 +120,17 @@ class SModelFSWriter( } } + override def visit(sClass: SClass): Unit = { + // pass + } + override def visit(sAttr: SAttribute): Unit = { // pass } + + override def visit(sRef: SReference): Unit = { + // pass + } override def visit(sMethod: SMethod): Unit = { // pass @@ -124,7 +168,7 @@ class SModelFSWriter( }) }) }) - + println(modelConfig + " I: " + images) images } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/BasicTypeGetterSetterGeneratingVisitor.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/BasicTypeGetterSetterGeneratingVisitor.scala new file mode 100644 index 0000000000000000000000000000000000000000..1bdfde2ce77c1798744658895d18b61bac7f206c --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/BasicTypeGetterSetterGeneratingVisitor.scala @@ -0,0 +1,39 @@ +package org.rosi_project.model_sync.generator.sync + +import org.rosi_project.model_sync.generator.acr_model._ + +class BasicTypeGetterSetterGeneratingVisitor extends SModelVisitor { + + override def visit(sModel: SModel): Unit = { + sModel.getModelClasses.foreach(cls => { + //add all getter and setter for each normal attribute + cls.getAttributes.foreach(attr => { + attr.setVisibility(MethodVisibility.protectedVis) + val getter = new SGetter(attr) + val setter = new SSetter(attr) + cls.addMethod(getter) + cls.addMethod(setter) + }) + }) + } + + override def visit(sClass: SClass): Unit = { + // pass + } + + override def visit(sAttr: SAttribute): Unit = { + // pass + } + + override def visit(sRef: SReference): Unit = { + // pass + } + + override def visit(sMethod: SMethod): Unit = { + // pass + } + + override def visit(sType: SType): Unit = { + // pass + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/GenerateQueryHelperVisitor.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/GenerateQueryHelperVisitor.scala new file mode 100644 index 0000000000000000000000000000000000000000..3018c8f3b324af53276385c1aab3baeb164f4f0a --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/GenerateQueryHelperVisitor.scala @@ -0,0 +1,48 @@ +package org.rosi_project.model_sync.generator.sync + +import org.rosi_project.model_sync.generator.acr_model._ +import org.rosi_project.model_sync.generator.acr_model.types.PredefTypes +import org.rosi_project.model_sync.generator.PackageNames + +class GenerateQueryHelperVisitor extends SModelVisitor { + + override def visit(sModel: SModel): Unit = { + var newClasses: Set[SClass] = Set.empty + //iterate over all abstract classes or interfaces + sModel.getModelClasses.foreach(cls => { + if (cls.isAbstract || cls.isInterface) { + val newClass = new SClass(PackageNames.queryHelperPrefix + cls.getName, cls.getPackage) + newClass.addParent(cls) + newClass.addParent(PredefRsumTypes.QUERY_HELPER_STYPE) + newClass.addMethod(new SMethod( + name = "equals", + result = PredefTypes.Boolean, + params = Seq(SMethodParameter("that", PredefTypes.Any)), + implementation = Seq(SMethodStatement(content = s"that.isInstanceOf[${cls.getName}]", usedTypes = Set.empty)), + true)) + newClasses += newClass + } + }) + newClasses.foreach(sModel.addModelClass(_)) + } + + override def visit(sClass: SClass): Unit = { + // pass + } + + override def visit(sAttr: SAttribute): Unit = { + // pass + } + + override def visit(sRef: SReference): Unit = { + // pass + } + + override def visit(sMethod: SMethod): Unit = { + // pass + } + + override def visit(sType: SType): Unit = { + // pass + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/GetterSetterGeneratingVisitor.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/GetterSetterGeneratingVisitor.scala index dd6fd38c5c7cc1da67789de45328b9a876637bfb..b9285aaa2d94636ebd428c2348c8d959b85ef84e 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/sync/GetterSetterGeneratingVisitor.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/GetterSetterGeneratingVisitor.scala @@ -1,30 +1,47 @@ package org.rosi_project.model_sync.generator.sync + import org.rosi_project.model_sync.generator.acr_model._ +import org.rosi_project.model_sync.generator.acr_model.types.GenericSequence -/** Service to extend [[SClass SClasses]] with getter and setter methods for all attributes. - * - * @author Rico Bergmann - */ +/** + * Service to extend [[SClass SClasses]] with getter and setter methods for all attributes. + * + * @author Rico Bergmann + */ class GetterSetterGeneratingVisitor extends SModelVisitor { override def visit(sModel: SModel): Unit = { - // pass + sModel.getModelClasses.foreach(cls => { + //add all getter and setter for all structural features + cls.getStructuralFeatures.foreach(attr => { + attr.setVisibility(MethodVisibility.protectedVis) + val getter = new SGetter(attr) + cls.addMethod(getter) + if (attr.getTypeElement.isInstanceOf[GenericSequence]) { + val adder = new SSetterAdd(attr, attr.getTypeElement.asInstanceOf[GenericSequence].typeParam) + cls.addMethod(adder) + val remover = new SSetterRemove(attr, attr.getTypeElement.asInstanceOf[GenericSequence].typeParam) + cls.addMethod(remover) + } else { + val setter = new SSetter(attr) + cls.addMethod(setter) + } + }) + }) } override def visit(sClass: SClass): Unit = { - sClass.attributes.foreach(attr => { - val getter = new SGetter(attr) - val setter = new SSetter(attr) - sClass.addMethod(getter) - sClass.addMethod(setter) - }) - + // pass } override def visit(sAttr: SAttribute): Unit = { // pass } + override def visit(sRef: SReference): Unit = { + // pass + } + override def visit(sMethod: SMethod): Unit = { // pass } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/HelperFunctions.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/HelperFunctions.scala new file mode 100644 index 0000000000000000000000000000000000000000..7b00cf31870c5011bd1ed7cdc3572e5ffe196f14 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/HelperFunctions.scala @@ -0,0 +1,37 @@ +package org.rosi_project.model_sync.generator.sync + +import org.rosi_project.model_sync.generator.acr_model._ +import org.rosi_project.model_sync.generator.support.ExtendedString.stringToExtended + +object HelperFunctions { + def classNameCreation(t: STypedElement): String = s"className.isInstanceOf[${t.getName}]" + + def initialAttributeDoing(mp: SMethodParameter, sfs: Seq[SStructuralFeature]): String = { + sfs.foreach(s => { + if (s.getName == mp.getName) { + return mp.getName + } + }) + return classEmptyConstructorParameterCreation(mp) + } + + def attributeEqualCreation(a: SStructuralFeature): String = s"base.get${a.getName.firstLetterToUpperCase}() == other.get${a.getName.firstLetterToUpperCase}()" + + def classEmptyConstructorParameterCreation(t: SMethodParameter): String = { + classEmptyType(t.getTypeName) + } + + def classEmptyType(s: String): String = { + s match { + case "Boolean" => return "false" + case "Double" => return "0" + case "Float" => return "0" + case "Long" => return "0" + case "Integer" => return "0" + case "Int" => return "0" + case "Short" => return "0" + case "Byte" => return "0" + case _ => return "null" + } + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/Imports.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/Imports.scala deleted file mode 100644 index bf4ba3cf8cda50fdef4ec5f8b52bc201d1ae2d78..0000000000000000000000000000000000000000 --- a/src/main/scala/org/rosi_project/model_sync/generator/sync/Imports.scala +++ /dev/null @@ -1,15 +0,0 @@ -package org.rosi_project.model_sync.generator.sync - -import org.rosi_project.model_sync.generator.acr_model.SImport - -/** Contains a number of imports which are used throughout the sync infrastructure. - * - * @author Rico Bergmann - */ -object Imports { - - /** Import for the `ModelRegistry` type. - */ - val ModelRegistry = SImport(PredefTypes.ModelRegistry.sPackage, PredefTypes.ModelRegistry.name) - -} diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/InstanceCombiGenerator.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/InstanceCombiGenerator.scala new file mode 100644 index 0000000000000000000000000000000000000000..73a31185eb74b6b2a5a20cf56a1e57aab299d143 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/InstanceCombiGenerator.scala @@ -0,0 +1,126 @@ +package org.rosi_project.model_sync.generator.sync + +import scala.collection.JavaConverters._ +import org.rosi_project.model_sync.generator.acr_model._ +import org.rosi_project.model_sync.generator.util.ClassAndInstance +import org.eclipse.emf.ecore.EObject +import org.rosi_project.model_sync.generator.util.InstanceLine +import org.rosi_project.model_sync.generator.acr_model.types.PredefTypes +import org.eclipse.emf.ecore.EStructuralFeature +import org.eclipse.emf.common.util.EList +import org.rosi_project.model_sync.util.EMFUtilForGenerator +import java.util.List +import org.rosi_project.model_sync.generator.PackageNames + +class InstanceCombiGenerator(val clsins: ClassAndInstance) extends SModelVisitor { + + override def visit(sModel: SModel): Unit = { + //println("++++++++++++++++++++++++++++++++++++++++++++++") + val example = new SClass("ExampleCombiCase", PackageNames.examplePkgName, SClassType.normalObject) + val contents = clsins.obj.eAllContents().asScala + var counter = 0 + var lines: Seq[InstanceLine] = Seq.empty + var generationLines: Seq[InstanceLine] = Seq.empty + var sType = STypeRegistry.getFromClass(clsins.obj.eClass()) + if (sType != null) { + lines = lines :+ new InstanceLine(counter, clsins.obj, sType) + counter += 1 + } + contents.foreach(o => { + sType = STypeRegistry.getFromClass(o.eClass()) + if (sType != null) { + lines = lines :+ new InstanceLine(counter, o, sType) + counter += 1 + } + }) + //add values for instances + lines.foreach(l => { + l.usedType.getAllConstructorParameters.foreach(cp => { + if (!STypeRegistry.isDefaultType(cp.getType.getName)) { + val structs: Seq[EStructuralFeature] = l.obj.eClass().getEAllStructuralFeatures.asScala + structs.foreach(att => { + if (att.getName == cp.getName) { + val obj = l.obj.eGet(att) + if (obj.isInstanceOf[EObject]) { + lines.foreach(lnow => { + if (lnow.obj == obj.asInstanceOf[EObject]) { + //println("Found: " + lnow.counter) .filter(_.isInstanceOf[SRelationalCompartmentClass]) + sModel.getRelationalCompartments.foreach(rc => { + val realRc = rc.asInstanceOf[SRelationalCompartmentClass] + //println(" AN: " + att.getName + " l1: " + l.usedType.getName + " l2: " + lnow.usedType.getName + " RC: " + realRc.connectedRef.getName + " SN: " + realRc.sClass.getName + " TN: " + realRc.tClass.getName) + if (realRc.connectedRef.getName == att.getName && l.usedType.proofHierarchicalEquality(realRc.sClass) && lnow.usedType.proofHierarchicalEquality(realRc.tClass)) { + val s = s"(new ${realRc.getName}(${l.getName()}, ${lnow.getName()})).initialize()" + generationLines = generationLines :+ new InstanceLine(0, null, realRc, s) + } + }) + } + }) + } else { + val listi: List[EObject] = EMFUtilForGenerator.getList(obj) + val liste = listi.asScala + liste.foreach(eo => { + lines.foreach(lnow => { + if (lnow.obj == eo) { + sModel.getRelationalCompartments.foreach(rc => { + val realRc = rc.asInstanceOf[SRelationalCompartmentClass] + //println(" AN: " + att.getName + " l1: " + l.usedType.getName + " l2: " + lnow.usedType.getName + " RC: " + realRc.connectedRef.getName + " SN: " + realRc.sClass.getName + " TN: " + realRc.tClass.getName) + if (realRc.connectedRef.getName == att.getName && l.usedType.proofHierarchicalEquality(realRc.sClass) && lnow.usedType.proofHierarchicalEquality(realRc.tClass)) { + val s = s"(new ${realRc.getName}(${l.getName()}, ${lnow.getName()})).initialize()" + generationLines = generationLines :+ new InstanceLine(0, null, realRc, s) + } + }) + } + }) + }) + } + } + }) + } + }) + }) + + //construction of instances + lines.foreach(l => { + example.augmentConstructor(new SMethodStatement(l.getLine(), Set(l.usedType))) + }) + + //construction of connections + generationLines.foreach(l => { + example.augmentConstructor(new SMethodStatement(l.getLine(), Set(l.usedType))) + }) + + + example.addParent(PredefTypes.App) + sModel.addProviderClass(example) + } + + def setValues(eo: EObject, lines: Seq[InstanceLine]): String = { + lines.foreach(lnow => { + if (lnow.obj == eo) { + return lnow.getName() + } + }) + "" + } + + override def visit(sClass: SClass): Unit = { + // pass + } + + override def visit(sAttr: SAttribute): Unit = { + // pass + } + + override def visit(sRef: SReference): Unit = { + // pass + } + + override def visit(sMethod: SMethod): Unit = { + // pass + } + + override def visit(sType: SType): Unit = { + // pass + } + +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/InstanceGenerator.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/InstanceGenerator.scala new file mode 100644 index 0000000000000000000000000000000000000000..241f424cb0c2c1baa56978180d6199e17b76e66c --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/InstanceGenerator.scala @@ -0,0 +1,108 @@ +package org.rosi_project.model_sync.generator.sync + +import scala.collection.JavaConverters._ +import org.rosi_project.model_sync.generator.acr_model._ +import org.rosi_project.model_sync.generator.util.ClassAndInstance +import org.eclipse.emf.ecore.EObject +import org.rosi_project.model_sync.generator.util.InstanceLine +import org.rosi_project.model_sync.generator.acr_model.types.PredefTypes +import org.eclipse.emf.ecore.EStructuralFeature +import org.eclipse.emf.common.util.EList +import org.rosi_project.model_sync.util.EMFUtilForGenerator +import java.util.List +import org.rosi_project.model_sync.generator.PackageNames + +/** + * Service to create an instance creation object. + * + * @author Christopher Werner + */ +class InstanceGenerator(val clsins: ClassAndInstance) extends SModelVisitor { + + override def visit(sModel: SModel): Unit = { + //println("++++++++++++++++++++++++++++++++++++++++++++++") + val example = new SClass("ExampleCase", PackageNames.examplePkgName, SClassType.normalObject) + val contents = clsins.obj.eAllContents().asScala + var counter = 0 + var lines: Seq[InstanceLine] = Seq.empty + var sType = STypeRegistry.getFromClass(clsins.obj.eClass()) + if (sType != null) { + lines = lines :+ new InstanceLine(counter, clsins.obj, sType) + counter += 1 + } + contents.foreach(o => { + sType = STypeRegistry.getFromClass(o.eClass()) + if (sType != null) { + lines = lines :+ new InstanceLine(counter, o, sType) + counter += 1 + } + }) + //construction of instances + lines.foreach(l => { + example.augmentConstructor(new SMethodStatement(l.getLine(), Set(l.usedType))) + }) + //add values for instances + lines.foreach(l => { + l.usedType.getAllConstructorParameters.foreach(cp => { + if (!STypeRegistry.isDefaultType(cp.getType.getName)) { + var structs: Seq[EStructuralFeature] = l.obj.eClass().getEAllStructuralFeatures.asScala + structs.foreach(att => { + if (att.getName == cp.getName) { + val obj = l.obj.eGet(att) + //println("### " + att.getName) + if (obj.isInstanceOf[EObject]) { + lines.foreach(lnow => { + if (lnow.obj == obj.asInstanceOf[EObject]) { + //println("Found: " + lnow.counter) + var s = s"${l.getName()}.set${att.getName.capitalize}(${lnow.getName()})" + example.augmentConstructor(new SMethodStatement(s)) + } + }) + } else { + val listi: List[EObject] = EMFUtilForGenerator.getList(obj) + val liste = listi.asScala + val s = s"${l.getName()}.set${att.getName.capitalize}(Set(${liste.map(setValues(_, lines)).mkString(", ")}))" + example.augmentConstructor(new SMethodStatement(s)) + } + } + }) + } + }) + }) + example.addParent(PredefTypes.App) + sModel.addProviderClass(example) + //println("++++++++++++++++++++++++++++++++++++++++++++++") + // pass + + } + + def setValues(eo: EObject, lines: Seq[InstanceLine]): String = { + lines.foreach(lnow => { + if (lnow.obj == eo) { + return lnow.getName() + } + }) + "" + } + + override def visit(sClass: SClass): Unit = { + // pass + } + + override def visit(sAttr: SAttribute): Unit = { + // pass + } + + override def visit(sRef: SReference): Unit = { + // pass + } + + override def visit(sMethod: SMethod): Unit = { + // pass + } + + override def visit(sType: SType): Unit = { + // pass + } + +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/JoinGeneratingVisitor.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/JoinGeneratingVisitor.scala new file mode 100644 index 0000000000000000000000000000000000000000..d3c9b884e1cfae0040219ce86bb14d2f93adf5eb --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/JoinGeneratingVisitor.scala @@ -0,0 +1,152 @@ +package org.rosi_project.model_sync.generator.sync + +import org.rosi_project.model_sync.generator.acr_model._ +import org.rosi_project.model_sync.model_join.representation.grammar.ModelJoinExpression +import org.rosi_project.model_management.sum.join.RsumJoinType +import org.rosi_project.model_sync.model_join.representation.grammar.JoinExpression.JoinType +import org.rosi_project.model_sync.model_join.representation.grammar.ThetaJoinExpression + +class JoinGeneratingVisitor(joinExpression: ModelJoinExpression) extends SModelVisitor { + + override def visit(sModel: SModel): Unit = { + + joinExpression.getJoins.forEach(j => { + println("Type: " + j.getType + " Base: " + j.getBaseModel.getResourcePath + " " + j.getBaseModel.getResourceName + " Other: " + j.getOtherModel + " Target: " + j.getTarget) + println(j) + j.getKeeps.forEach(k => { + println(k) + }) + }) + + joinExpression.getJoins.forEach(j => { + val baseType: Option[STypedElement] = STypeRegistry.query(j.getBaseModel().getResourceName, j.getBaseModel().getResourcePath) + val otherType: Option[STypedElement] = STypeRegistry.query(j.getOtherModel().getResourceName, j.getOtherModel().getResourcePath) + var targetType: Option[STypedElement] = STypeRegistry.query(j.getTarget().getResourceName, j.getTarget().getResourcePath) + + println("B: " + baseType + " O: " + otherType + " T: " + targetType + " Same: " + j.isSameElement) + + if (j.isSameElement || baseType.isEmpty || otherType.isEmpty || !targetType.isEmpty) { + return + } + + val baseClass = baseType.get.asInstanceOf[SClass] + val otherClass = otherType.get.asInstanceOf[SClass] + + var rsumJoinType = RsumJoinType.natural + var compareString: String = null + + j.getType match { + case JoinType.NATURAL => rsumJoinType = RsumJoinType.natural + case JoinType.OUTER => rsumJoinType = RsumJoinType.outer + case JoinType.THETA => + rsumJoinType = RsumJoinType.theta + compareString = j.asInstanceOf[ThetaJoinExpression].getCondition.get + } + + var otherAttsBase: Set[SStructuralFeature] = Set.empty + var otherAttsOther: Set[SStructuralFeature] = Set.empty + var joinAtts: Set[SStructuralFeature] = Set.empty + + baseClass.getDeepStructuralFeatures.foreach(ba => { + var foundOne = false + otherClass.getDeepStructuralFeatures.foreach(oa => { + if (oa.getName == ba.getName && oa.getTypeElement.getName == ba.getTypeElement.getName) { + joinAtts += ba + foundOne = true + } + }) + if (!foundOne) { + otherAttsBase += ba + } + }) + + otherClass.getDeepStructuralFeatures.foreach(oa => { + var foundOne = false + joinAtts.foreach(ba => { + if (oa.getName == ba.getName && oa.getTypeElement.getName == ba.getTypeElement.getName) { + foundOne = true + } + }) + if (!foundOne) { + otherAttsOther += oa + } + }) + + println("J: " + joinAtts + " T: " + rsumJoinType) + println("B: " + otherAttsBase) + println("O: " + otherAttsOther) + + val joinObject = new SClass(j.getTarget().getResourceName + "Object", j.getTarget().getResourcePath, SClassType.normalObject) + val joinClass = new SJoinClass(j.getTarget().getResourceName, j.getTarget().getResourcePath, + base = baseClass, other = otherClass, joinType = rsumJoinType, + joinAttributes = joinAtts, innerAttributes = joinAtts ++ otherAttsBase ++ otherAttsOther, joinObject) + + //add parents + joinClass.addParent(PredefRsumTypes.IJOIN_COMPARTMENT_STYPE) + joinObject.addParent(PredefRsumTypes.JOIN_INFO_STYPE) + + //add functions to the join object + joinObject.addMethod(JoinMethods.getJoinTypeMethod(j.getType)) + joinObject.addMethod(JoinMethods.getInstanceBaseModelMethod(baseClass)) + joinObject.addMethod(JoinMethods.getInstanceOtherModelMethod(otherClass)) + joinObject.addMethod(JoinMethods.getNewInstanceMethod(joinClass)) + joinObject.addMethod(JoinMethods.getInstanceOfMethod(joinClass)) + joinObject.addMethod(JoinMethods.getMatchMethod(baseClass, otherClass, joinAtts, compareString)) + joinObject.addMethod(ToStringMethods.onlyStringToStringMethod(joinObject.getName)) + + //add functions to the join class + val attributesJoinClass = Seq(new SAttribute("base", baseClass), new SAttribute("other", otherClass)) + attributesJoinClass.foreach(a => { + a.setVisibility(MethodVisibility.privateVis) + a.isFinal = true + }) + + joinClass.setAttributes(attributesJoinClass) + //add base functions + joinClass.augmentConstructor(new SMethodStatement("initialize(base, other)", Set())) + joinClass.addMethod(JoinMethods.getJoinInfoMethod(joinObject)) + //add getter and setter functions + joinAtts.foreach(a => { + joinClass.addMethod(JoinMethods.getBaseAttributeGetter(a)) + joinClass.addMethod(JoinMethods.getMixedAttributeSetter(a)) + }) + otherAttsBase.foreach(a => { + joinClass.addMethod(JoinMethods.getBaseAttributeGetter(a)) + joinClass.addMethod(JoinMethods.getBaseAttributeSetter(a)) + }) + otherAttsOther.foreach(a => { + joinClass.addMethod(JoinMethods.getOtherAttributeGetter(a)) + joinClass.addMethod(JoinMethods.getOtherAttributeSetter(a)) + }) + //add to String method + joinClass.addMethod(ToStringMethods.joinToStringMethod(joinClass.getName)) + + sModel.addJoinClass(joinClass) + sModel.addJoinClass(joinObject) + + //add in Type Registry + STypeRegistry.addType(joinClass, null) + }) + } + + override def visit(sClass: SClass): Unit = { + // pass + } + + override def visit(sAttr: SAttribute): Unit = { + // pass + } + + override def visit(sMethod: SMethod): Unit = { + // pass + } + + override def visit(sType: SType): Unit = { + // pass + } + + override def visit(sRef: SReference): Unit = { + // pass + } + +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/JoinMethods.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/JoinMethods.scala new file mode 100644 index 0000000000000000000000000000000000000000..335b5b3e9e001d16227442c17fb385bb994e0dda --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/JoinMethods.scala @@ -0,0 +1,137 @@ +package org.rosi_project.model_sync.generator.sync + +import org.rosi_project.model_sync.generator.acr_model._ +import org.rosi_project.model_sync.model_join.representation.grammar.JoinExpression.JoinType +import org.rosi_project.model_sync.generator.acr_model.types.PredefTypes +import org.rosi_project.model_sync.generator.support.ExtendedString.stringToExtended + +object JoinMethods { + + //JOIN OBJECT METHODS + def getJoinTypeMethod(joinType: JoinType): SMethod = { + val met = new SMethod( + name = "getJoinType", + result = PredefRsumTypes.RSUM_JOIN_TYPE_STYPE, + params = Seq.empty, + implementation = Seq()) + if (joinType == JoinType.NATURAL) { + met.implementation = Seq(SMethodStatement(content = s"RsumJoinType.natural", usedTypes = Set())) + } + if (joinType == JoinType.OUTER) { + met.implementation = Seq(SMethodStatement(content = s"RsumJoinType.outer", usedTypes = Set())) + } + if (joinType == JoinType.THETA) { + met.implementation = Seq(SMethodStatement(content = s"RsumJoinType.theta", usedTypes = Set())) + } + met + } + + def getInstanceBaseModelMethod(cls: SClass): SMethod = { + new SMethod( + name = "isInstanceBaseModel", + result = PredefTypes.Boolean, + params = Seq(SMethodParameter("obj", PredefTypes.Object)), + implementation = Seq(SMethodStatement(content = s"obj.isInstanceOf[${cls.getName}]", usedTypes = Set(cls)))) + } + + def getInstanceOtherModelMethod(cls: SClass): SMethod = { + new SMethod( + name = "isInstanceOtherModel", + result = PredefTypes.Boolean, + params = Seq(SMethodParameter("obj", PredefTypes.Object)), + implementation = Seq(SMethodStatement(content = s"obj.isInstanceOf[${cls.getName}]", usedTypes = Set(cls)))) + } + + def getInstanceOfMethod(cls: SClass): SMethod = { + new SMethod( + name = "isInstanceOf", + result = PredefTypes.Boolean, + params = Seq(SMethodParameter("obj", PredefTypes.Object)), + implementation = Seq(SMethodStatement(content = s"obj.isInstanceOf[${cls.getName}]", usedTypes = Set(cls)))) + } + + def getNewInstanceMethod(cls: SClass): SMethod = { + new SMethod( + name = "getNewInstance", + result = PredefRsumTypes.IJOIN_COMPARTMENT_STYPE, + params = Seq(SMethodParameter("b", PredefTypes.Object), SMethodParameter("o", PredefTypes.Object)), + implementation = Seq(SMethodStatement(content = s"val j = new ${cls.getName}(null, null)", usedTypes = Set(cls)), + SMethodStatement(content = "objectInitialize(j, b, o)", usedTypes = Set()), + SMethodStatement(content = "j", usedTypes = Set()))) + } + + def getMatchMethod(base: SClass, other: SClass, joinAtts: Set[SStructuralFeature], joinString: String): SMethod = { + val met = new SMethod( + name = "matchTwoObjects", + result = PredefTypes.Boolean, + params = Seq(SMethodParameter("b", PredefTypes.Object), SMethodParameter("o", PredefTypes.Object)), + implementation = Seq()) + met.implementation = Seq(SMethodStatement(content = s"val base = b.asInstanceOf[${base.getName}]", usedTypes = Set(base)), + SMethodStatement(content = s"val other = o.asInstanceOf[${other.getName}]", usedTypes = Set(other))) + if (joinString == null) { + met.implementation = met.implementation :+ SMethodStatement(content = s"${joinAtts.map(HelperFunctions.attributeEqualCreation(_)).mkString(" && ")}") + } else { + met.implementation = met.implementation :+ SMethodStatement(content = joinString) + } + met + } + + //JOIN CLASS METHODS + def getJoinInfoMethod(obj: SClass): SMethod = { + new SMethod( + name = "getJoinInfo", + result = PredefRsumTypes.JOIN_INFO_STYPE, + params = Seq.empty, + implementation = Seq(SMethodStatement(content = s"${obj.getName}", usedTypes = Set(obj)))) + } + + //GETTER + def getBaseAttributeGetter(struc: SStructuralFeature): SMethod = { + new SMethod( + name = s"get${struc.getName.firstLetterToUpperCase}", + result = struc.getTypeElement, + params = Seq.empty, + implementation = Seq(SMethodStatement(content = s"+baseRole get${struc.getName.firstLetterToUpperCase}()", usedTypes = Set(struc.getTypeElement)))) + } + + def getOtherAttributeGetter(struc: SStructuralFeature): SMethod = { + new SMethod( + name = s"get${struc.getName.firstLetterToUpperCase}", + result = struc.getTypeElement, + params = Seq.empty, + implementation = Seq(SMethodStatement(content = "if (otherObj != null) {", usedTypes = Set()), + SMethodStatement(content = s"return +otherRole get${struc.getName.firstLetterToUpperCase}()", usedTypes = Set(struc.getTypeElement)), + SMethodStatement(content = "}", usedTypes = Set()), + SMethodStatement(content = s"return ${HelperFunctions.classEmptyType(struc.getTypeElement.getName)}", usedTypes = Set()))) + } + + //SETTER + def getBaseAttributeSetter(struc: SStructuralFeature): SMethod = { + new SMethod( + name = s"set${struc.getName.firstLetterToUpperCase}", + result = PredefTypes.Unit, + params = Seq(SMethodParameter(struc.getName.toLowerCase(), struc.getTypeElement)), + implementation = Seq(SMethodStatement(content = s"+baseRole set${struc.getName.firstLetterToUpperCase}(${struc.getName.toLowerCase()})", usedTypes = Set(struc.getTypeElement)))) + } + + def getMixedAttributeSetter(struc: SStructuralFeature): SMethod = { + new SMethod( + name = s"set${struc.getName.firstLetterToUpperCase}View", + result = PredefTypes.Unit, + params = Seq(SMethodParameter(struc.getName.toLowerCase(), struc.getTypeElement)), + implementation = Seq(SMethodStatement(content = s"+baseRole set${struc.getName.firstLetterToUpperCase}(${struc.getName.toLowerCase()})", usedTypes = Set(struc.getTypeElement)), + SMethodStatement(content = "if (otherObj != null) {", usedTypes = Set()), + SMethodStatement(content = s"+otherRole set${struc.getName.firstLetterToUpperCase}(${struc.getName.toLowerCase()})", usedTypes = Set(struc.getTypeElement)), + SMethodStatement(content = "}", usedTypes = Set.empty))) + } + + def getOtherAttributeSetter(struc: SStructuralFeature): SMethod = { + new SMethod( + name = s"set${struc.getName.firstLetterToUpperCase}View", + result = PredefTypes.Unit, + params = Seq(SMethodParameter(struc.getName.toLowerCase(), struc.getTypeElement)), + implementation = Seq(SMethodStatement(content = "if (otherObj != null) {", usedTypes = Set()), + SMethodStatement(content = s"+otherRole set${struc.getName.firstLetterToUpperCase}(${struc.getName.toLowerCase()})", usedTypes = Set(struc.getTypeElement)), + SMethodStatement(content = "}", usedTypes = Set.empty))) + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/ModelJoinViewGeneratingVisitor.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/ModelJoinViewGeneratingVisitor.scala new file mode 100644 index 0000000000000000000000000000000000000000..9cea21c63baf358e2a26168561af82376dc8bea3 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/ModelJoinViewGeneratingVisitor.scala @@ -0,0 +1,262 @@ +package org.rosi_project.model_sync.generator.sync + +import org.rosi_project.model_sync.generator.acr_model._ +import org.rosi_project.model_sync.generator.acr_model.types._ +import org.rosi_project.model_sync.model_join.representation.grammar._ +import scala.collection.JavaConverters._ +import scala.collection.convert.AsScalaConverters +import org.rosi_project.model_management.sum.join.RsumJoinType +import org.rosi_project.model_sync.generator.PackageNames + +class ModelJoinViewGeneratingVisitor(joinExpression: ModelJoinExpression) extends SModelVisitor { + + var viewCompartment: SViewClass = null + var refClasses: Seq[SClass] = Seq.empty + var refRelationalClasses: Seq[SClass] = Seq.empty + var newInternalRoles: Seq[SInnerViewNaturalClass] = Seq.empty + var newInternalRelationalRoles: Seq[SInnerViewRelationalClass] = Seq.empty + var allImportClasses: Set[STypedElement] = Set.empty + + override def visit(sModel: SModel): Unit = { + var counter = 0 + joinExpression.getJoins.forEach(j => { + refClasses = Seq.empty + refRelationalClasses = Seq.empty + newInternalRoles = Seq.empty + newInternalRelationalRoles = Seq.empty + allImportClasses = Set.empty + viewCompartment = new SViewClass(joinExpression.getName() + counter, PackageNames.viewPkgName) + counter += 1 + viewCompartment.addParent(PredefRsumTypes.IVIEW_COMPARTMENT_STYPE) + + val joinType = STypeRegistry.query(j.getTarget.getResourceName, j.getTarget.getResourcePath) + if (!joinType.isEmpty) { + if (joinType.get.isInstanceOf[SJoinClass]) { + viewCompartment.addJoinObject(joinType.get.asInstanceOf[SJoinClass]) + } + createClasses(asScalaBuffer(j.getKeepsList).toSet, joinType.get.asInstanceOf[SClass], sModel) + } + + //Now fill all natural internal roles with functionality + newInternalRoles.foreach(inner => { + //set inheritance to abstract view role + if (inner.isRootClass) { + inner.addParent(PredefRsumTypes.AVIEW_ROLE_STYPE) + } + //add initialize method if necessary + if (!inner.isAbstract && !inner.isInterface) { + inner.addMethod(ViewMethods.getIsRelationalMethod(false)) + inner.addMethod(ViewMethods.getCreationObjectMethod(inner)) + } + //add to string method + inner.addMethod(ToStringMethods.onlyStringToStringMethod("VNR: " + inner.getName)) + //add delete method + inner.addMethod(ViewMethods.getDeleteElementNaturalMethod(inner)) + //add getter and setter for attributes in the inner class + inner.getAttributes.foreach(attr => { + inner.addMethod(ViewMethods.getViewAttributeGetter(attr)) + inner.addMethod(ViewMethods.getViewAttributeSetter(attr)) + }) + }) + + //add methods that must be override from the view trait + viewCompartment.addMethod(ViewMethods.getIsViewableMethod((refClasses ++ refRelationalClasses).toSet)) + viewCompartment.addMethod(ViewMethods.getViewNameMethod(viewCompartment)) + viewCompartment.addMethod(ViewMethods.getGetNaturalRoleMethod(newInternalRoles.toSet)) + viewCompartment.addMethod(ViewMethods.getGetRelationalRoleMethod(newInternalRelationalRoles.toSet)) + viewCompartment.addMethod(ToStringMethods.onlyStringToStringMethod("VC: " + viewCompartment.getName)) + //Create methods to create elements from the view + ViewMethods.getCreateNaturalRoleMethods(newInternalRoles.toSet).foreach(viewCompartment.addMethod(_)) + + viewCompartment.augmentConstructor(new SMethodStatement("", allImportClasses)) + + //add the view to the list for generating views + sModel.addViewCompartment(viewCompartment) + }) + } + + def createClasses(keeps: Set[KeepExpression], cls: SClass, sModel: SModel): SInnerViewNaturalClass = { + var internalClass: SInnerViewNaturalClass = null + var newAtts: Seq[SAttribute] = Seq.empty + if (refClasses.contains(cls)) { + newInternalRoles.foreach(nir => { + if (nir.sumSource == cls) { + internalClass = nir + newAtts = nir.getAttributes() + } + }) + } else { + refClasses = refClasses :+ cls + internalClass = new SInnerViewNaturalClass(cls.getName + PackageNames.viewRolePostName, + _sClassType = cls.sClassType, + _externalClass = viewCompartment, + sumSource = cls) + newInternalRoles = newInternalRoles :+ internalClass + allImportClasses = allImportClasses + cls + viewCompartment.addInternalClass(internalClass) + } + + //without keep lists + //KeepAggregateExpression KeepAttributesExpression KeepCalculatedExpression + //sets the attributes from the source class + var features: Set[SStructuralFeature] = Set.empty + if (cls.isInstanceOf[SJoinClass]) { + val jCls = cls.asInstanceOf[SJoinClass] + features = jCls.innerAttributes + if (jCls.joinType != RsumJoinType.theta) { + //if natural or outer join add all join attributes + jCls.joinAttributes.foreach(a => { + var newAtt = SAttribute(a.getName, a.getTypeElement) + newAtt.setVisibility(MethodVisibility.protectedVis) + newAtt.isFinal = true + newAtts = newAtts :+ newAtt + }) + } + } else { + features = cls.getDeepStructuralFeatures.toSet + } + + //println("+++ KeepAttributesExpression") + keeps.filter(_.isInstanceOf[KeepAttributesExpression]).foreach(ja => { + val keepAtt = ja.asInstanceOf[KeepAttributesExpression] + keepAtt.getAttributes.forEach(attExp => { + //println("N: " + attExp.getAttributeName + " P: " + attExp.getContainingClass.getPackage + " CN: " + attExp.getContainingClass.getClassName) + features.filter(_.getName == attExp.getAttributeName).foreach(a => { + var isIn = false + internalClass.getAttributes().foreach(ain => { + if (ain.getName == a.getName && ain.getTypeElement.getName == a.getTypeElement.getName) { + isIn = true + } + }) + if (!isIn) { + //Proof if attribute must be in then add it to view class + var newAtt = SAttribute(a.getName, a.getTypeElement) + newAtt.setVisibility(MethodVisibility.protectedVis) + newAtt.isFinal = true + newAtts = newAtts :+ newAtt + } + }) + }) + }) + internalClass.setAttributes(newAtts) + //println("+++ KeepAggregateExpression") + keeps.filter(_.isInstanceOf[KeepAggregateExpression]).foreach(ja => { + //TODO: later + }) + //println("+++ KeepCalculatedExpression") + keeps.filter(_.isInstanceOf[KeepCalculatedExpression]).foreach(ja => { + //TODO: later + }) + //println("+++ KeepSubTypeExpression") + //with keep lists + //KeepSubTypeExpression KeepSuperTypeExpression KeepReferenceExpression (List of Keeps) + keeps.filter(_.isInstanceOf[KeepSubTypeExpression]).foreach(ja => { + val keepAtt = ja.asInstanceOf[KeepSubTypeExpression] + sModel.getModelClasses.filter(m => m.getName == keepAtt.getType.getClassName && m.getPackage == keepAtt.getType.getPackage).foreach(mc => { + val parent = mc.getRootClassWithNameAndPackage(cls.getName, cls.getPackage) + if (parent != null) { + val innerParent = createClasses(asScalaBuffer(keepAtt.getKeeps).toSet, mc, sModel) + innerParent.addParent(internalClass) + } + }) + }) + //println("+++ KeepSuperTypeExpression") + keeps.filter(_.isInstanceOf[KeepSuperTypeExpression]).foreach(ja => { + val keepAtt = ja.asInstanceOf[KeepSuperTypeExpression] + //println("TC: " + keepAtt.getTarget + " TC: " + keepAtt.getType) + val parent = cls.getRootClassWithNameAndPackage(keepAtt.getType.getClassName, keepAtt.getType.getPackage) + if (parent != null) { + val innerParent = createClasses(asScalaBuffer(keepAtt.getKeeps).toSet, parent, sModel) + internalClass.addParent(innerParent) + } + }) + //println("+++ KeepReferenceExpression") + keeps.filter(_.isInstanceOf[KeepReferenceExpression]).foreach(ja => { + val keepAtt = ja.asInstanceOf[KeepReferenceExpression] + //println("AN: " + keepAtt.getAttribute.getAttributeName + " " + keepAtt.getAttribute.getContainingClass.getPackage + " " + keepAtt.getAttribute.getContainingClass.getClassName) + sModel.getRelationalCompartments.foreach(me => { + var rc = me.asInstanceOf[SRelationalCompartmentClass] + if (rc.getPackage == keepAtt.getAttribute.getContainingClass.getPackage) { + if (rc.sClass.getName == keepAtt.getAttribute.getContainingClass.getClassName || rc.tClass.getName == keepAtt.getAttribute.getContainingClass.getClassName) { + if (rc.connectedRef.getName == keepAtt.getAttribute.getAttributeName || (rc.connectedRef.hasOpposite && rc.connectedRef.oppositeRef.getName == keepAtt.getAttribute.getAttributeName)) { + var sourceRole: SInnerViewNaturalClass = null + var targetRole: SInnerViewNaturalClass = null + var sourceAtt: SAttribute = null + var targetAtt: SAttribute = null + var createNormal = false + var createOpposite = false + if (rc.sClass.getName == keepAtt.getAttribute.getContainingClass.getClassName) { + //current is source + sourceRole = internalClass + var tClass = rc.tClass.asInstanceOf[SClass] + sModel.getModelClasses.filter(m => m.getName == keepAtt.getTarget.getClassName && m.getPackage == keepAtt.getTarget.getPackage).foreach(cs => { + val parent = cs.getRootClassWithNameAndPackage(rc.tClass.getName, rc.tClass.getPackage) + if (parent != null) { + tClass = cs + } + }) + targetRole = createClasses(asScalaBuffer(keepAtt.getKeeps).toSet, tClass, sModel) + createNormal = true + } else { + //current is target + var sClass = rc.sClass.asInstanceOf[SClass] + sModel.getModelClasses.filter(m => m.getName == keepAtt.getTarget.getClassName && m.getPackage == keepAtt.getTarget.getPackage).foreach(cs => { + val parent = cs.getRootClassWithNameAndPackage(rc.sClass.getName, rc.sClass.getPackage) + if (parent != null) { + sClass = cs + } + }) + sourceRole = createClasses(asScalaBuffer(keepAtt.getKeeps).toSet, sClass, sModel) + targetRole = internalClass + createOpposite = true + } + sourceAtt = new SAttribute("source", sourceRole) + targetAtt = new SAttribute("target", targetRole) + sourceAtt.isFinal = true + sourceAtt.setVisibility(MethodVisibility.privateVis) + targetAtt.isFinal = true + targetAtt.setVisibility(MethodVisibility.privateVis) + //now find the right relational compartment + refRelationalClasses = refRelationalClasses :+ rc + //Iterate over all Relational compartments and create relational internal role classes + val internalRelClass = new SInnerViewRelationalClass(rc.getName + PackageNames.viewRolePostName, _externalClass = viewCompartment, + sumSource = rc, viewSource = sourceRole, viewTarget = targetRole) + internalRelClass.setAttributes(sourceAtt ++ targetAtt) + internalRelClass.addMethod(ViewMethods.getIsRelationalMethod(true)) + internalRelClass.addMethod(ViewMethods.getCreationObjectMethod(internalRelClass, createNormal, createOpposite)) + internalRelClass.addMethod(ViewMethods.getDeleteElementRelationMethod(internalRelClass, createNormal, createOpposite)) + internalRelClass.addMethod(ToStringMethods.onlyStringToStringMethod("VRR: " + internalRelClass.getName)) + ViewMethods.getSourceAndTargetGetter(internalRelClass).foreach(internalRelClass.addMethod(_)) + internalRelClass.addParent(PredefRsumTypes.AVIEW_ROLE_STYPE) + ViewMethods.createAllReferenceLinks(internalRelClass, createNormal, createOpposite) + newInternalRelationalRoles = newInternalRelationalRoles :+ internalRelClass + allImportClasses = allImportClasses + sourceRole.sumSource + targetRole.sumSource + rc.tClass + rc.sClass + viewCompartment.addInternalClass(internalRelClass) + } + } + } + }) + }) + internalClass + } + + override def visit(sClass: SClass): Unit = { + // pass + } + + override def visit(sAttr: SAttribute): Unit = { + // pass + } + + override def visit(sMethod: SMethod): Unit = { + // pass + } + + override def visit(sType: SType): Unit = { + // pass + } + + override def visit(sRef: SReference): Unit = { + // pass + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/PredefRsumTypes.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/PredefRsumTypes.scala new file mode 100644 index 0000000000000000000000000000000000000000..5a3b9f745bd5b0b1adaa79934ac9d8989e6e264a --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/PredefRsumTypes.scala @@ -0,0 +1,104 @@ +package org.rosi_project.model_sync.generator.sync + +import org.rosi_project.model_sync.generator.acr_model.SType +import org.rosi_project.model_sync.generator.acr_model.SEnum +import org.rosi_project.model_management.sum.IViewCompartment +import org.rosi_project.model_management.sum.IViewTypeInfo +import org.rosi_project.model_management.sum.query._ +import org.rosi_project.model_management.sum.join._ +import org.rosi_project.model_management.sum.compartments._ +import org.rosi_project.model_management.sum.roles.IRelationRole + +object PredefRsumTypes { + + //JOIN TYPES + private val IJOIN_COMPARTMENT_CLASS = classOf[IJoinCompartment] + val IJOIN_COMPARTMENT_STYPE = SType(IJOIN_COMPARTMENT_CLASS.getSimpleName, IJOIN_COMPARTMENT_CLASS.getPackage.getName) + + private val JOIN_INFO_CLASS = classOf[IJoinInfo] + val JOIN_INFO_STYPE = SType(JOIN_INFO_CLASS.getSimpleName, JOIN_INFO_CLASS.getPackage.getName) + + private val RSUM_JOIN_TYPE_CLASS = RsumJoinType.getClass + val RSUM_JOIN_TYPE_STYPE = new SEnum(RSUM_JOIN_TYPE_CLASS.getSimpleName.replace("$", ""), RSUM_JOIN_TYPE_CLASS.getPackage.getName, Set.empty) + + //VIEW TYPES + private val IVIEW_COMPARTMENT_CLASS = classOf[IViewCompartment] + val IVIEW_COMPARTMENT_STYPE = SType(IVIEW_COMPARTMENT_CLASS.getSimpleName, IVIEW_COMPARTMENT_CLASS.getPackage.getName) + + private val VIEWTYPE_INFO_CLASS = classOf[IViewTypeInfo] + val VIEWTYPE_INFO_STYPE = SType(VIEWTYPE_INFO_CLASS.getSimpleName, VIEWTYPE_INFO_CLASS.getPackage.getName) + + private val AVIEW_ROLE_CLASS = classOf[IViewCompartment#AViewRole] + val AVIEW_ROLE_STYPE = SType(AVIEW_ROLE_CLASS.getSimpleName)//AVIEW_ROLE_CLASS.getPackage.getName) + + //QUERY TYPES + private val CHECKING_OPTION_CLASS = CheckingOption.getClass + val CHECKING_OPTION_STYPE = new SEnum(CHECKING_OPTION_CLASS.getSimpleName.replace("$", ""), CHECKING_OPTION_CLASS.getPackage.getName, Set.empty) + + private val QUERY_HELPER_CLASS = classOf[QueryHelper] + val QUERY_HELPER_STYPE = SType(QUERY_HELPER_CLASS.getSimpleName, QUERY_HELPER_CLASS.getPackage.getName) + + private val IQUERY_VIEW_COMPARTMENT_CLASS = classOf[QueryFactory] + val IQUERY_VIEW_COMPARTMENT_STYPE = SType(IQUERY_VIEW_COMPARTMENT_CLASS.getSimpleName, IQUERY_VIEW_COMPARTMENT_CLASS.getPackage.getName) + + private val AQUERY_VIEW_ROLE_CLASS = classOf[QueryFactory#QueryFactoryElement] + val AQUERY_VIEW_ROLE_STYPE = SType(AQUERY_VIEW_ROLE_CLASS.getSimpleName) //, AQUERY_VIEW_ROLE_CLASS.getPackage.getName) + + //RELATIONAL COMPARTMENT TYPES + private val IRELATIONROLE_CLASS = classOf[IRelationRole] + val IRELATIONROLE_STYPE = SType(IRELATIONROLE_CLASS.getSimpleName, IRELATIONROLE_CLASS.getPackage.getName) + + private val IAGGREGTATION_CLASS = classOf[IAggregation] + val IAGGREGTATION_STYPE = SType(IAGGREGTATION_CLASS.getSimpleName, IAGGREGTATION_CLASS.getPackage.getName) + + private val IAGGREGTATION_SOURCE_CLASS = classOf[IAggregation#IAggregationSource] + val IAGGREGTATION_SOURCE_STYPE = SType(IAGGREGTATION_SOURCE_CLASS.getSimpleName, IAGGREGTATION_SOURCE_CLASS.getPackage.getName) + + private val IAGGREGTATION_TARGET_CLASS = classOf[IAggregation#IAggregationTarget] + val IAGGREGTATION_TARGET_STYPE = SType(IAGGREGTATION_TARGET_CLASS.getSimpleName, IAGGREGTATION_TARGET_CLASS.getPackage.getName) + + private val IASSOCIATION_CLASS = classOf[IAssociation] + val IASSOCIATION_STYPE = SType(IASSOCIATION_CLASS.getSimpleName, IASSOCIATION_CLASS.getPackage.getName) + + private val IASSOCIATION_SOURCE_CLASS = classOf[IAssociation#IAssociationSource] + val IASSOCIATION_SOURCE_STYPE = SType(IASSOCIATION_SOURCE_CLASS.getSimpleName, IASSOCIATION_SOURCE_CLASS.getPackage.getName) + + private val IASSOCIATION_TARGET_CLASS = classOf[IAssociation#IAssociationTarget] + val IASSOCIATION_TARGET_STYPE = SType(IASSOCIATION_TARGET_CLASS.getSimpleName, IASSOCIATION_TARGET_CLASS.getPackage.getName) + + private val ICOMPOSITION_CLASS = classOf[IComposition] + val ICOMPOSITION_STYPE = SType(ICOMPOSITION_CLASS.getSimpleName, ICOMPOSITION_CLASS.getPackage.getName) + + private val ICOMPOSITION_SOURCE_CLASS = classOf[IComposition#ICompositionSource] + val ICOMPOSITION_SOURCE_STYPE = SType(ICOMPOSITION_SOURCE_CLASS.getSimpleName, ICOMPOSITION_SOURCE_CLASS.getPackage.getName) + + private val ICOMPOSITION_TARGET_CLASS = classOf[IComposition#ICompositionTarget] + val ICOMPOSITION_TARGET_STYPE = SType(ICOMPOSITION_TARGET_CLASS.getSimpleName, ICOMPOSITION_TARGET_CLASS.getPackage.getName) + + private val IDIRECT_AGGREGATION_CLASS = classOf[IDirectAggregation] + val IDIRECT_AGGREGATION_STYPE = SType(IDIRECT_AGGREGATION_CLASS.getSimpleName, IDIRECT_AGGREGATION_CLASS.getPackage.getName) + + private val IDIRECT_AGGREGATION_SOURCE_CLASS = classOf[IDirectAggregation#IDirectAggregationSource] + val IDIRECT_AGGREGATION_SOURCE_STYPE = SType(IDIRECT_AGGREGATION_SOURCE_CLASS.getSimpleName, IDIRECT_AGGREGATION_SOURCE_CLASS.getPackage.getName) + + private val IDIRECT_AGGREGATION_TARGET_CLASS = classOf[IDirectAggregation#IDirectAggregationTarget] + val IDIRECT_AGGREGATION_TARGET_STYPE = SType(IDIRECT_AGGREGATION_TARGET_CLASS.getSimpleName, IDIRECT_AGGREGATION_TARGET_CLASS.getPackage.getName) + + private val IDIRECT_ASSOCIATION_CLASS = classOf[IDirectAssoziation] + val IDIRECT_ASSOCIATION_STYPE = SType(IDIRECT_ASSOCIATION_CLASS.getSimpleName, IDIRECT_ASSOCIATION_CLASS.getPackage.getName) + + private val IDIRECT_ASSOCIATION_SOURCE_CLASS = classOf[IDirectAssoziation#IDirectAssoziationSource] + val IDIRECT_ASSOCIATION_SOURCE_STYPE = SType(IDIRECT_ASSOCIATION_SOURCE_CLASS.getSimpleName, IDIRECT_ASSOCIATION_SOURCE_CLASS.getPackage.getName) + + private val IDIRECT_ASSOCIATION_TARGET_CLASS = classOf[IDirectAssoziation#IDirectAssoziationTarget] + val IDIRECT_ASSOCIATION_TARGET_STYPE = SType(IDIRECT_ASSOCIATION_TARGET_CLASS.getSimpleName, IDIRECT_ASSOCIATION_TARGET_CLASS.getPackage.getName) + + private val IDIRECT_COMPOSITION_CLASS = classOf[IDirectComposition] + val IDIRECT_COMPOSITION_STYPE = SType(IDIRECT_COMPOSITION_CLASS.getSimpleName, IDIRECT_COMPOSITION_CLASS.getPackage.getName) + + private val IDIRECT_COMPOSITION_SOURCE_CLASS = classOf[IDirectComposition#IDirectCompositionSource] + val IDIRECT_COMPOSITION_SOURCE_STYPE = SType(IDIRECT_COMPOSITION_SOURCE_CLASS.getSimpleName, IDIRECT_COMPOSITION_SOURCE_CLASS.getPackage.getName) + + private val IDIRECT_COMPOSITION_TARGET_CLASS = classOf[IDirectComposition#IDirectCompositionTarget] + val IDIRECT_COMPOSITION_TARGET_STYPE = SType(IDIRECT_COMPOSITION_TARGET_CLASS.getSimpleName, IDIRECT_COMPOSITION_TARGET_CLASS.getPackage.getName) +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/PredefSyncTypes.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/PredefSyncTypes.scala new file mode 100644 index 0000000000000000000000000000000000000000..052a048a75df3a860bb2f8ad3381fafffd4942fe --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/PredefSyncTypes.scala @@ -0,0 +1,10 @@ +package org.rosi_project.model_sync.generator.sync + +import org.rosi_project.model_sync.generator.acr_model.SType +import org.rosi_project.model_management.core.PlayerSync + +object PredefSyncTypes { + + private val PLAYER_SYNC_CLASS = classOf[PlayerSync] + val PLAYER_SYNC_STYPE = SType(PLAYER_SYNC_CLASS.getSimpleName, PLAYER_SYNC_CLASS.getPackage.getName) +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/PredefTypes.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/PredefTypes.scala deleted file mode 100644 index 0491c444f2512bada9edabbedf5f803c9ab01ca2..0000000000000000000000000000000000000000 --- a/src/main/scala/org/rosi_project/model_sync/generator/sync/PredefTypes.scala +++ /dev/null @@ -1,42 +0,0 @@ -package org.rosi_project.model_sync.generator.sync - -import org.rosi_project.model_sync.generator.acr_model.SType - -/** Contains a number of types which are used throughout the synchronization. - * - * Equivalent to [[org.rosi_project.model_sync.generator.acr_model.types.PredefTypes]], just for - * the sync types. - * - * @author Rico Bergmann - */ -object PredefTypes { - - /** `org.rosi_project.model_sync.provider.DisplayableModel` - */ - val DisplayableModel = SType("DisplayableModel", "org.rosi_project.model_sync.provider") - - /** `org.rosi_project.model_sync.provider.DisplayableModelForInitialization` - */ - val DisplayableModelForInitialization = SType("DisplayableModelForInitialization", "org.rosi_project.model_sync.provider") - - /** `org.rosi_project.model_sync.provider.DisplayableModelForIntegration` - */ - val DisplayableModelForIntegration = SType("DisplayableModelForIntegration", "org.rosi_project.model_sync.provider") - - /** `org.rosi_project.model_sync.provider.ModelSyncProvider` - */ - val ModelProvider = SType("ModelSyncProvider", "org.rosi_project.model_sync.provider") - - /** `org.rosi_project.model_sync.provider.ModelRegistry` - */ - val ModelRegistry = SType("ModelRegistry", "org.rosi_project.model_sync.provider") - - /** `org.rosi_project.model_sync.provider.instances.ModelInstanceConstructor` - */ - val ModelInstanceConstructor = SType("ModelInstanceConstructor", "org.rosi_project.model_sync.instances") - - /** `org.rosi_project.model_sync.provider.instances.ModelInstanceModifier` - */ - val ModelInstanceModifier = SType("ModelInstanceModifier", "org.rosi_project.model_sync.instances") - -} diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/QueryGeneratingVisitor.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/QueryGeneratingVisitor.scala new file mode 100644 index 0000000000000000000000000000000000000000..2f7f50fcc006cd92c12896e904db1f4b11545b29 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/QueryGeneratingVisitor.scala @@ -0,0 +1,134 @@ +package org.rosi_project.model_sync.generator.sync + +import org.rosi_project.model_sync.generator.acr_model._ +import org.rosi_project.model_sync.generator.acr_model.types._ +import org.rosi_project.model_sync.generator.PackageNames + +class QueryGeneratingVisitor extends SModelVisitor { + + override def visit(sModel: SModel): Unit = { + + val viewCompartment = new SClass(sModel.getName.capitalize + PackageNames.queryPostName, PackageNames.queryPkgName) + var newInternalRoles: Seq[SInnerViewNaturalClass] = Seq.empty + var newInternalRelationalRoles: Seq[SInnerViewRelationalClass] = Seq.empty + viewCompartment.addParent(PredefRsumTypes.IQUERY_VIEW_COMPARTMENT_STYPE) + + var allTypes: Set[STypedElement] = sModel.getModelClasses ++ sModel.getRelationalCompartments ++ PredefRsumTypes.CHECKING_OPTION_STYPE ++ sModel.getModelEnums + sModel.getModelClasses.foreach(_.getStructuralFeatures.foreach(s => { + if (s.getTypeElement.sPackage != "") + allTypes += s.getTypeElement + })) + + viewCompartment.augmentConstructor(SMethodStatement(s"""init("${viewCompartment.getName}")""", allTypes)) + + //Iterate over all Model classes and create natural internal role classes + sModel.getModelClasses.filter(!_.getName.startsWith(PackageNames.queryHelperPrefix)).foreach(cls => { + val internalClass = new SInnerViewNaturalClass(cls.getName + PackageNames.queryRolePostName, + _externalClass = viewCompartment, + sumSource = cls) + //sets the attributes from the source class + var newAtts: Set[SAttribute] = Set.empty + cls.getAttributes.foreach(attr => { + var newAtt = SAttribute(attr.getName, attr.getTypeElement, attr.unique) + newAtt.setVisibility(MethodVisibility.protectedVis) + newAtt.isFinal = true + newAtts += newAtt + }) + internalClass.setAttributes(newAtts.toSeq) + newInternalRoles = newInternalRoles :+ internalClass + viewCompartment.addInternalClass(internalClass) + }) + + //TODO: can be necessary to add all parents in one loop first + //Now fill all natural internal roles with functionality + newInternalRoles.foreach(inner => { + val cls = inner.sumSource + //set inheritance to abstract view role + if (cls.isRootClass) { + inner.addParent(PredefRsumTypes.AQUERY_VIEW_ROLE_STYPE) + } + //add initialize method if necessary + inner.addMethod(ViewMethods.getIsRelationalMethod(false)) + inner.addMethod(QueryMethods.getInitializeMethod(inner)) + //add delete method + inner.addMethod(ViewMethods.getDeleteElementNaturalMethod(inner)) + //add parents + cls.getAllParents().foreach(p => { + val existing: Option[STypedElement] = newInternalRoles.find(existing => existing.getName == p.getName + PackageNames.queryRolePostName) + if (!existing.isEmpty) { + inner.addParent(existing.get) + } + }) + //add getter and setter for attributes in the inner class + inner.getAttributes.foreach(attr => { + inner.addMethod(ViewMethods.getViewAttributeGetter(attr)) + inner.addMethod(QueryMethods.getViewAttributeSetter(attr)) + }) + //remove all attributes + inner.setAttributes(Seq.empty) + }) + + //Iterate over all Relational compartments and create relational internal role classes + sModel.getRelationalCompartments.foreach(r => { + var sourceAtt: SAttribute = null + var targetAtt: SAttribute = null + //set as attributes the other classes + var sourceRole: SInnerViewNaturalClass = null + var targetRole: SInnerViewNaturalClass = null + r.getAttributes.foreach(attr => { + newInternalRoles.foreach(inte => { + if (inte.getName == attr.getTypeElement.getName + PackageNames.queryRolePostName) { + if (attr.getName == "sInstance") { + sourceRole = inte + sourceAtt = new SAttribute("source", inte) + sourceAtt.isFinal = true + sourceAtt.setVisibility(MethodVisibility.privateVis) + } else { + targetRole = inte + targetAtt = new SAttribute("target", inte) + targetAtt.isFinal = true + targetAtt.setVisibility(MethodVisibility.privateVis) + } + } + }) + }) + val internalClass = new SInnerViewRelationalClass(r.getName + PackageNames.queryRolePostName, _externalClass = viewCompartment, + sumSource = r.asInstanceOf[SRelationalCompartmentClass], viewSource = sourceRole, viewTarget = targetRole) + internalClass.setAttributes(sourceAtt ++ targetAtt) + internalClass.addMethod(ViewMethods.getIsRelationalMethod(true)) + internalClass.addMethod(QueryMethods.getInitializeMethod(internalClass)) + internalClass.addMethod(ViewMethods.getDeleteElementRelationMethod(internalClass, true, true)) + ViewMethods.getSourceAndTargetGetter(internalClass).foreach(internalClass.addMethod(_)) + internalClass.addParent(PredefRsumTypes.AQUERY_VIEW_ROLE_STYPE) + QueryMethods.createAllReferenceLinks(internalClass) + newInternalRelationalRoles = newInternalRelationalRoles :+ internalClass + viewCompartment.addInternalClass(internalClass) + }) + + //Create methods to create elements from the view + QueryMethods.getCreateNaturalRoleMethods(newInternalRoles.toSet).foreach(viewCompartment.addMethod(_)) + + //add the view to the list for generating views + sModel.addProviderClass(viewCompartment) + } + + override def visit(sClass: SClass): Unit = { + // pass + } + + override def visit(sAttr: SAttribute): Unit = { + // pass + } + + override def visit(sMethod: SMethod): Unit = { + // pass + } + + override def visit(sType: SType): Unit = { + // pass + } + + override def visit(sRef: SReference): Unit = { + // pass + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/QueryMethods.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/QueryMethods.scala new file mode 100644 index 0000000000000000000000000000000000000000..ff6d5ecf37b6d444369568c6494cca2cfac4e45e --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/QueryMethods.scala @@ -0,0 +1,202 @@ +package org.rosi_project.model_sync.generator.sync + +import org.rosi_project.model_sync.generator.support.ExtendedString.stringToExtended +import org.rosi_project.model_sync.generator.acr_model.types.PredefTypes +import org.rosi_project.model_sync.generator.acr_model._ +import org.rosi_project.model_sync.generator.acr_model.types.SSet + +object QueryMethods { + + /** + * Special because of Helper classes. + */ + def getCreateNaturalRoleMethods(naturalRoles: Set[SInnerViewNaturalClass]): Seq[SMethod] = { + var methods: Seq[SMethod] = Seq.empty + naturalRoles.foreach(nr => { + if (!nr.getName.startsWith("Helper")) { + val method = new SMethod( + name = s"create${nr.sumSource.getName}", + result = nr, + params = Seq.empty, + implementation = Seq(SMethodStatement(content = s"return new ${nr.getName}()"))) + methods = methods :+ method + } + }) + methods + } + + /** + * Is also split here now. + */ + def getInitializeMethod(nat: SInnerViewNaturalClass): SMethod = { + var helper = "" + if (nat.sumSource.isAbstract || nat.sumSource.isInterface) helper = "Helper" + val method = new SMethod( + name = "getCreationObject", + result = PredefTypes.Object, + params = Seq.empty, + implementation = Seq(SMethodStatement(content = s"return new $helper${nat.sumSource.getName}(" + + s"${nat.sumSource.getAllConstructorParameters.map(HelperFunctions.classEmptyConstructorParameterCreation(_)).mkString(", ")})")), + true) + method.setVisibility(MethodVisibility.protectedVis) + method + } + + /** + * Is also split here now. + */ + def getInitializeMethod(ref: SInnerViewRelationalClass): SMethod = { + val method = new SMethod( + name = "getCreationObject", + result = PredefTypes.Object, + params = Seq.empty, + implementation = Seq(SMethodStatement(content = "return")), + true) + var statements: Seq[SMethodStatement] = Seq.empty + if (ref.sumSource.connectedRef.hasOpposite) { + statements = Seq(SMethodStatement(content = s"target.set${ref.sumSource.connectedRef.oppositeRef.getName.capitalize}Intern(this)")) + } + statements = statements ++ Seq(SMethodStatement(content = s"source.set${ref.sumSource.connectedRef.getName.capitalize}Intern(this)"), + SMethodStatement(content = s"val sp: ${ref.viewSource.sumSource.getName} = source.player.right.get.asInstanceOf[${ref.viewSource.sumSource.getName}]", + usedTypes = Set(ref.viewSource.sumSource)), + SMethodStatement(content = s"val tp: ${ref.viewTarget.sumSource.getName} = target.player.right.get.asInstanceOf[${ref.viewTarget.sumSource.getName}]", + usedTypes = Set(ref.viewTarget.sumSource)), + SMethodStatement(content = s"val v: ${ref.sumSource.getName} = new ${ref.sumSource.getName}(sp, tp)", + usedTypes = Set(ref.sumSource)), + SMethodStatement(content = "return v", + usedTypes = Set.empty)) + method.implementation = statements + method.setVisibility(MethodVisibility.protectedVis) + method + } + + /** + * Special are the attribute filter options. + */ + def getViewAttributeSetter(struc: SStructuralFeature): SMethod = { + new SMethod( + name = s"set${struc.getName.firstLetterToUpperCase}View", + result = PredefTypes.Unit, + params = Seq(SMethodParameter(struc.getName.toLowerCase(), struc.getTypeElement), SMethodParameter("check", PredefRsumTypes.CHECKING_OPTION_STYPE)), + implementation = Seq(SMethodStatement(content = s"+this set${struc.getName.firstLetterToUpperCase}(${struc.getName.toLowerCase()})", usedTypes = Set(struc.getTypeElement)), + SMethodStatement(content = s"""connected.addAttributeFilter("${struc.getName}", ${struc.getName.toLowerCase()}.toString(), check)"""))) + } + + def createAllReferenceLinks(refClass: SInnerViewRelationalClass): Unit = { + val targetClass: SInnerViewNaturalClass = refClass.viewTarget + val sourceClass: SInnerViewNaturalClass = refClass.viewSource + val realRef: SReference = refClass.sumSource.connectedRef + val oppoRef: SReference = refClass.sumSource.connectedRef.oppositeRef + createReferenceLinks(refClass, realRef, sourceClass, targetClass, true) + if (oppoRef != null) { + createReferenceLinks(refClass, oppoRef, targetClass, sourceClass, false) + } + } + + private def createReferenceLinks(refClass: SInnerViewRelationalClass, realRef: SReference, sourceClass: SInnerViewNaturalClass, targetClass: SInnerViewNaturalClass, isReal: Boolean): Unit = { + val getStatement: String = if (isReal) "getTarget" else "getSource" + val thisStatement: String = if (isReal) "(this, v)" else "(v, this)" + if (realRef.upperBound == 1) { + //add delete role for attributes because query is not connected with RSUM + sourceClass.getMethods.foreach(m => { + if (m.getName == "deleteElement") { + m.implementation = m.implementation :+ SMethodStatement(s"if (${realRef.getName} != null) ${realRef.getName}.deleteElement()") + } + }) + + //upper Bound = 1 + //variable settings + sourceClass.augmentConstructor(SMethodStatement(s"private var ${realRef.getName}: ${refClass.getDeepName} = null")) + //internal variables + val removeMethodInternal = new SMethod( + name = s"remove${realRef.getName.capitalize}Intern", + result = PredefTypes.Unit, + params = Seq(SMethodParameter("v", refClass)), //TODO: remove this then each remove internal method has different input parameters + implementation = Seq(SMethodStatement(content = s"${realRef.getName} = null"))) + removeMethodInternal.setVisibility(MethodVisibility.privateExternalClass) + sourceClass.addMethod(removeMethodInternal) + val setMethodInternal = new SMethod( + name = s"set${realRef.getName.capitalize}Intern", + result = PredefTypes.Unit, + params = Seq(SMethodParameter("v", refClass)), + implementation = Seq(SMethodStatement(content = s"${realRef.getName} = v"))) + setMethodInternal.setVisibility(MethodVisibility.privateExternalClass) + sourceClass.addMethod(setMethodInternal) + //external variables + sourceClass.addMethod(new SMethod( + name = s"get${realRef.getName.capitalize}", + result = targetClass, + params = Seq.empty, + implementation = Seq(SMethodStatement(content = s"return ${realRef.getName}.${getStatement}()")))) + sourceClass.addMethod(new SMethod( + name = s"set${realRef.getName.capitalize}", + result = PredefTypes.Boolean, + params = Seq(SMethodParameter("v", targetClass)), + implementation = Seq(SMethodStatement(content = "if (v == null) return false"), + SMethodStatement(content = s"if (!containsRole(v.asInstanceOf[${PredefRsumTypes.AQUERY_VIEW_ROLE_STYPE.getName}])) return false"), + SMethodStatement(content = s"if (${realRef.getName} != null) {"), + SMethodStatement(content = s"if (${realRef.getName}.${getStatement}() == v) return false"), + SMethodStatement(content = s"${realRef.getName}.deleteElement()"), + SMethodStatement(content = "}"), + SMethodStatement(content = s"new ${refClass.getName}${thisStatement}"), + SMethodStatement(content = "return true")))) + } else { + //add delete role for attributes + sourceClass.getMethods.foreach(m => { + if (m.getName == "deleteElement") { + m.implementation = m.implementation :+ SMethodStatement(s"${realRef.getName}.foreach(_.deleteElement())") + } + }) + + //upper Bound = endless + //variable settings + sourceClass.augmentConstructor(SMethodStatement(s"private var ${realRef.getName}: Set[${refClass.getDeepName}] = Set.empty")) + //internal variables + val removeMethodInternal = new SMethod( + name = s"remove${realRef.getName.capitalize}Intern", + result = PredefTypes.Unit, + params = Seq(SMethodParameter("v", refClass)), + implementation = Seq(SMethodStatement(content = s"${realRef.getName} -= v"))) + removeMethodInternal.setVisibility(MethodVisibility.privateExternalClass) + sourceClass.addMethod(removeMethodInternal) + val setMethodInternal = new SMethod( + name = s"set${realRef.getName.capitalize}Intern", + result = PredefTypes.Unit, + params = Seq(SMethodParameter("v", refClass)), + implementation = Seq(SMethodStatement(content = s"${realRef.getName} += v"))) + setMethodInternal.setVisibility(MethodVisibility.privateExternalClass) + sourceClass.addMethod(setMethodInternal) + //external variables + sourceClass.addMethod(new SMethod( + name = s"get${realRef.getName.capitalize}", + result = SSet(targetClass), + params = Seq.empty, + implementation = Seq(SMethodStatement(content = s"var vs: Set[${targetClass.getDeepName}] = Set.empty"), + SMethodStatement(content = s"${realRef.getName}.foreach{ v => vs += v.${getStatement}()}"), + SMethodStatement(content = "return vs")))) + sourceClass.addMethod(new SMethod( + name = s"has${realRef.getName.capitalize}", + result = PredefTypes.Boolean, + params = Seq(SMethodParameter("v", targetClass)), + implementation = Seq(SMethodStatement(content = s"return get${realRef.getName.capitalize}.contains(v)")))) + sourceClass.addMethod(new SMethod( + name = s"add${realRef.getName.capitalize}", + result = PredefTypes.Boolean, + params = Seq(SMethodParameter("v", targetClass)), + implementation = Seq(SMethodStatement(content = s"if (has${realRef.getName.capitalize}(v) || !containsRole(v.asInstanceOf[${PredefRsumTypes.AQUERY_VIEW_ROLE_STYPE.getName}])) return false"), + SMethodStatement(content = s"new ${refClass.getName}${thisStatement}"), + SMethodStatement(content = "return true")))) + sourceClass.addMethod(new SMethod( + name = s"remove${realRef.getName.capitalize}", + result = PredefTypes.Boolean, + params = Seq(SMethodParameter("v", targetClass)), + implementation = Seq(SMethodStatement(content = s"if (!has${realRef.getName.capitalize}(v)) return false"), + SMethodStatement(content = s"${realRef.getName}.foreach{ h =>"), + SMethodStatement(content = s"if (h.${getStatement}() == v) {"), + SMethodStatement(content = "h.deleteElement()"), + SMethodStatement(content = "return true"), + SMethodStatement(content = "}}"), + SMethodStatement(content = "return true")))) + } + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/ReferenceMethodCreationVisitor.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/ReferenceMethodCreationVisitor.scala new file mode 100644 index 0000000000000000000000000000000000000000..257523f0826ad8466a8e814e3263b68311385354 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/ReferenceMethodCreationVisitor.scala @@ -0,0 +1,93 @@ +package org.rosi_project.model_sync.generator.sync + +import org.rosi_project.model_sync.generator.acr_model._ +import org.rosi_project.model_sync.generator.acr_model.types.GenericSequence + +/** + * Create the methods to get the references from each instance. Is only possible in combination with sync, because of role functionality. + */ +class ReferenceMethodCreationVisitor extends SModelVisitor { + + override def visit(sModel: SModel): Unit = { + var typeName = "Set.empty" + var addElement = "result +=" + + sModel.getRelationalCompartments.foreach(cls => { + val relComp = cls.asInstanceOf[SRelationalCompartmentClass] + //iterate over all relational compartments + val methodSrc = new SMethod( + name = s"get${relComp.connectedRef.getName.capitalize}", + result = relComp.connectedRef.getTypeElement, + params = Seq.empty, + implementation = Seq.empty) + + //proof return type + if (relComp.connectedRef.getTypeElement.isInstanceOf[GenericSequence]) { + typeName = "Set.empty" + addElement = "result +=" + } else { + typeName = "null" + addElement = "result =" + } + //make impl + var implSrc: Seq[SMethodStatement] = Seq.empty + implSrc = implSrc :+ SMethodStatement(content = s"var result: ${relComp.connectedRef.getTypeElement.getName} = ${typeName}", usedTypes = Set(PredefRsumTypes.IRELATIONROLE_STYPE)) + implSrc = implSrc :+ SMethodStatement(content = s"""this.roles.filter(r => r.isInstanceOf[${PredefRsumTypes.IRELATIONROLE_STYPE.getName}] && + r.asInstanceOf[${PredefRsumTypes.IRELATIONROLE_STYPE.getName}].getOuterCompartment.isInstanceOf[${relComp.getName}]) + .foreach(r => { + ${addElement} r.asInstanceOf[${PredefRsumTypes.IRELATIONROLE_STYPE.getName}].getOuterCompartment.getTargetIns.asInstanceOf[${relComp.tClass.getName}] + })""") + implSrc = implSrc :+ SMethodStatement(content = "result") + methodSrc.implementation = implSrc + relComp.sClass.asInstanceOf[SClass].addMethod(methodSrc) + //proof opposite reference + if (relComp.connectedRef.hasOpposite) { + val methodTrg = new SMethod( + name = s"get${relComp.connectedRef.oppositeRef.getName.capitalize}", + result = relComp.connectedRef.oppositeRef.getTypeElement, + params = Seq.empty, + implementation = Seq.empty) + + //proof return type + if (relComp.connectedRef.oppositeRef.getTypeElement.isInstanceOf[GenericSequence]) { + typeName = "Set.empty" + addElement = "result +=" + } else { + typeName = "null" + addElement = "result =" + } + //make impl + var implTrg: Seq[SMethodStatement] = Seq.empty + implTrg = implTrg :+ SMethodStatement(content = s"var result: ${relComp.connectedRef.oppositeRef.getTypeElement.getName} = ${typeName}", usedTypes = Set(PredefRsumTypes.IRELATIONROLE_STYPE)) + implTrg = implTrg :+ SMethodStatement(content = s"""this.roles.filter(r => r.isInstanceOf[${PredefRsumTypes.IRELATIONROLE_STYPE.getName}] && + r.asInstanceOf[${PredefRsumTypes.IRELATIONROLE_STYPE.getName}].getOuterCompartment.isInstanceOf[${relComp.getName}]) + .foreach(r => { + ${addElement} r.asInstanceOf[${PredefRsumTypes.IRELATIONROLE_STYPE.getName}].getOuterCompartment.getSourceIns.asInstanceOf[${relComp.sClass.getName}] + })""") + implTrg = implTrg :+ SMethodStatement(content = "result") + methodTrg.implementation = implTrg + relComp.tClass.asInstanceOf[SClass].addMethod(methodTrg) + } + }) + } + + override def visit(sClass: SClass): Unit = { + // pass + } + + override def visit(sAttr: SAttribute): Unit = { + // pass + } + + override def visit(sMethod: SMethod): Unit = { + // pass + } + + override def visit(sType: SType): Unit = { + // pass + } + + override def visit(sRef: SReference): Unit = { + // pass + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/ReferenceRemoveVisitor.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/ReferenceRemoveVisitor.scala new file mode 100644 index 0000000000000000000000000000000000000000..4d0a9abb274f973ca4077bfaf6068d67cc5f5cb8 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/ReferenceRemoveVisitor.scala @@ -0,0 +1,34 @@ +package org.rosi_project.model_sync.generator.sync + +import org.rosi_project.model_sync.generator.acr_model._ + +class ReferenceRemoveVisitor extends SModelVisitor { + + override def visit(sModel: SModel): Unit = { + sModel.getModelClasses.foreach(cls => { + //remove all references from the class + cls.setReferences(null) + }) + } + + override def visit(sClass: SClass): Unit = { + // pass + } + + override def visit(sAttr: SAttribute): Unit = { + // pass + } + + override def visit(sMethod: SMethod): Unit = { + // pass + } + + override def visit(sType: SType): Unit = { + // pass + } + + override def visit(sRef: SReference): Unit = { + // pass + } + +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/RelationCompartmentGeneratingVisitor.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/RelationCompartmentGeneratingVisitor.scala new file mode 100644 index 0000000000000000000000000000000000000000..c4bdc7d4590851a32e7f408a02ef3a19264692db --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/RelationCompartmentGeneratingVisitor.scala @@ -0,0 +1,165 @@ +package org.rosi_project.model_sync.generator.sync + +import org.rosi_project.model_sync.generator.acr_model._ +import org.rosi_project.model_sync.generator.acr_model.types.SList +import org.rosi_project.model_sync.generator.acr_model.types.GenericSequence +import org.rosi_project.model_sync.generator.acr_model.types.PredefTypes + +class RelationCompartmentGeneratingVisitor extends SModelVisitor { + + override def visit(sModel: SModel): Unit = { + var allReferences: Seq[SReference] = Seq.empty + var newClasses: Seq[SRelationalCompartmentClass] = Seq.empty + sModel.getModelClasses.foreach(cls => { + cls.getReferences.foreach(ref => { + //he should only create a relational compartment for one relation and not for both directions + var shouldRun = true + if (ref.hasOpposite) { + //has opposite + if (!allReferences.contains(ref.oppositeRef) && !allReferences.contains(ref)) { + //did not handle this reference yet + if (ref.getImportant == ref.oppositeRef) { + //should run the other one + shouldRun = false + //add this element to the list + allReferences = allReferences ++ ref + } else { + //should run this one + shouldRun = true + //add the other one to the list + allReferences = allReferences ++ ref.oppositeRef + } + } else if (allReferences.contains(ref)) { + //this reference is in the list so he should not work with it + shouldRun = false + } + } + + if (shouldRun) { + var attType = ref.getTypeElement + if (attType.isInstanceOf[GenericSequence]) + { + attType = (attType.asInstanceOf[GenericSequence]).typeParam + } + + val className = cls.getName + ref.getName.capitalize + attType.getName; + //println("ClassName: " + className) + val newClass = new SRelationalCompartmentClass(className, cls.getPackage, connectedRef = ref, sClass = cls, tClass = attType) + + //attributes + val sourceAtt = SAttribute("sInstance", cls) + val targetAtt = SAttribute("tInstance", attType) + sourceAtt.setVisibility(MethodVisibility.privateVis) + sourceAtt.isFinal = true + targetAtt.setVisibility(MethodVisibility.privateVis) + targetAtt.isFinal = true + newClass.setAttributes(sourceAtt ++ targetAtt) + + //internal classes + val sourceClass = new SInnerClass("Source", externalClass = newClass) + val targetClass = new SInnerClass("Target", externalClass = newClass) + + //create own toString Method + sourceClass.addMethod(new SMethod( + name = "toString", + result = PredefTypes.String, + params = Seq.empty, + implementation = Seq(SMethodStatement(s""" "S: (" + sInstance + ")" """)), + overrides = true)) + targetClass.addMethod(new SMethod( + name = "toString", + result = PredefTypes.String, + params = Seq.empty, + implementation = Seq(SMethodStatement(s""" "T: (" + tInstance + ")" """)), + overrides = true)) + + //relation types with containment and opposite values + if (ref.containment) { + if (ref.hasOpposite) { + sourceClass.addParent(PredefRsumTypes.ICOMPOSITION_SOURCE_STYPE) + targetClass.addParent(PredefRsumTypes.ICOMPOSITION_TARGET_STYPE) + newClass.addParent(PredefRsumTypes.ICOMPOSITION_STYPE) + } else { + sourceClass.addParent(PredefRsumTypes.IDIRECT_COMPOSITION_SOURCE_STYPE) + targetClass.addParent(PredefRsumTypes.IDIRECT_COMPOSITION_TARGET_STYPE) + newClass.addParent(PredefRsumTypes.IDIRECT_COMPOSITION_STYPE) + } + } else { + if (ref.hasOpposite) { + sourceClass.addParent(PredefRsumTypes.IASSOCIATION_SOURCE_STYPE) + targetClass.addParent(PredefRsumTypes.IASSOCIATION_TARGET_STYPE) + newClass.addParent(PredefRsumTypes.IASSOCIATION_STYPE) + } else { + sourceClass.addParent(PredefRsumTypes.IDIRECT_ASSOCIATION_SOURCE_STYPE) + targetClass.addParent(PredefRsumTypes.IDIRECT_ASSOCIATION_TARGET_STYPE) + newClass.addParent(PredefRsumTypes.IDIRECT_ASSOCIATION_STYPE) + } + } + + newClass.addInternalClass(sourceClass) + newClass.addInternalClass(targetClass) + + //method implementation + val impl: Seq[SMethodStatement] = (SMethodStatement("this.source = new Source()") + ++ SMethodStatement("this.target = new Target()") + ++ SMethodStatement("sInstance play this.source") + ++ SMethodStatement("tInstance play this.target")) + + //add methods to relational compartment + newClass.addMethod(new SMethod ( + name = "internalInitialize", + result = PredefTypes.Unit, + params = Seq.empty, + implementation = impl, + overrides = true)) + newClass.addMethod(new SMethod( + name = "toString", + result = PredefTypes.String, + params = Seq.empty, + implementation = Seq(SMethodStatement(s""" "[$className " + source + ", " + target + "]" """)), + overrides = true)) + + newClass.addMethod(new SMethod ( + name = "getSourceIns", + result = cls, + params = Seq.empty, + implementation = Seq(SMethodStatement(s"return sInstance")), + overrides = false)) + + newClass.addMethod(new SMethod ( + name = "getTargetIns", + result = attType, + params = Seq.empty, + implementation = Seq(SMethodStatement(s"return tInstance")), + overrides = false)) + + newClasses = newClasses :+ newClass + } + }) + }) + newClasses.foreach(classe => { + sModel.addRelationalCompartment(classe) + }) + } + + override def visit(sClass: SClass): Unit = { + // pass + } + + override def visit(sAttr: SAttribute): Unit = { + // pass + } + + override def visit(sMethod: SMethod): Unit = { + // pass + } + + override def visit(sType: SType): Unit = { + // pass + } + + override def visit(sRef: SReference): Unit = { + // pass + } + +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/SumModelReadingVisitor.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/SumModelReadingVisitor.scala new file mode 100644 index 0000000000000000000000000000000000000000..30b22945d4735762505011b3159c7da2f643dd92 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/SumModelReadingVisitor.scala @@ -0,0 +1,230 @@ +package org.rosi_project.model_sync.generator.sync + +import org.rosi_project.model_sync.generator.acr_model._ +import org.rosi_project.model_sync.generator.PackageNames +import org.rosi_project.model_sync.generator.acr_model.types.PredefEcoreTypes +import org.rosi_project.model_sync.generator.acr_model.types.PredefTypes +import org.rosi_project.model_sync.generator.acr_model.types.GenericSequence +import org.rosi_project.model_sync.generator.GeneratorConfig +import org.rosi_project.model_sync.generator.Creation + +/** + * Read EMF and Ecore models. + * + * @author Christopher Werner + */ +class SumModelReadingVisitor(config: GeneratorConfig) extends SModelVisitor { + + override def visit(sModel: SModel): Unit = { + //println("++++++++++++++++++++++++++++++++++++++++++++++") + val creatorSum = new SClass("Creation" + sModel.getName + "Sum", PackageNames.creationPkgName) + val creatorSync = new SClass("Creation" + sModel.getName + "Sync", PackageNames.creationPkgName) + val creatorInterface = new SClass("ICreation" + sModel.getName, PackageNames.creationPkgName, SClassType.normalTrait) + val loader = new SClass("Loader" + sModel.getName, PackageNames.creationPkgName) + + creatorSum.addParent(creatorInterface) + creatorSync.addParent(creatorInterface) + + val loadEcore = new SMethod( + name = "loadEcore", + result = PredefEcoreTypes.EcoreObject, + params = Seq(SMethodParameter("pathMeta", PredefTypes.String), SMethodParameter("pathInstance", PredefTypes.String)), + implementation = Seq( + SMethodStatement(content = s"require(null != pathMeta && pathMeta.nonEmpty && null != pathInstance && pathInstance.nonEmpty)"), + SMethodStatement(content = s"val resourceSet = new ResourceSetImpl()", usedTypes = Set(PredefEcoreTypes.ResourceSetImpl)), + SMethodStatement(content = s"resourceSet.getResourceFactoryRegistry.getExtensionToFactoryMap.put(Resource.Factory.Registry.DEFAULT_EXTENSION, new XMIResourceFactoryImpl())", usedTypes = Set(PredefEcoreTypes.XMIResourceFactoryImpl, PredefEcoreTypes.Resource)), + SMethodStatement(content = s"val ressourceMeta = resourceSet.getResource(URI.createFileURI(pathMeta), true)", usedTypes = Set(PredefEcoreTypes.URI)), + SMethodStatement(content = s"val packageMeta = ressourceMeta.getContents().get(0)"), + SMethodStatement(content = s"require(null != ressourceMeta)"), + SMethodStatement(content = s"require(!ressourceMeta.getContents.isEmpty)"), + SMethodStatement(content = s"""resourceSet.getPackageRegistry().put("${sModel.getNsURI}", packageMeta);"""), + SMethodStatement(content = s"val ressourceModel = resourceSet.getResource(URI.createURI(pathInstance), true);"), + SMethodStatement(content = s"return ressourceModel.getContents().get(0)"))) + loader.addMethod(loadEcore) + + val createModelInstanceSum = new SMethod( + name = s"create${sModel.getName}Instance", + result = PredefTypes.Unit, + params = Seq(SMethodParameter("obj", PredefEcoreTypes.EcoreObject), SMethodParameter("creator", creatorInterface)), + implementation = Seq( + SMethodStatement(content = s"createObj(obj, creator)"), + SMethodStatement(content = s"obj.eAllContents().asScala.foreach(o => {", usedTypes = Set(PredefTypes.ScalaConverter)), + SMethodStatement(content = s"createObj(o, creator)"), + SMethodStatement(content = s"})"), + SMethodStatement(content = s"createRef(obj, creator)"), + SMethodStatement(content = s"obj.eAllContents().asScala.foreach(o => {"), + SMethodStatement(content = s"createRef(o, creator)"), + SMethodStatement(content = s"})"))) + loader.addMethod(createModelInstanceSum) + + val createObj = new SMethod( + name = "createObj", + result = PredefTypes.Unit, + params = Seq(SMethodParameter("obj", PredefEcoreTypes.EcoreObject), SMethodParameter("creator", creatorInterface)), + implementation = Seq.empty) + createObj.setVisibility(MethodVisibility.privateVis) + var createObjImpl = Seq(SMethodStatement(content = s"var objName = obj.eClass.getName"), + SMethodStatement(content = s"objName match {")) + + val createRef = new SMethod( + name = "createRef", + result = PredefTypes.Unit, + params = Seq(SMethodParameter("o1", PredefEcoreTypes.EcoreObject), SMethodParameter("creator", creatorInterface)), + implementation = Seq.empty) + createRef.setVisibility(MethodVisibility.privateVis) + var stringList: Set[String] = Set.empty + var createRefImpl = Seq(SMethodStatement(content = s"val o2 = o1.eGet(sf).asInstanceOf[EObject]"), + SMethodStatement(content = s"val o1Name = o1.eClass().getName"), + SMethodStatement(content = s"val o2Name = o2.eClass().getName")) + + creatorSum.augmentConstructor(SMethodStatement(content = s"var mapping: Map[EObject, Object] = Map.empty", usedTypes = Set(PredefEcoreTypes.EcoreObject))) + creatorSync.augmentConstructor(SMethodStatement(content = s"var mapping: Map[EObject, Object] = Map.empty", usedTypes = Set(PredefEcoreTypes.EcoreObject))) + + sModel.getModelClasses.filter(c => !c.isAbstract && !c.isInterface).foreach(c => { + //method for trait + val methodTrait = new SMethod( + name = s"create${c.getName}", + result = PredefTypes.Unit, + params = c.getAttributeConstructorParameters :+ SMethodParameter("id", PredefEcoreTypes.EcoreObject), + implementation = Seq.empty) + creatorInterface.addMethod(methodTrait) + + //method for sync + val methodSum = new SMethod( + name = s"create${c.getName}", + result = PredefTypes.Unit, + params = c.getAttributeConstructorParameters :+ SMethodParameter("id", PredefEcoreTypes.EcoreObject), + implementation = Seq( + SMethodStatement(content = s"mapping += (id -> new ${c.getName}(${c.getAttributeConstructorParameters.map(m => m.getName).mkString(", ")}))", usedTypes = Set(c))), + overrides = true) + creatorSum.addMethod(methodSum) + + //method for sync + val methodSync = new SMethod( + name = s"create${c.getName}", + result = PredefTypes.Unit, + params = c.getAttributeConstructorParameters :+ SMethodParameter("id", PredefEcoreTypes.EcoreObject), + implementation = Seq( + SMethodStatement(content = s"mapping += (id -> new ${c.getName}(${c.getAllConstructorParameters.map(m => if (m.getType.isInstanceOf[GenericSequence]) "Set.empty" else if (m.getType.isInstanceOf[SClass]) "null" else m.getName).mkString(", ")}))", usedTypes = Set(c))), //TODO + overrides = true) + creatorSync.addMethod(methodSync) + + var types = c.getAttributeConstructorParameters.map(m => m.getType) + var s = c.getAttributeConstructorParameters.map(m => s"""obj.eGet(obj.eClass().getEStructuralFeature("${m.getName}"))${if (m.getTypeName == "String") ".toString()" else s".asInstanceOf[${m.getTypeName}${if(m.getType.isInstanceOf[SEnum]) ".Value" else ""}]"} """).mkString(", ") + if (s.isEmpty()) { + s = "obj" + } else { + s = s + ", obj" + } + createObjImpl = createObjImpl :+ SMethodStatement(content = s"""case "${c.getName}" => creator.create${c.getName}(${s})""", types.toSet) + }) + + sModel.getRelationalCompartments.foreach(r => { + var rc = r.asInstanceOf[SRelationalCompartmentClass] + //method for trait + val methodTrait = new SMethod( + name = s"create${r.getName}", + result = PredefTypes.Unit, + params = Seq(SMethodParameter("s", PredefEcoreTypes.EcoreObject), SMethodParameter("t", PredefEcoreTypes.EcoreObject)), + implementation = Seq.empty) + creatorInterface.addMethod(methodTrait) + + //sum method + val methodSum = new SMethod( + name = s"create${r.getName}", + result = PredefTypes.Unit, + params = Seq(SMethodParameter("s", PredefEcoreTypes.EcoreObject), SMethodParameter("t", PredefEcoreTypes.EcoreObject)), + implementation = Seq( + SMethodStatement(content = s"val s1 = mapping.get(s).get.asInstanceOf[${rc.sClass.getName}]"), + SMethodStatement(content = s"val t1 = mapping.get(t).get.asInstanceOf[${rc.tClass.getName}]"), + SMethodStatement(content = s"(new ${rc.getName}(s1, t1)).initialize()", usedTypes = Set(rc, rc.sClass, rc.tClass))), + overrides = true) + creatorSum.addMethod(methodSum) + + //sync method + val methodSync = new SMethod( + name = s"create${r.getName}", + result = PredefTypes.Unit, + params = Seq(SMethodParameter("s", PredefEcoreTypes.EcoreObject), SMethodParameter("t", PredefEcoreTypes.EcoreObject)), + implementation = Seq.empty, + overrides = true) + var implMethodSync = Seq(SMethodStatement(content = s"val s1 = mapping.get(s).get.asInstanceOf[${rc.sClass.getName}]", usedTypes = Set(rc.sClass, rc.tClass)), + SMethodStatement(content = s"val t1 = mapping.get(t).get.asInstanceOf[${rc.tClass.getName}]")) + if (rc.connectedRef.getTypeElement.isInstanceOf[GenericSequence]) { + //add -> add method + implMethodSync = implMethodSync :+ SMethodStatement(content = s"s1.add${rc.connectedRef.getName.capitalize}(t1)") + } else { + //add -> set method + implMethodSync = implMethodSync :+ SMethodStatement(content = s"s1.set${rc.connectedRef.getName.capitalize}(t1)") + } + if (rc.connectedRef.hasOpposite) { + if (rc.connectedRef.oppositeRef.getTypeElement.isInstanceOf[GenericSequence]) { + //add -> add method + implMethodSync = implMethodSync :+ SMethodStatement(content = s"t1.add${rc.connectedRef.oppositeRef.getName.capitalize}(s1)") + } else { + //add -> set method + implMethodSync = implMethodSync :+ SMethodStatement(content = s"t1.set${rc.connectedRef.oppositeRef.getName.capitalize}(s1)") + } + } + methodSync.implementation = implMethodSync + creatorSync.addMethod(methodSync) + + //TODO: anpassen + val reference = rc.connectedRef.getMinimalConnection + if (reference != null) { + if (reference == rc.connectedRef) { + createRefImpl = createRefImpl :+ SMethodStatement(content = s"""if (o1Name.contains("${rc.sClass.getName}") && sfName == "${reference.getName}" && o2Name.contains("${rc.tClass.getName}")) {""") + createRefImpl = createRefImpl :+ SMethodStatement(content = s"creator.create${rc.getName}(o1, o2)") + createRefImpl = createRefImpl :+ SMethodStatement(content = "}") + } else { + createRefImpl = createRefImpl :+ SMethodStatement(content = s"""if (o1Name.contains("${rc.tClass.getName}") && sfName == "${reference.getName}" && o2Name.contains("${rc.sClass.getName}")) {""") + createRefImpl = createRefImpl :+ SMethodStatement(content = s"creator.create${rc.getName}(o2, o1)") + createRefImpl = createRefImpl :+ SMethodStatement(content = "}") + } + stringList += reference.getName + } + }) + + createObjImpl = createObjImpl :+ SMethodStatement(content = "case _ =>") + createObjImpl = createObjImpl :+ SMethodStatement(content = "}") + createObj.implementation = createObjImpl + loader.addMethod(createObj) + + createRefImpl = createRefImpl :+ SMethodStatement(content = "}})") + createRefImpl = Seq(SMethodStatement(content = s"o1.eClass().getEAllReferences.forEach(sf => {"), + SMethodStatement(content = s"val sfName = sf.getName"), + SMethodStatement(content = s"""if(${stringList.map(str => s"""sfName == "${str}" """).mkString(" || ")}) {""")) ++ createRefImpl + createRef.implementation = createRefImpl + loader.addMethod(createRef) + + //add the new classes as model classes + if (config.create == Creation.rolesync) { + sModel.addProviderClass(creatorSync) + } else { + sModel.addProviderClass(creatorSum) + } + sModel.addProviderClass(creatorInterface) + sModel.addProviderClass(loader) + } + + override def visit(sClass: SClass): Unit = { + // pass + } + + override def visit(sAttr: SAttribute): Unit = { + // pass + } + + override def visit(sRef: SReference): Unit = { + // pass + } + + override def visit(sMethod: SMethod): Unit = { + // pass + } + + override def visit(sType: SType): Unit = { + // pass + } + +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/SyncEnhancingVisitor.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/SyncEnhancingVisitor.scala index 23e433740969af76c2c8dff3b0ff702283d61443..b4c550d133b63881f06ddd750718644770bbc759 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/sync/SyncEnhancingVisitor.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/SyncEnhancingVisitor.scala @@ -1,77 +1,75 @@ package org.rosi_project.model_sync.generator.sync -import org.rosi_project.model_sync.generator.ModelConfig import org.rosi_project.model_sync.generator.acr_model._ -import org.rosi_project.model_sync.sync.PlayerSync -import org.rosi_project.model_sync.sync.ISynchronizationCompartment -/** Augments [[SClass SClasses]] with the necessary method calls to make it usable in a - * synchronization context. - * - * The following modifications are performed: - * - the class (or its furthest parent) becomes a subclass of [[PlayerSync]] - * - [[PlayerSync.buildClass()]] will be called in the constructor - * - each setter will notify the synchronization context about the change - * - * @see [[ISynchronizationCompartment]] - * @author Rico Bergmann - */ -class SyncEnhancingVisitor(val modelCfg: ModelConfig) extends SModelVisitor { - - private var additionalSyncClasses: Seq[SClass] = Seq.empty +/** + * Augments [[SClass SClasses]] with the necessary method calls to make it usable in a + * synchronization context. + * + * The following modifications are performed: + * - the class (or its furthest parent) becomes a subclass of [[PlayerSync]] + * - [[PlayerSync.buildClass()]] will be called in the constructor + * - each setter will notify the synchronization context about the change + * + * @see [[ISynchronizationCompartment]] + * @author Rico Bergmann + */ +class SyncEnhancingVisitor() extends SModelVisitor { override def visit(sModel: SModel): Unit = { - additionalSyncClasses.foreach(sModel.addModelClass) - - modelCfg.init.nested.foreach(_.foreach(model => sModel.addModelClass(new InitialModelTemplate(model)))) - sModel.addModelClass(new InitialModelTemplate(modelCfg.init)) - sModel.addModelClass(new ModelProviderTemplate(modelCfg.init)) - + sModel.getModelClasses.foreach(cls => { + //TODO: do not have in mind trait extends abstract extends trait hierarchy + if (cls.isAbsoluteRootClassOrInterface) { + cls.addParent(PredefSyncTypes.PLAYER_SYNC_STYPE) + } + cls.getMethods.foreach(m => { + extractSetterAttr(m).foreach(attr => m.augmentImplementation(SMethodStatement(s"+this $attr"))) + }) + }) } override def visit(sClass: SClass): Unit = { - sClass.getInheritanceHierarchy.reverse.headOption.foreach{ - case root: SClass => root.setParent(SyncEnhancingVisitor.PLAYER_SYNC_STYPE) - case tp => sys.error(s"May not enhance $tp as it is a type and not a class") - } - - sClass.augmentConstructor(SyncEnhancingVisitor.PLAYER_SYNC_INIT) - - additionalSyncClasses = additionalSyncClasses :+ new ConstructorTemplate(sClass) - sClass.attributes.foreach(attr => { - additionalSyncClasses = additionalSyncClasses :+ new ModifierTemplate(sClass, attr) - }) + // pass } override def visit(sAttr: SAttribute): Unit = { // pass } + override def visit(sRef: SReference): Unit = { + // pass + } + override def visit(sMethod: SMethod): Unit = { - extractSetterAttr(sMethod).foreach(attr => sMethod.augmentImplementation(SMethodStatement(s"+this change$attr ()"))) + // pass } override def visit(sType: SType): Unit = { // pass } - /** Tries to get the attribute's name from a setter method. - * - * A ''valid'' setter will have the following signature: `setXyz(x: T): Unit` (the parameter's - * name does not matter). - * - * Mind that the first letter will be left uppercase (i.e. `Xyz` will be returned although the - * actual attribute may be `xyz`) - * - * @param sMethod the method to analyze. May be any method (not necessarily a setter) but never - * `null`. - * @return the attribute's name if `sMethod` was a valid setter. '''The first letter will be left - * uppercase.''' - */ + /** + * Tries to get the attribute's name from a setter method. + * + * A ''valid'' setter will have the following signature: `setXyz(x: T): Unit` (the parameter's + * name does not matter). + * + * Mind that the first letter will be left uppercase (i.e. `Xyz` will be returned although the + * actual attribute may be `xyz`) + * + * @param sMethod the method to analyze. May be any method (not necessarily a setter) but never + * `null`. + * @return the attribute's name if `sMethod` was a valid setter. '''The first letter will be left + * uppercase.''' + */ private def extractSetterAttr(sMethod: SMethod): Option[String] = { - sMethod.name match { + sMethod.getName match { case SyncEnhancingVisitor.Setter(attrName) => - Option(attrName) + Option("syncSet" + attrName + " ()") + case SyncEnhancingVisitor.Adder(attrName) => + Option("syncAdd" + attrName + s" (${attrName.charAt(0).toLower})") + case SyncEnhancingVisitor.Remover(attrName) => + Option("syncRemove" + attrName + s" (${attrName.charAt(0).toLower})") case _ => None } @@ -80,15 +78,12 @@ class SyncEnhancingVisitor(val modelCfg: ModelConfig) extends SModelVisitor { } -/** The companion contains some static values. - */ +/** + * The companion contains some static values. + */ object SyncEnhancingVisitor { - private val Setter = """set([A-Z][a-zA-z0-9]*)""".r - - private val PLAYER_SYNC_CLASS = classOf[PlayerSync] - private val PLAYER_SYNC_STYPE = SType(PLAYER_SYNC_CLASS.getSimpleName, PLAYER_SYNC_CLASS.getPackage.getName) - + private val Adder = """add([A-Z][a-zA-z0-9]*)""".r + private val Remover = """remove([A-Z][a-zA-z0-9]*)""".r private val PLAYER_SYNC_INIT = SMethodStatement("buildClass()") - } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/ToStringMethods.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/ToStringMethods.scala new file mode 100644 index 0000000000000000000000000000000000000000..39d0ed6c7cf1e8297c341232a68239d17360d12c --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/ToStringMethods.scala @@ -0,0 +1,39 @@ +package org.rosi_project.model_sync.generator.sync + +import org.rosi_project.model_sync.generator.acr_model.SMethod +import org.rosi_project.model_sync.generator.acr_model.types.PredefTypes +import org.rosi_project.model_sync.generator.acr_model.SMethodStatement +import org.rosi_project.model_sync.generator.acr_model.SClass + +object ToStringMethods { + + def normalToStringMethod(cls: SClass): SMethod = { + new SMethod( + name = "toString", + result = PredefTypes.String, + params = Seq.empty, + implementation = Seq(SMethodStatement((List(s""" "${cls.getName}:" """) ++ cls.getOnlyDeepAttributes.map(attr => s""" " ${attr.getName}=" + ${attr.getName} """)).mkString(" + "))), + overrides = true + ) + } + + def joinToStringMethod(s: String): SMethod = { + new SMethod( + name = "toString", + result = PredefTypes.String, + params = Seq.empty, + implementation = Seq(SMethodStatement(s""" "JOIN ${s}: " + baseObj + " " + otherObj """)), + overrides = true + ) + } + + def onlyStringToStringMethod(s: String): SMethod = { + new SMethod( + name = "toString", + result = PredefTypes.String, + params = Seq.empty, + implementation = Seq(SMethodStatement(s""" "${s}" """)), + overrides = true + ) + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/ViewGeneratingVisitor.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/ViewGeneratingVisitor.scala new file mode 100644 index 0000000000000000000000000000000000000000..c290a7add0719d5ce0ddc2e3bda469c1ac06747e --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/ViewGeneratingVisitor.scala @@ -0,0 +1,138 @@ +package org.rosi_project.model_sync.generator.sync + +import org.rosi_project.model_sync.generator.acr_model._ +import org.rosi_project.model_sync.generator.acr_model.types._ +import org.rosi_project.model_sync.generator.PackageNames + +class ViewGeneratingVisitor extends SModelVisitor { + + override def visit(sModel: SModel): Unit = { + + val viewCompartment = new SViewClass(sModel.getName.capitalize + PackageNames.viewPostName, PackageNames.viewPkgName) + var newInternalRoles: Seq[SInnerViewNaturalClass] = Seq.empty + var newInternalRelationalRoles: Seq[SInnerViewRelationalClass] = Seq.empty + viewCompartment.addParent(PredefRsumTypes.IVIEW_COMPARTMENT_STYPE) + + //Iterate over all Model classes and create natural internal role classes + sModel.getModelClasses.foreach(cls => { + val internalClass = new SInnerViewNaturalClass(cls.getName + PackageNames.viewRolePostName, + _sClassType = cls.sClassType, + _externalClass = viewCompartment, + sumSource = cls) + //sets the attributes from the source class + var newAtts: Set[SAttribute] = Set.empty + cls.getAttributes.foreach(attr => { + var newAtt = SAttribute(attr.getName, attr.getTypeElement, attr.unique) + newAtt.setVisibility(MethodVisibility.protectedVis) + newAtt.isFinal = true + newAtts += newAtt + }) + internalClass.setAttributes(newAtts.toSeq) + newInternalRoles = newInternalRoles :+ internalClass + viewCompartment.addInternalClass(internalClass) + }) + + //Now add the parents to all natural internal roles first + newInternalRoles.foreach(inner => { + val cls = inner.sumSource + //set inheritance to abstract view role + if (cls.isRootClass) { + inner.addParent(PredefRsumTypes.AVIEW_ROLE_STYPE) + } + //add parents + cls.getAllParents().foreach(p => { + val existing: Option[STypedElement] = newInternalRoles.find(existing => existing.getName == p.getName + PackageNames.viewRolePostName) + if (!existing.isEmpty) { + inner.addParent(existing.get) + } + }) + }) + + //add now the messages because they can depend on the parents + newInternalRoles.foreach(inner => { + //add initialize method if necessary + if (!inner.isAbstract && !inner.isInterface) { + inner.addMethod(ViewMethods.getIsRelationalMethod(false)) + inner.addMethod(ViewMethods.getCreationObjectMethod(inner)) + } + //add delete method + inner.addMethod(ToStringMethods.onlyStringToStringMethod("VNR: " + inner.getName)) + inner.addMethod(ViewMethods.getDeleteElementNaturalMethod(inner)) + //add getter and setter for attributes in the inner class + inner.getAttributes.foreach(attr => { + inner.addMethod(ViewMethods.getViewAttributeGetter(attr)) + inner.addMethod(ViewMethods.getViewAttributeSetter(attr)) + }) + }) + + //Iterate over all Relational compartments and create relational internal role classes + sModel.getRelationalCompartments.foreach(r => { + var sourceAtt: SAttribute = null + var targetAtt: SAttribute = null + //set as attributes the other classes + var sourceRole: SInnerViewNaturalClass = null + var targetRole: SInnerViewNaturalClass = null + r.getAttributes.foreach(attr => { + newInternalRoles.foreach(inte => { + if (inte.getName == attr.getTypeElement.getName + PackageNames.viewRolePostName) { + if (attr.getName == "sInstance") { + sourceRole = inte + sourceAtt = new SAttribute("source", inte) + sourceAtt.isFinal = true + sourceAtt.setVisibility(MethodVisibility.privateVis) + } else { + targetRole = inte + targetAtt = new SAttribute("target", inte) + targetAtt.isFinal = true + targetAtt.setVisibility(MethodVisibility.privateVis) + } + } + }) + }) + val internalClass = new SInnerViewRelationalClass(r.getName + PackageNames.viewRolePostName, _externalClass = viewCompartment, + sumSource = r.asInstanceOf[SRelationalCompartmentClass], viewSource = sourceRole, viewTarget = targetRole) + internalClass.setAttributes(sourceAtt ++ targetAtt) + internalClass.addMethod(ViewMethods.getIsRelationalMethod(true)) + internalClass.addMethod(ViewMethods.getCreationObjectMethod(internalClass, true, true)) + internalClass.addMethod(ViewMethods.getDeleteElementRelationMethod(internalClass, true, true)) + internalClass.addMethod(ToStringMethods.onlyStringToStringMethod("VRR: " + internalClass.getName)) + ViewMethods.getSourceAndTargetGetter(internalClass).foreach(internalClass.addMethod(_)) + internalClass.addParent(PredefRsumTypes.AVIEW_ROLE_STYPE) + ViewMethods.createAllReferenceLinks(internalClass, true, true) + newInternalRelationalRoles = newInternalRelationalRoles :+ internalClass + viewCompartment.addInternalClass(internalClass) + }) + + //add methods that must be override from the view trait + viewCompartment.addMethod(ViewMethods.getIsViewableMethod((sModel.getRelationalCompartments ++ sModel.getModelClasses).toSet)) + viewCompartment.addMethod(ViewMethods.getViewNameMethod(viewCompartment)) + viewCompartment.addMethod(ViewMethods.getGetNaturalRoleMethod(newInternalRoles.toSet)) + viewCompartment.addMethod(ViewMethods.getGetRelationalRoleMethod(newInternalRelationalRoles.toSet)) + viewCompartment.addMethod(ToStringMethods.onlyStringToStringMethod("VC: " + viewCompartment.getName)) + //Create methods to create elements from the view + ViewMethods.getCreateNaturalRoleMethods(newInternalRoles.toSet).foreach(viewCompartment.addMethod(_)) + + //add the view to the list for generating views + sModel.addViewCompartment(viewCompartment) + } + + override def visit(sClass: SClass): Unit = { + // pass + } + + override def visit(sAttr: SAttribute): Unit = { + // pass + } + + override def visit(sMethod: SMethod): Unit = { + // pass + } + + override def visit(sType: SType): Unit = { + // pass + } + + override def visit(sRef: SReference): Unit = { + // pass + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/ViewMethods.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/ViewMethods.scala new file mode 100644 index 0000000000000000000000000000000000000000..ed616df0b225be8ec05e1b0b879399d424494c9e --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/ViewMethods.scala @@ -0,0 +1,317 @@ +package org.rosi_project.model_sync.generator.sync + +import org.rosi_project.model_sync.generator.support.ExtendedString.stringToExtended +import org.rosi_project.model_sync.generator.acr_model.types.PredefTypes +import org.rosi_project.model_sync.generator.acr_model._ +import org.rosi_project.model_sync.generator.acr_model.types.SSet + +object ViewMethods { + + def getDeleteElementRelationMethod(ref: SInnerViewRelationalClass, createNormal: Boolean, createOpposite: Boolean): SMethod = { + val method = new SMethod( + name = "deleteElement", + result = PredefTypes.Unit, + params = Seq.empty, + implementation = Seq.empty, + true) + var impl: Seq[SMethodStatement] = Seq.empty + if (createNormal) { + impl = impl :+ SMethodStatement(content = s"source.remove${ref.sumSource.connectedRef.getName.capitalize}Intern(this)") + } + if (createOpposite && ref.sumSource.connectedRef.hasOpposite) { + impl = impl :+ SMethodStatement(content = s"target.remove${ref.sumSource.connectedRef.oppositeRef.getName.capitalize}Intern(this)") + } + impl = impl :+ SMethodStatement(content = "super.deleteElement()") + method.implementation = impl + method + } + + def getDeleteElementNaturalMethod(ref: SInnerViewNaturalClass): SMethod = { + val method = new SMethod( + name = "deleteElement", + result = PredefTypes.Unit, + params = Seq.empty, + implementation = Seq(SMethodStatement(content = "super.deleteElement()")), + true) + method + } + + def getSourceAndTargetGetter(ref: SInnerViewRelationalClass): Seq[SMethod] = { + (new SMethod( + name = "getSource", + result = ref.viewSource, + params = Seq.empty, + implementation = Seq(SMethodStatement("source"))) ++ + new SMethod( + name = "getTarget", + result = ref.viewTarget, + params = Seq.empty, + implementation = Seq(SMethodStatement("target")))) + } + + def getCreateNaturalRoleMethods(naturalRoles: Set[SInnerViewNaturalClass]): Seq[SMethod] = { + var methods: Seq[SMethod] = Seq.empty + naturalRoles.foreach(nr => { + if (!nr.isAbstract && !nr.isInterface) { + val method = new SMethod( + name = s"create${nr.sumSource.getName}", + result = nr, + params = nr.getAllConstructorParameters, + implementation = Seq(SMethodStatement(content = s"return new ${nr.getName}(${nr.getAllConstructorParameters.map(m => m.getName).mkString(", ")})"))) + methods = methods :+ method + } + }) + methods + } + + def getIsRelationalMethod(relational: Boolean): SMethod = { + val method = new SMethod( + name = "isRelational", + result = PredefTypes.Boolean, + params = Seq.empty, + implementation = Seq(SMethodStatement(content = s"return ${relational}")), + true) + method.setVisibility(MethodVisibility.protectedVis) + method + } + + def getCreationObjectMethod(nat: SInnerViewNaturalClass): SMethod = { + val method = new SMethod( + name = "getCreationObject", + result = PredefTypes.Object, + params = Seq.empty, + implementation = Seq.empty, + true) + if (nat.sumSource.isInstanceOf[SJoinClass]) { + val jcls = nat.sumSource.asInstanceOf[SJoinClass] + method.implementation = Seq(SMethodStatement(content = s"return new ${jcls.getName}(new ${jcls.base.getName}(" + + s"${jcls.base.getAllConstructorParameters.map(HelperFunctions.initialAttributeDoing(_, nat.getDeepStructuralFeatures)).mkString(", ")}), new ${jcls.other.getName}(" + + s"${jcls.other.getAllConstructorParameters.map(HelperFunctions.initialAttributeDoing(_, nat.getDeepStructuralFeatures)).mkString(", ")}))", usedTypes = Set(jcls.other, jcls.base))) + } else { + method.implementation = Seq(SMethodStatement(content = s"return new ${nat.sumSource.getName}(" + + s"${nat.sumSource.getAllConstructorParameters.map(HelperFunctions.initialAttributeDoing(_, nat.getDeepStructuralFeatures)).mkString(", ")})")) + } + method.setVisibility(MethodVisibility.protectedVis) + method + } + + def getCreationObjectMethod(ref: SInnerViewRelationalClass, createNormal: Boolean, createOpposite: Boolean): SMethod = { + val method = new SMethod( + name = "getCreationObject", + result = PredefTypes.Object, + params = Seq.empty, + implementation = Seq(SMethodStatement(content = "return")), + true) + var statements: Seq[SMethodStatement] = Seq.empty + if (ref.sumSource.connectedRef.hasOpposite && createOpposite) { + statements = Seq(SMethodStatement(content = s"target.set${ref.sumSource.connectedRef.oppositeRef.getName.capitalize}Intern(this)")) + } + if (createNormal) { + statements = statements ++ SMethodStatement(content = s"source.set${ref.sumSource.connectedRef.getName.capitalize}Intern(this)") + } + statements = statements ++ Seq(SMethodStatement(content = s"""val sp: ${ref.sumSource.sClass.getName} = getPlayerOfType(source, "${ref.sumSource.sClass.getName}").asInstanceOf[${ref.sumSource.sClass.getName}]""", + usedTypes = Set(ref.viewSource.sumSource)), + SMethodStatement(content = s"""val tp: ${ref.sumSource.tClass.getName} = getPlayerOfType(target, "${ref.sumSource.tClass.getName}").asInstanceOf[${ref.sumSource.tClass.getName}]""", + usedTypes = Set(ref.viewTarget.sumSource)), + SMethodStatement(content = s"val v: ${ref.sumSource.getName} = new ${ref.sumSource.getName}(sp, tp)", + usedTypes = Set(ref.sumSource)), + SMethodStatement(content = s"return v")) + method.implementation = statements + method.setVisibility(MethodVisibility.protectedVis) + method + } + + def getGetNaturalRoleMethod(types: Set[SInnerViewNaturalClass]): SMethod = { + val method = new SMethod( + name = "getNaturalRole", + result = PredefRsumTypes.AVIEW_ROLE_STYPE, + params = Seq(SMethodParameter("className", PredefTypes.Object)), + implementation = Seq.empty) + var statements: Seq[SMethodStatement] = Seq.empty + types.foreach(t => { + if (!t.isAbstract && !t.isInterface) { + var statement = s"if (className.isInstanceOf[${t.sumSource.getName}]) return new " + + s"${t.getName}(${t.getAllConstructorParameters.map(HelperFunctions.classEmptyConstructorParameterCreation(_)).mkString(", ")})" + statements = statements :+ SMethodStatement(content = statement, usedTypes = Set(t)) + } + }) + statements = statements :+ SMethodStatement(content = "return null") + method.implementation = statements + method.setVisibility(MethodVisibility.protectedVis) + method + } + + def getGetRelationalRoleMethod(types: Set[SInnerViewRelationalClass]): SMethod = { + val method = new SMethod( + name = "getRelationalRole", + result = PredefRsumTypes.AVIEW_ROLE_STYPE, + params = Seq(SMethodParameter("className", PredefTypes.Object), SMethodParameter("sourceRole", PredefRsumTypes.AVIEW_ROLE_STYPE), SMethodParameter("targetRole", PredefRsumTypes.AVIEW_ROLE_STYPE)), + implementation = Seq.empty) + + var statements: Seq[SMethodStatement] = Seq.empty + types.foreach(t => { + var statement = s"if (className.isInstanceOf[${t.sumSource.getName}]) return new " + + s"${t.getName}(sourceRole.asInstanceOf[${t.viewSource.getName}], targetRole.asInstanceOf[${t.viewTarget.getName}])" + statements = statements :+ SMethodStatement(content = statement, usedTypes = Set(t)) + }) + statements = statements :+ SMethodStatement(content = "return null") + method.implementation = statements + method.setVisibility(MethodVisibility.protectedVis) + method + } + + def getIsViewableMethod(types: Set[SClass]): SMethod = { + val method = new SMethod( + name = "isViewable", + result = PredefTypes.Boolean, + params = Seq(SMethodParameter("className", PredefTypes.Object)), + implementation = Seq.empty) + var newTypes: Set[STypedElement] = Set.empty + types.filter(_.isInstanceOf[SJoinClass]).foreach(cls => { + newTypes = newTypes + cls.asInstanceOf[SJoinClass].base + cls.asInstanceOf[SJoinClass].other + }) + if (types.isEmpty) { + method.implementation = Seq(SMethodStatement(content = "return false", usedTypes = newTypes)) + } else { + val statement = s"if (${types.filter(t => !t.isAbstract && !t.isInterface).map(HelperFunctions.classNameCreation(_)).mkString(" || ")}) return true" + method.implementation = Seq(SMethodStatement(content = statement, usedTypes = types.asInstanceOf[Set[STypedElement]]), + SMethodStatement(content = "return false", usedTypes = newTypes)) + } + method.setVisibility(MethodVisibility.protectedVis) + method + } + + def getViewNameMethod(viewCompartment: SClass): SMethod = { + new SMethod( + name = "getViewName", + result = PredefTypes.String, + params = Seq.empty, + implementation = Seq(SMethodStatement(content = s"${viewCompartment.getName}.getViewName()", usedTypes = Set(PredefTypes.String))), + overrides = true) + } + + def getViewAttributeGetter(struc: SStructuralFeature): SMethod = { + new SMethod( + name = s"get${struc.getName.firstLetterToUpperCase}View", + result = struc.getTypeElement, + params = Seq.empty, + implementation = Seq(SMethodStatement(content = s"+this get${struc.getName.firstLetterToUpperCase}()", usedTypes = Set(struc.getTypeElement)))) + } + + def getViewAttributeSetter(struc: SStructuralFeature): SMethod = { + new SMethod( + name = s"set${struc.getName.firstLetterToUpperCase}View", + result = PredefTypes.Unit, + params = Seq(SMethodParameter(struc.getName.toLowerCase(), struc.getTypeElement)), + implementation = Seq(SMethodStatement(content = s"+this set${struc.getName.firstLetterToUpperCase}(${struc.getName.toLowerCase()})", usedTypes = Set(struc.getTypeElement)), + SMethodStatement(content = s"+this changeSomething()"))) + } + + def createAllReferenceLinks(refClass: SInnerViewRelationalClass, createNormal: Boolean, createOpposite: Boolean): Unit = { + val targetClass: SInnerViewNaturalClass = refClass.viewTarget + val sourceClass: SInnerViewNaturalClass = refClass.viewSource + val realRef: SReference = refClass.sumSource.connectedRef + val oppoRef: SReference = refClass.sumSource.connectedRef.oppositeRef + if (createNormal) { + createReferenceLinks(refClass, realRef, sourceClass, targetClass, true) + } + if (createOpposite) { + if (oppoRef != null) { + createReferenceLinks(refClass, oppoRef, targetClass, sourceClass, false) + } + } + } + + private def createReferenceLinks(refClass: SInnerViewRelationalClass, realRef: SReference, sourceClass: SInnerViewNaturalClass, targetClass: SInnerViewNaturalClass, isReal: Boolean): Unit = { + val getStatement: String = if (isReal) "getTarget" else "getSource" + val thisStatement: String = if (isReal) "(this, v)" else "(v, this)" + if (realRef.upperBound == 1) { + //upper Bound = 1 + //variable settings + sourceClass.augmentConstructor(SMethodStatement(s"private var ${realRef.getName}: ${refClass.getDeepName} = null")) + //internal variables + val removeMethodInternal = new SMethod( + name = s"remove${realRef.getName.capitalize}Intern", + result = PredefTypes.Unit, + params = Seq(SMethodParameter("v", refClass)), //TODO: remove this then each remove internal method has different input parameters + implementation = Seq(SMethodStatement(content = s"${realRef.getName} = null"))) + removeMethodInternal.setVisibility(MethodVisibility.privateExternalClass) + sourceClass.addMethod(removeMethodInternal) + val setMethodInternal = new SMethod( + name = s"set${realRef.getName.capitalize}Intern", + result = PredefTypes.Unit, + params = Seq(SMethodParameter("v", refClass)), + implementation = Seq(SMethodStatement(content = s"${realRef.getName} = v"))) + setMethodInternal.setVisibility(MethodVisibility.privateExternalClass) + sourceClass.addMethod(setMethodInternal) + //external variables + sourceClass.addMethod(new SMethod( + name = s"get${realRef.getName.capitalize}", + result = targetClass, + params = Seq.empty, + implementation = Seq(SMethodStatement(content = s"return ${realRef.getName}.${getStatement}()")))) + sourceClass.addMethod(new SMethod( + name = s"set${realRef.getName.capitalize}", + result = PredefTypes.Boolean, + params = Seq(SMethodParameter("v", targetClass)), + implementation = Seq(SMethodStatement(content = "if (v == null) return false"), + SMethodStatement(content = "if (!containsRole(v.asInstanceOf[AViewRole])) return false"), + SMethodStatement(content = s"if (${realRef.getName} != null) {"), + SMethodStatement(content = s"if (${realRef.getName}.${getStatement}() == v) return false"), + SMethodStatement(content = s"${realRef.getName}.deleteElement()"), + SMethodStatement(content = "}"), + SMethodStatement(content = s"new ${refClass.getName}${thisStatement}"), + SMethodStatement(content = "return true")))) + } else { + //upper Bound = endless + //variable settings + sourceClass.augmentConstructor(SMethodStatement(s"private var ${realRef.getName}: Set[${refClass.getDeepName}] = Set.empty")) + //internal variables + val removeMethodInternal = new SMethod( + name = s"remove${realRef.getName.capitalize}Intern", + result = PredefTypes.Unit, + params = Seq(SMethodParameter("v", refClass)), + implementation = Seq(SMethodStatement(content = s"${realRef.getName} -= v"))) + removeMethodInternal.setVisibility(MethodVisibility.privateExternalClass) + sourceClass.addMethod(removeMethodInternal) + val setMethodInternal = new SMethod( + name = s"set${realRef.getName.capitalize}Intern", + result = PredefTypes.Unit, + params = Seq(SMethodParameter("v", refClass)), + implementation = Seq(SMethodStatement(content = s"${realRef.getName} += v"))) + setMethodInternal.setVisibility(MethodVisibility.privateExternalClass) + sourceClass.addMethod(setMethodInternal) + //external variables + sourceClass.addMethod(new SMethod( + name = s"get${realRef.getName.capitalize}", + result = SSet(targetClass), + params = Seq.empty, + implementation = Seq(SMethodStatement(content = s"var vs: Set[${targetClass.getDeepName}] = Set.empty"), + SMethodStatement(content = s"${realRef.getName}.foreach{ v => vs += v.${getStatement}()}"), + SMethodStatement(content = "return vs")))) + sourceClass.addMethod(new SMethod( + name = s"has${realRef.getName.capitalize}", + result = PredefTypes.Boolean, + params = Seq(SMethodParameter("v", targetClass)), + implementation = Seq(SMethodStatement(content = s"return get${realRef.getName.capitalize}.contains(v)")))) + sourceClass.addMethod(new SMethod( + name = s"add${realRef.getName.capitalize}", + result = PredefTypes.Boolean, + params = Seq(SMethodParameter("v", targetClass)), + implementation = Seq(SMethodStatement(content = s"if (has${realRef.getName.capitalize}(v) || !containsRole(v.asInstanceOf[AViewRole])) return false"), + SMethodStatement(content = s"new ${refClass.getName}${thisStatement}"), + SMethodStatement(content = "return true")))) + sourceClass.addMethod(new SMethod( + name = s"remove${realRef.getName.capitalize}", + result = PredefTypes.Boolean, + params = Seq(SMethodParameter("v", targetClass)), + implementation = Seq(SMethodStatement(content = s"if (!has${realRef.getName.capitalize}(v)) return false"), + SMethodStatement(content = s"${realRef.getName}.foreach{ h =>"), + SMethodStatement(content = s"if (h.${getStatement}() == v) {"), + SMethodStatement(content = "h.deleteElement()"), + SMethodStatement(content = "return true"), + SMethodStatement(content = "}}"), + SMethodStatement(content = "return true")))) + } + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/package.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync/package.scala index 4e0a694ebd741b85202f40dac9ad9ecf4b9298e4..e5139c2a06546e5f5490d2791069edc64621c806 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/sync/package.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/sync/package.scala @@ -8,8 +8,6 @@ import org.rosi_project.model_sync.generator.acr_model.{SMethodStatement, SModel */ package object sync { - val RES_PATH = "res/" - implicit def t2SeqT[T](t: T): Seq[T] = Seq(t) implicit def string2SeqMethodImpl(impl: String): Seq[SMethodStatement] = Seq(SMethodStatement(impl)) diff --git a/src/main/scala/org/rosi_project/model_sync/generator/test/ApplicationTest.scala b/src/main/scala/org/rosi_project/model_sync/generator/test/ApplicationTest.scala new file mode 100644 index 0000000000000000000000000000000000000000..10c6275f5b2321b1c3d5229e7c224d385dfe40cc --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/test/ApplicationTest.scala @@ -0,0 +1,128 @@ +package org.rosi_project.model_sync.generator.test + +import org.rosi_project.model_sync.generator.GeneratorConfig +import org.rosi_project.model_sync.generator.Generator +import java.io.File +import org.rosi_project.model_sync.generator.Creation + +object ApplicationTest extends App { + + runLibraries() + + //runTestLibrary(Creation.rolesum) + //runCombinedTest(Creation.rolecomb) + //runShrinkingModel(Creation.rolesum) + //runTestAML(Creation.rolesum) + + //TTC Case examples + //runTestEmfLibrary(Creation.rolecomb) + //runTTC2019(Creation.rolecomb) + //runTTC2019(Creation.rolesync) + //runTTCLive2019(Creation.rolesync) + + //Run all tests + //runAllTests(Creation.rsum) + //runAllTests(Creation.rsync) + + def runLibraries(): Unit = { + println("SUMM #####################################################################################") + runCombinedTest(Creation.rolesum) + runTestLibrary(Creation.rolesum) + + println("SYNC #####################################################################################") + runCombinedTest(Creation.rolesync) + runTestLibrary(Creation.rolesync) + + println("COMB #####################################################################################") + runCombinedTest(Creation.rolecomb) + runTestLibrary(Creation.rolecomb) + } + + def runAllTests(cre: Creation.Value): Unit = { + println("#####################################################################################") + runTestFamily(cre) + println("#####################################################################################") + runTestSimplePerson(cre) + println("#####################################################################################") + runTestPerson(cre) + println("#####################################################################################") + runTestLibrary(cre) + println("#####################################################################################") + runTestShrinkingModel(cre) + println("#####################################################################################") + runTestAML(cre) + println("#####################################################################################") + runTestIMDB(cre) + println("#####################################################################################") + runTestModelJoinLib(cre) + println("#####################################################################################") + runCombinedTest(cre) + println("#####################################################################################") + } + + def runTTCLive2019(cre: Creation.Value): Unit = { + var config: GeneratorConfig = GeneratorConfig(Seq("assets/models/BibTeX.ecore", "assets/models/DocBook.ecore", "assets/models/NMetaChanges.ecore"), false, new File("assets/models"), create = cre); + new Generator(config).run() + } + + def runTTC2019(cre: Creation.Value): Unit = { + var config: GeneratorConfig = GeneratorConfig(Seq("assets/models/BDD.ecore", "assets/models/BDDv2.ecore", "assets/models/TT.ecore"), false, new File("assets/models"), create = cre); + new Generator(config).run() + } + + def runShrinkingModel(cre: Creation.Value): Unit = { + var config: GeneratorConfig = GeneratorConfig(Seq("assets/models/ShrinkingModel.ecore"), false, new File("assets/models"), modelJoin = "assets/model_join/shrinking.modeljoin", create = cre); + new Generator(config).run() + } + + def runCombinedTest(cre: Creation.Value): Unit = { + var config: GeneratorConfig = GeneratorConfig(Seq("assets/models/IMDBDatabase.ecore", "assets/models/ModelJoinLibrary.ecore"), false, new File("assets/models"), modelJoin = "assets/model_join/simple.modeljoin", create = cre); + new Generator(config).run() + } + + def runTestFamily(cre: Creation.Value): Unit = { + var config: GeneratorConfig = GeneratorConfig(Seq("assets/models/Family.ecore"), false, new File("assets/models"), create = cre); + new Generator(config).run() + } + + def runTestSimplePerson(cre: Creation.Value): Unit = { + var config: GeneratorConfig = GeneratorConfig(Seq("assets/models/SimplePerson.ecore"), false, new File("assets/models"), create = cre); + new Generator(config).run() + } + + def runTestPerson(cre: Creation.Value): Unit = { + var config: GeneratorConfig = GeneratorConfig(Seq("assets/models/Person.ecore"), false, new File("assets/models"), create = cre); + new Generator(config).run() + } + + def runTestLibrary(cre: Creation.Value): Unit = { + var config: GeneratorConfig = GeneratorConfig(Seq("assets/models/Library.ecore"), false, new File("assets/models"), modelJoin = "assets/model_join/manager.modeljoin", create = cre); + new Generator(config).run() + } + + def runTestEmfLibrary(cre: Creation.Value): Unit = { + var config: GeneratorConfig = GeneratorConfig(Seq("assets/models/EMFLibrary.ecore"), false, new File("assets/models"), create = cre); + new Generator(config).run() + } + + def runTestShrinkingModel(cre: Creation.Value): Unit = { + var config: GeneratorConfig = GeneratorConfig(Seq("assets/models/ShrinkingModel.ecore"), false, new File("assets/models"), create = cre); + new Generator(config).run() + } + + def runTestAML(cre: Creation.Value): Unit = { + var config: GeneratorConfig = GeneratorConfig(Seq("assets/models/AML.ecore"), false, new File("assets/models"), create = cre); + new Generator(config).run() + } + + def runTestIMDB(cre: Creation.Value): Unit = { + var config: GeneratorConfig = GeneratorConfig(Seq("assets/models/IMDBDatabase.ecore"), false, new File("assets/models"), create = cre); + new Generator(config).run() + } + + def runTestModelJoinLib(cre: Creation.Value): Unit = { + var config: GeneratorConfig = GeneratorConfig(Seq("assets/models/ModelJoinLibrary.ecore"), false, new File("assets/models"), create = cre); + new Generator(config).run() + } + +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/io/SClassWriterTest.scala b/src/main/scala/org/rosi_project/model_sync/generator/test/SClassWriterTest.scala similarity index 67% rename from src/main/scala/org/rosi_project/model_sync/generator/io/SClassWriterTest.scala rename to src/main/scala/org/rosi_project/model_sync/generator/test/SClassWriterTest.scala index 528232225f239873446d478ce402be9a6a76a604..b1b1d6761a8515bb00253410a90ea4e4ebb2f5c0 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/io/SClassWriterTest.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/test/SClassWriterTest.scala @@ -1,7 +1,9 @@ -package org.rosi_project.model_sync.generator.io +package org.rosi_project.model_sync.generator.test import org.rosi_project.model_sync.generator.acr_model._ import org.rosi_project.model_sync.generator.sync.{GetterSetterGeneratingVisitor, SyncEnhancingVisitor} +import org.rosi_project.model_sync.generator.io.SClassWriter +import scala.collection.Seq /** * @author Rico Bergmann @@ -11,12 +13,14 @@ object SClassWriterTest/* extends App */{ val stringType = SType("String") val attrs = Seq(SAttribute("name", stringType)) val sayHelloMethod = new SMethod("sayHello", stringType, Seq.empty, Seq(SMethodStatement("s\"Hello $name\""))) - val modelClass = new SClass("Person", attributes = attrs, methods = Seq(sayHelloMethod)) + val modelClass = new SClass("Person", "foo") + modelClass.setAttributes(attrs) + modelClass.addMethod(sayHelloMethod) val getterSetterVisitor = new GetterSetterGeneratingVisitor modelClass.accept(getterSetterVisitor) - - val syncNotificationVisitor = new SyncEnhancingVisitor(null) + + val syncNotificationVisitor = new SyncEnhancingVisitor modelClass.accept(syncNotificationVisitor) val writer = new SClassWriter(modelClass) diff --git a/src/main/scala/org/rosi_project/model_sync/generator/io/SModelFSWriterTest.scala b/src/main/scala/org/rosi_project/model_sync/generator/test/SModelFSWriterTest.scala similarity index 68% rename from src/main/scala/org/rosi_project/model_sync/generator/io/SModelFSWriterTest.scala rename to src/main/scala/org/rosi_project/model_sync/generator/test/SModelFSWriterTest.scala index 266077240831ebcfb08efbc09ea975e656a2c3b4..b7f00b87273be3a934316afc6f13327d65fd795a 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/io/SModelFSWriterTest.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/test/SModelFSWriterTest.scala @@ -1,24 +1,25 @@ -package org.rosi_project.model_sync.generator.io +package org.rosi_project.model_sync.generator.test import org.rosi_project.model_sync.generator.acr_model.{SimpleSModel, _} import org.rosi_project.model_sync.generator.sync.{GetterSetterGeneratingVisitor, SyncEnhancingVisitor} - -import scala.reflect.io.File +import scala.collection.Seq /** @author Rico Bergmann */ object SModelFSWriterTest/* extends App */{ - val model = new SimpleSModel + val model = new SimpleSModel("Foo", "source", "http.//test.test") val stringType = SType("String") val personAttrs = Seq(SAttribute("name", stringType)) val personSayHelloMethod = new SMethod("sayHello", stringType, Seq.empty, Seq(SMethodStatement("s\"Hello $name\""))) - val personClass = new SClass("Person", sPackage = "foo", attributes = personAttrs, methods = Seq(personSayHelloMethod)) + val personClass = new SClass("Person", "foo") + personClass.setAttributes(personAttrs) + personClass.addMethod(personSayHelloMethod) val getterSetterVisitor = new GetterSetterGeneratingVisitor - val syncNotificationVisitor = new SyncEnhancingVisitor(null) + val syncNotificationVisitor = new SyncEnhancingVisitor model.addModelClass(personClass) diff --git a/src/main/scala/org/rosi_project/model_sync/generator/test/SModelGeneratorTest.scala b/src/main/scala/org/rosi_project/model_sync/generator/test/SModelGeneratorTest.scala new file mode 100644 index 0000000000000000000000000000000000000000..038ef0c7979c4d1ce7983e0bb79f83dfe36cd97c --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/test/SModelGeneratorTest.scala @@ -0,0 +1,26 @@ +package org.rosi_project.model_sync.generator.test + +import org.eclipse.emf.common.util.URI +import org.eclipse.emf.ecore.{EObject, EPackage} +import org.eclipse.emf.ecore.resource.Resource +import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl +import org.rosi_project.model_sync.generator.conversion.SModelGenerator + +/** + * @author Rico Bergmann + */ +object SModelGeneratorTest/* extends App */{ + + val path: String = "assets/ttc17.ecore" + + val resourceSet = new ResourceSetImpl() + val _ = resourceSet.getResourceFactoryRegistry.getExtensionToFactoryMap.put(Resource.Factory.Registry.DEFAULT_EXTENSION, new XMIResourceFactoryImpl()) + val res = resourceSet.getResource(URI.createFileURI(path), true) + + require(null != res) + require(!res.getContents.isEmpty) + println(s"We done: $res") + + res.getContents.toArray(new Array[EObject](0)).toList.find(_.isInstanceOf[EPackage]).foreach(e => (new SModelGenerator).convert(e.asInstanceOf[EPackage], "source")) +} diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/ConstructorTemplate.scala b/src/main/scala/org/rosi_project/model_sync/generator/ui/ConstructorTemplate.scala similarity index 56% rename from src/main/scala/org/rosi_project/model_sync/generator/sync/ConstructorTemplate.scala rename to src/main/scala/org/rosi_project/model_sync/generator/ui/ConstructorTemplate.scala index c1dfbbec7dee61f50deceb0b3ad7a26c2c215ce8..b732523defa64a09e5f6d08f4493c816ebe5b8e9 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/sync/ConstructorTemplate.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/ui/ConstructorTemplate.scala @@ -1,18 +1,19 @@ -package org.rosi_project.model_sync.generator.sync +package org.rosi_project.model_sync.generator.ui -import org.rosi_project.model_sync.instances.ModelInstanceConstructor import org.rosi_project.model_sync.generator.acr_model.{SClass, SImport, SMethod, SMethodParameter, SMethodStatement, SType, types => acr} +import org.rosi_project.model_sync.generator.sync.string2SeqMethodImpl +import org.rosi_project.model_sync.generator.acr_model.types.PredefTypes /** Creates implementations of [[ModelInstanceConstructor]] for model classes. * * @param modelClass the class for which the constructor should be wrapped * @author Rico Bergmann */ -class ConstructorTemplate(modelClass: SClass) extends SClass(name = s"${modelClass.name}Constructor") { +class ConstructorTemplate(modelClass: SClass) extends SClass(_name = s"${modelClass.getName}Constructor", _sPackage = s"${modelClass.sPackage}.visualize") { - parent = PredefTypes.ModelInstanceConstructor + addParent(PredefUiTypes.MODEL_INSTANCE_CONSTRUCTOR_STYPE) - private val constructorParams = modelClass.attributes.map(attr => s"classOf[${attr.attrType.getName}]").mkString(", ") + private val constructorParams: String = generateConstructorParams constructorStatements = constructorStatements :+ SMethodStatement(s"private val ${ConstructorTemplate.ConstructorAttr} = classOf[${modelClass.getName}].getConstructor($constructorParams)") @@ -26,22 +27,29 @@ class ConstructorTemplate(modelClass: SClass) extends SClass(name = s"${modelCla ), new SMethod( name = "invoke", - result = SType.AnyRef, + result = PredefTypes.AnyRef, params = Seq(SMethodParameter("args", acr.SSeq(acr.PredefTypes.Object))), implementation = s"${ConstructorTemplate.ConstructorAttr}.newInstance(args: _*)", overrides = true ), new SMethod( name = "toString", - result = SType.String, + result = PredefTypes.String, params = Seq.empty, implementation = s""" "${modelClass.getName} Constructor" """, overrides = true ) ) - override def getNecessaryImports: Set[SImport] = modelClass.getUsedTypes.filter(_.getPackage != "").map(elem => SImport(elem.getPackage, elem.getName)) ++ super.getNecessaryImports + SImport(modelClass.getPackage, modelClass.getName) + override def getNecessaryImports: Set[SImport] = { + (modelClass.getUsedTypes.filter(_.getPackage != "").map(elem => SImport(elem.getPackage, elem.getName)) + ++ super.getNecessaryImports + + SImport(modelClass.getPackage, modelClass.getName)) + } + private def generateConstructorParams: String = { + modelClass.getDeepStructuralFeatures.map(attr => s"classOf[${attr.getTypeElement.getName}]").mkString(", ") + } } object ConstructorTemplate { diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/InitialModelTemplate.scala b/src/main/scala/org/rosi_project/model_sync/generator/ui/InitialModelTemplate.scala similarity index 53% rename from src/main/scala/org/rosi_project/model_sync/generator/sync/InitialModelTemplate.scala rename to src/main/scala/org/rosi_project/model_sync/generator/ui/InitialModelTemplate.scala index 018824aa198f879de82decbd01bf37b5fbf06ac6..e45e03b87f47ee2fee63517f74d71787eebcf41b 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/sync/InitialModelTemplate.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/ui/InitialModelTemplate.scala @@ -1,22 +1,21 @@ -package org.rosi_project.model_sync.generator.sync +package org.rosi_project.model_sync.generator.ui import java.io.File - import org.rosi_project.model_sync.generator.{Model, ModelDataException} import org.rosi_project.model_sync.generator.acr_model._ import org.rosi_project.model_sync.generator.acr_model.{types => acr} import org.rosi_project.model_sync.generator.support.ExtendedString.stringToExtended -import org.rosi_project.model_sync.provider.DisplayableModelForInitialization - +import org.rosi_project.model_sync.generator.sync.string2SeqMethodImpl +import org.rosi_project.model_sync.generator.acr_model.types.PredefTypes /** Creates implementations of [[DisplayableModelForInitialization]] for models. * * @param model the model which should be initialized * @author Rico Bergmann */ -class InitialModelTemplate(model: Model) extends SClass(name = s"Initialized${Model.parseClass(model.primaryClass)._2.firstLetterToUpperCase}") { +class InitialModelTemplate(model: Model) extends SClass(_name = s"Initialized${Model.parseClass(model.primaryClass)._2.firstLetterToUpperCase}", _sPackage = s"${Model.parseClass(model.primaryClass)._1}.visualize") { - parent = SType("DisplayableModelForInitialization", sPackage = "org.rosi_project.model_sync.provider") + addParent(SType("DisplayableModelForInitialization", "org.rosi_project.model_sync.provider")) private val primaryClassComps = Model.parseClass(model.primaryClass) private val primaryClass: SClass = STypeRegistry.query(primaryClassComps._2, primaryClassComps._1).getOrElse(throw new ModelDataException).asInstanceOf[SClass] @@ -26,55 +25,76 @@ class InitialModelTemplate(model: Model) extends SClass(name = s"Initialized${Mo private var modelImagePath = "None" model.image.foreach(image => { val imageFile = new File(image) - modelImagePath = s"""Some(new File("${RES_PATH + imageFile.getName}"))""" + modelImagePath = s"""Some(new File("${PredefUiTypes.RES_PATH + imageFile.getName}"))""" }) methods = Seq( new SMethod ( name = "getName", - result = SType.String, + result = PredefTypes.String, params = Seq.empty, - implementation = s""" "${model.name}" """ + implementation = s""" "${model.name}" """, + true ), new SMethod ( name = "getInstanceClass", result = SType("Class[_ <: AnyRef]"), params = Seq.empty, - implementation = s"classOf[${primaryClass.getName}]" + implementation = Seq(SMethodStatement(s"classOf[${primaryClass.getName}]", Set(primaryClass))), + true ), new SMethod ( name = "getModelDiagram", result = acr.PredefTypes.option(acr.PredefTypes.File), params = Seq.empty, - implementation = modelImagePath + implementation = modelImagePath, + true ), new SMethod ( name = "getConstructors", - result = acr.SSeq(PredefTypes.ModelInstanceConstructor), + result = acr.SSeq(PredefUiTypes.MODEL_INSTANCE_CONSTRUCTOR_STYPE), params = Seq.empty, - implementation = s"Seq(${allModelClasses.map(cls => s"new ${cls.getName}Constructor").mkString(", ")})" + implementation = s"Seq(${allModelClasses + .filter(!_.isAbstract) + .map(cls => + s"new ${cls.getName}Constructor").mkString(", ")})", + true ), new SMethod ( name = "getUpdateMethods", - result = acr.SSeq(PredefTypes.ModelInstanceModifier), + result = acr.SSeq(PredefUiTypes.MODEL_INSTANCE_MODIFIER_STYPE), params = Seq.empty, - implementation = s"Seq(${allModelClasses.map(cls => cls.attributes.map(attr => s"new ${cls.name}${attr.name.firstLetterToUpperCase}Modifier").mkString(", ")).mkString(", ")})" + implementation = s"Seq(${allModelClasses + .filter(_.getStructuralFeatures.nonEmpty) + .map(cls => { + cls.getStructuralFeatures.map(attr => s"new ${cls.getName}${attr.getName.firstLetterToUpperCase}Modifier").mkString(", ") + }) + .mkString(", ")})", + true ), - new SMethod ( + new SMethod( + name = "toString", + result = PredefTypes.String, + params = Seq.empty, + implementation = s""" "${getName}" """, + overrides = true + ) + /*new SMethod ( name = "getInstances", result = acr.SSeq(SType.AnyRef), params = Seq.empty, - implementation = "Seq.empty" // TODO - ) + implementation = "Seq.empty", // TODO + true + )*/ ) if (model.nested.nonEmpty) { methods = methods :+ new SMethod( name = "getNestedModels", - result = acr.SSeq(PredefTypes.DisplayableModel), + result = acr.SSeq(PredefUiTypes.DISPLAYABLE_MODEL_STYPE), params = Seq.empty, implementation = s"Seq( ${model.nested.getOrElse(List()).map(nested => "new Initialized" + Model.parseClass(nested.primaryClass)._2.firstLetterToUpperCase).mkString(", ")} )", overrides = true @@ -82,16 +102,16 @@ class InitialModelTemplate(model: Model) extends SClass(name = s"Initialized${Mo } - constructorStatements = Statements.ModelRegistration +: constructorStatements - - override def getNecessaryImports: Set[SImport] = { - val base = super.getNecessaryImports + Imports.ModelRegistry + augmentConstructor(Statements.ModelRegistration) + /*override def getNecessaryImports: Set[SImport] = { + val base = super.getNecessaryImports + if (primaryClass.isDefaultPackage) { base } else { base + SImport(primaryClass.getPackage, primaryClass.getName) } - } + }*/ } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/ModelProviderTemplate.scala b/src/main/scala/org/rosi_project/model_sync/generator/ui/ModelProviderTemplate.scala similarity index 59% rename from src/main/scala/org/rosi_project/model_sync/generator/sync/ModelProviderTemplate.scala rename to src/main/scala/org/rosi_project/model_sync/generator/ui/ModelProviderTemplate.scala index 9b912f66a65b930ceeb400206f4c89d5f195f283..99b2a17cb713b0cc9b36461f88e65660165ea917 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/sync/ModelProviderTemplate.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/ui/ModelProviderTemplate.scala @@ -1,29 +1,30 @@ -package org.rosi_project.model_sync.generator.sync +package org.rosi_project.model_sync.generator.ui import org.rosi_project.model_sync.generator.Model import org.rosi_project.model_sync.generator.acr_model.{SClass, SMethod, types => acr} import org.rosi_project.model_sync.generator.support.ExtendedString.stringToExtended -import org.rosi_project.model_sync.provider.ModelSyncProvider +import org.rosi_project.model_sync.generator.sync.string2SeqMethodImpl +import scala.collection.Seq /** Creates implementations of [[ModelSyncProvider]] for models. * * @param model the model which should be initialized * @author Rico Bergmann */ -class ModelProviderTemplate(model: Model) extends SClass(name = "ModelProvider") { +class ModelProviderTemplate(model: Model) extends SClass(_name = "ModelProvider", _sPackage = s"${Model.parseClass(model.primaryClass)._1}.visualize") { - parent = PredefTypes.ModelProvider + addParent(PredefUiTypes.MODEL_SYNC_PROVIDER_STYPE) methods = Seq( new SMethod ( name = "getInitialDisplayableModel", - result = PredefTypes.DisplayableModelForInitialization, + result = PredefUiTypes.DISPLAYABLE_MODEL_FOR_INITIALIZATION_STYPE, params = Seq.empty, implementation = s"new Initialized${Model.parseClass(model.primaryClass)._2.firstLetterToUpperCase}" ), new SMethod ( name = "getDisplayableModelsForIntegration", - result = acr.SSeq(PredefTypes.DisplayableModelForIntegration), + result = acr.SSeq(PredefUiTypes.DISPLAYABLE_MODEL_FOR_INTEGRATION_STYPE), params = Seq.empty, implementation = "Seq.empty" ) diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/ModifierTemplate.scala b/src/main/scala/org/rosi_project/model_sync/generator/ui/ModifierTemplate.scala similarity index 56% rename from src/main/scala/org/rosi_project/model_sync/generator/sync/ModifierTemplate.scala rename to src/main/scala/org/rosi_project/model_sync/generator/ui/ModifierTemplate.scala index 065a04ca7a11ca0813534c284d4384eb951db4d0..02135e66bfbfb7f273c2c6f110193051f656e135 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/sync/ModifierTemplate.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/ui/ModifierTemplate.scala @@ -1,8 +1,10 @@ -package org.rosi_project.model_sync.generator.sync +package org.rosi_project.model_sync.generator.ui -import org.rosi_project.model_sync.generator.acr_model.{GenericSType, SAttribute, SClass, SImport, SMethod, SMethodParameter, SMethodStatement, SType, STypedElement, types => acr} +import org.rosi_project.model_sync.generator.acr_model.{GenericSType, SStructuralFeature, SClass, SImport, SMethod, SMethodParameter, SMethodStatement, SType, STypedElement, types => acr} import org.rosi_project.model_sync.generator.support.ExtendedString.stringToExtended -import org.rosi_project.model_sync.instances.ModelInstanceModifier +import org.rosi_project.model_sync.generator.sync.string2SeqMethodImpl +import scala.collection.Seq +import org.rosi_project.model_sync.generator.acr_model.types.PredefTypes /** Creates implementations of [[ModelInstanceModifier]] for attributes of model classes. * @@ -10,12 +12,12 @@ import org.rosi_project.model_sync.instances.ModelInstanceModifier * @param attribute the attribute for which the modifier should be created * @author Rico Bergmann */ -class ModifierTemplate(modelClass: SClass, attribute: SAttribute) extends SClass(name = s"${modelClass.name}${attribute.name.firstLetterToUpperCase}Modifier") { +class ModifierTemplate(modelClass: SClass, attribute: SStructuralFeature) extends SClass(_name = s"${modelClass.getName}${attribute.getName.firstLetterToUpperCase}Modifier", _sPackage = s"${modelClass.sPackage}.visualize") { - parent = PredefTypes.ModelInstanceModifier + addParent(PredefUiTypes.MODEL_INSTANCE_MODIFIER_STYPE) constructorStatements = constructorStatements :+ - SMethodStatement(s"""private val ${ModifierTemplate.MethodAttr} = classOf[${modelClass.getName}].getMethod("set${attribute.name.firstLetterToUpperCase}", classOf[${attribute.getType}])""") + SMethodStatement(s"""private val ${ModifierTemplate.MethodAttr} = classOf[${modelClass.getName}].getMethod("set${attribute.getName.firstLetterToUpperCase}", classOf[${attribute.getTypeElement.getName}])""") methods = Seq( new SMethod ( @@ -27,22 +29,22 @@ class ModifierTemplate(modelClass: SClass, attribute: SAttribute) extends SClass ), new SMethod ( name = "invoke", - result = SType.Unit, - params = Seq(SMethodParameter("instance", SType.AnyRef), SMethodParameter("args", acr.SSeq(SType.AnyRef))), + result = PredefTypes.Unit, + params = Seq(SMethodParameter("instance", PredefTypes.AnyRef), SMethodParameter("args", acr.SSeq(PredefTypes.AnyRef))), implementation = s"${ModifierTemplate.MethodAttr}.invoke(instance, args: _*)", overrides = true ), new SMethod( name = "toString", - result = SType.String, + result = PredefTypes.String, params = Seq.empty, - implementation = s""" "Change ${attribute.name}" """, + implementation = s""" "Change ${attribute.getName}" """, overrides = true ) ) override def getNecessaryImports: Set[SImport] = { - val attrImports = attribute.attrType match { + val attrImports = attribute.getTypeElement match { case gt : GenericSType => SImport.generateImports(gt, gt.typeParam) case t : STypedElement => SImport.generateImports(t) } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/ui/PredefUiTypes.scala b/src/main/scala/org/rosi_project/model_sync/generator/ui/PredefUiTypes.scala new file mode 100644 index 0000000000000000000000000000000000000000..3dcd4cf803316af14cdd59a61dd57a9aaa2e2bfc --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/ui/PredefUiTypes.scala @@ -0,0 +1,31 @@ +package org.rosi_project.model_sync.generator.ui + +import org.rosi_project.model_sync.generator.acr_model.SType +import org.rosi_project.model_sync.provider._ +import org.rosi_project.model_sync.instances._ + +object PredefUiTypes { + + val RES_PATH = "res/" + + private val DISPLAYABLE_MODEL_CLASS = classOf[DisplayableModel] + val DISPLAYABLE_MODEL_STYPE = SType(DISPLAYABLE_MODEL_CLASS.getSimpleName, DISPLAYABLE_MODEL_CLASS.getPackage.getName) + + private val DISPLAYABLE_MODEL_FOR_INITIALIZATION_CLASS = classOf[DisplayableModelForInitialization] + val DISPLAYABLE_MODEL_FOR_INITIALIZATION_STYPE = SType(DISPLAYABLE_MODEL_FOR_INITIALIZATION_CLASS.getSimpleName, DISPLAYABLE_MODEL_FOR_INITIALIZATION_CLASS.getPackage.getName) + + private val DISPLAYABLE_MODEL_FOR_INTEGRATION_CLASS = classOf[DisplayableModelForIntegration] + val DISPLAYABLE_MODEL_FOR_INTEGRATION_STYPE = SType(DISPLAYABLE_MODEL_FOR_INTEGRATION_CLASS.getSimpleName, DISPLAYABLE_MODEL_FOR_INTEGRATION_CLASS.getPackage.getName) + + private val MODEL_SYNC_PROVIDER_CLASS = classOf[ModelSyncProvider] + val MODEL_SYNC_PROVIDER_STYPE = SType(MODEL_SYNC_PROVIDER_CLASS.getSimpleName, MODEL_SYNC_PROVIDER_CLASS.getPackage.getName) + + private val MODEL_REGISTRY_CLASS = ModelRegistry.getClass + val MODEL_REGISTRY_STYPE = SType(MODEL_REGISTRY_CLASS.getSimpleName.replace("$", ""), MODEL_REGISTRY_CLASS.getPackage.getName) + + private val MODEL_INSTANCE_CONSTRUCTOR_CLASS = classOf[ModelInstanceConstructor] + val MODEL_INSTANCE_CONSTRUCTOR_STYPE = SType(MODEL_INSTANCE_CONSTRUCTOR_CLASS.getSimpleName, MODEL_INSTANCE_CONSTRUCTOR_CLASS.getPackage.getName) + + private val MODEL_INSTANCE_MODIFIER_CLASS = classOf[ModelInstanceModifier] + val MODEL_INSTANCE_MODIFIER_STYPE = SType(MODEL_INSTANCE_MODIFIER_CLASS.getSimpleName, MODEL_INSTANCE_MODIFIER_CLASS.getPackage.getName) +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync/Statements.scala b/src/main/scala/org/rosi_project/model_sync/generator/ui/Statements.scala similarity index 56% rename from src/main/scala/org/rosi_project/model_sync/generator/sync/Statements.scala rename to src/main/scala/org/rosi_project/model_sync/generator/ui/Statements.scala index 59fa88d7d81fe94ed4dcccfbc1ae5a9b1eedf680..729cf98a3956933b685a9699d2aa0e6f1c99e92e 100644 --- a/src/main/scala/org/rosi_project/model_sync/generator/sync/Statements.scala +++ b/src/main/scala/org/rosi_project/model_sync/generator/ui/Statements.scala @@ -1,4 +1,4 @@ -package org.rosi_project.model_sync.generator.sync +package org.rosi_project.model_sync.generator.ui import org.rosi_project.model_sync.generator.acr_model.SMethodStatement @@ -10,6 +10,6 @@ import org.rosi_project.model_sync.generator.acr_model.SMethodStatement */ object Statements { - val ModelRegistration = SMethodStatement("ModelRegistry.registerNewModel(this)", Set(PredefTypes.ModelRegistry)) + val ModelRegistration = SMethodStatement("val registered = ModelRegistry.registerNewModel(this)", Set(PredefUiTypes.MODEL_REGISTRY_STYPE)) } diff --git a/src/main/scala/org/rosi_project/model_sync/generator/ui/SyncUiVisitor.scala b/src/main/scala/org/rosi_project/model_sync/generator/ui/SyncUiVisitor.scala new file mode 100644 index 0000000000000000000000000000000000000000..26cc53a33d9d89ebe6de59e7c361c0d5c228dedb --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/ui/SyncUiVisitor.scala @@ -0,0 +1,49 @@ +package org.rosi_project.model_sync.generator.ui + +import org.rosi_project.model_sync.generator.ModelConfig +import org.rosi_project.model_sync.generator.acr_model._ + +/** + * Add the UI Provider classes for the visualisation in the user interface. + */ +class SyncUiVisitor(val modelCfg: ModelConfig) extends SModelVisitor { + + override def visit(sModel: SModel): Unit = { + var additionalSyncClasses: Seq[SClass] = Seq.empty + sModel.getModelClasses.foreach(cls => { + if (!cls.isAbstract && !cls.isInterface) { + additionalSyncClasses = additionalSyncClasses :+ new ConstructorTemplate(cls) + } + cls.getStructuralFeatures.foreach(struc => { + additionalSyncClasses = additionalSyncClasses :+ new ModifierTemplate(cls, struc) + }) + }) + + additionalSyncClasses.foreach(sModel.addProviderClass) + + modelCfg.init.nested.foreach(_.foreach(model => sModel.addProviderClass(new InitialModelTemplate(model)))) + sModel.addProviderClass(new InitialModelTemplate(modelCfg.init)) + sModel.addProviderClass(new ModelProviderTemplate(modelCfg.init)) + + } + + override def visit(sClass: SClass): Unit = { + // pass + } + + override def visit(sAttr: SAttribute): Unit = { + // pass + } + + override def visit(sRef: SReference): Unit = { + // pass + } + + override def visit(sMethod: SMethod): Unit = { + // pass + } + + override def visit(sType: SType): Unit = { + // pass + } +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/util/ClassAndInstance.scala b/src/main/scala/org/rosi_project/model_sync/generator/util/ClassAndInstance.scala new file mode 100644 index 0000000000000000000000000000000000000000..1ef23113d87b0a6c8065b430121112d4e6fb6803 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/util/ClassAndInstance.scala @@ -0,0 +1,8 @@ +package org.rosi_project.model_sync.generator.util + +import org.eclipse.emf.ecore.EObject +import org.eclipse.emf.ecore.EPackage + +class ClassAndInstance(val pkg: EPackage, val obj: EObject) { + +} \ No newline at end of file diff --git a/src/main/scala/org/rosi_project/model_sync/generator/util/InstanceLine.scala b/src/main/scala/org/rosi_project/model_sync/generator/util/InstanceLine.scala new file mode 100644 index 0000000000000000000000000000000000000000..56bd013cd7ce0d1d44472f5a3b08c6c2169581e5 --- /dev/null +++ b/src/main/scala/org/rosi_project/model_sync/generator/util/InstanceLine.scala @@ -0,0 +1,38 @@ +package org.rosi_project.model_sync.generator.util + +import scala.collection.JavaConverters._ +import org.eclipse.emf.ecore.EObject +import org.rosi_project.model_sync.generator.acr_model.STypedElement +import org.eclipse.emf.ecore.EClass +import org.rosi_project.model_sync.generator.sync.HelperFunctions +import org.rosi_project.model_sync.generator.acr_model.SMethodParameter +import org.rosi_project.model_sync.generator.acr_model.STypeRegistry +import org.eclipse.emf.ecore.EStructuralFeature + +class InstanceLine(val counter: Int, val obj: EObject, val usedType: STypedElement, val lineString: String = "") { + + def getLine(): String = { + if (obj != null) { + return s"val i${counter} = new ${usedType.getName} (${usedType.getAllConstructorParameters.map(classEmptyConstructorParameterCreation(_)).mkString(", ")})" + } + return lineString + } + + def getName(): String = "i" + counter + + def classEmptyConstructorParameterCreation(t: SMethodParameter): String = { + if (STypeRegistry.isDefaultType(t.getType.getName)) { + var structs: Seq[EStructuralFeature] = obj.eClass().getEAllStructuralFeatures.asScala + structs.foreach(att => { + if (att.getName == t.getName) { + if (t.getType.getName == "String" && obj.eGet(att) != null) { + return s""" "${obj.eGet(att)}" """ + } else { + return obj.eGet(att) + "" + } + } + }) + } + return HelperFunctions.classEmptyType(t.getTypeName) + } +} \ No newline at end of file