diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e6431cf9d44258e2ba620f7e1f7f79ff0770c85a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,177 @@
+#### joe made this: http://goel.io/joe
+
+#### scala ####
+*.class
+*.log
+
+
+#### sbt ####
+# Simple Build Tool
+# http://www.scala-sbt.org/release/docs/Getting-Started/Directories.html#configuring-version-control
+
+dist/*
+target/
+lib_managed/
+src_managed/
+project/boot/
+project/plugins/project/
+.history
+.cache
+.lib/
+
+
+#### jetbrains ####
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn.  Uncomment if using
+# auto-import.
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+
+#### java ####
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+
+#### eclipse ####
+
+.metadata
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.settings/
+.loadpath
+.recommenders
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# PyDev specific (Python IDE for Eclipse)
+*.pydevproject
+
+# CDT-specific (C/C++ Development Tooling)
+.cproject
+
+# CDT- autotools
+.autotools
+
+# Java annotation processor (APT)
+.factorypath
+
+# PDT-specific (PHP Development Tools)
+.buildpath
+
+# sbteclipse plugin
+.target
+
+# Tern plugin
+.tern-project
+
+# TeXlipse plugin
+.texlipse
+
+# STS (Spring Tool Suite)
+.springBeans
+
+# Code Recommenders
+.recommenders/
+
+# Annotation Processing
+.apt_generated/
+
+# Scala IDE specific (Scala & Java development for Eclipse)
+.cache-main
+.scala_dependencies
+.worksheet
+
+# Custom (user defined) insertions
+.idea/
+.classpath
+.project
+output/
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000000000000000000000000000000000000..d32bc548305c52a170e059020262ab0e062d32d6
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,6 @@
+[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
diff --git a/assets/ttc17.ecore b/assets/ttc17.ecore
new file mode 100644
index 0000000000000000000000000000000000000000..7f2edd41690a950461bf0e6137bcc912bf591e12
--- /dev/null
+++ b/assets/ttc17.ecore
@@ -0,0 +1,9 @@
+<?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="ttc17" nsURI="http://www.example.org/ttc17" nsPrefix="ttc17">
+  <eClassifiers xsi:type="ecore:EClass" name="Person">
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="fullName" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EClass" name="Male" eSuperTypes="#//Person"/>
+  <eClassifiers xsi:type="ecore:EClass" name="Female" eSuperTypes="#//Person"/>
+</ecore:EPackage>
diff --git a/build.sbt b/build.sbt
new file mode 100644
index 0000000000000000000000000000000000000000..1660dd3eaef67463e4e9a0d01f8ce0040ae053a9
--- /dev/null
+++ b/build.sbt
@@ -0,0 +1,38 @@
+import sbt.Keys.{libraryDependencies, scalacOptions, version}
+
+val emfcommonVersion = "2.12.0"
+val emfecoreVersion = "2.12.0"
+val scrollVersion = "1.6"
+val scoptVersion = "3.7.0"
+
+val syncProvider = RootProject(file("lib/ModelSyncProvider"))
+
+lazy val generator = (project in file("."))
+  .settings(
+    name := "CodeGenerator",
+    version := "0.1",
+    scalaVersion := "2.12.6",
+    libraryDependencies ++= Seq(
+      "org.scala-lang" % "scala-reflect" % scalaVersion.value,
+      "org.scala-lang" % "scala-compiler" % scalaVersion.value,
+      "org.eclipse.emf" % "org.eclipse.emf.common" % emfcommonVersion,
+      "org.eclipse.emf" % "org.eclipse.emf.ecore" % emfecoreVersion,
+      "com.github.scopt" %% "scopt" % scoptVersion
+    ),
+    scalacOptions ++= Seq(
+      "-language:implicitConversions"
+    ),
+    mainClass in assembly := Some("org.rosi_project.model_sync.generator.Generator"),
+    assemblyMergeStrategy in assembly := {
+      case "MANIFEST.MF" => MergeStrategy.first
+      case "plugin.xml" => MergeStrategy.discard
+      case "plugin.properties" => MergeStrategy.discard
+      case "generated_package.exsd" => MergeStrategy.discard
+      case "dynamic_package.exsd" => MergeStrategy.discard
+      case PathList("schema", ps @ _ *) if ps.lastOption.exists(_.endsWith("generated_package.exsd")) => MergeStrategy.discard
+      case PathList("schema", ps @ _ *) if ps.lastOption.exists(_.endsWith("dynamic_package.exsd")) => MergeStrategy.discard
+      case x =>
+        val oldStrategy = (assemblyMergeStrategy in assembly).value
+        oldStrategy(x)
+    }
+  ).dependsOn(syncProvider)
diff --git a/lib/ModelSyncProvider b/lib/ModelSyncProvider
new file mode 160000
index 0000000000000000000000000000000000000000..ace8bdf5799dd89bd66d01782237123172bb0ec0
--- /dev/null
+++ b/lib/ModelSyncProvider
@@ -0,0 +1 @@
+Subproject commit ace8bdf5799dd89bd66d01782237123172bb0ec0
diff --git a/lib/SCROLL b/lib/SCROLL
new file mode 160000
index 0000000000000000000000000000000000000000..623765816af6d27387efb82dfb890bc4318c58a2
--- /dev/null
+++ b/lib/SCROLL
@@ -0,0 +1 @@
+Subproject commit 623765816af6d27387efb82dfb890bc4318c58a2
diff --git a/project/assembly.sbt b/project/assembly.sbt
new file mode 100644
index 0000000000000000000000000000000000000000..d95475f16ffa0d9a0670795c8296b31fa24c76ec
--- /dev/null
+++ b/project/assembly.sbt
@@ -0,0 +1 @@
+addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.7")
diff --git a/project/build.properties b/project/build.properties
new file mode 100644
index 0000000000000000000000000000000000000000..8db5ca22266ea113c2b39c92dddb73c83e61ffee
--- /dev/null
+++ b/project/build.properties
@@ -0,0 +1 @@
+sbt.version = 1.2.1
\ No newline at end of file
diff --git a/project/plugins.sbt b/project/plugins.sbt
new file mode 100644
index 0000000000000000000000000000000000000000..45a6f02d1880ea4c9bff889a194ab87adf467611
--- /dev/null
+++ b/project/plugins.sbt
@@ -0,0 +1,2 @@
+addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "5.2.4")
+addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "1.0.0")
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/Config.scala b/src/main/scala/org/rosi_project/model_sync/generator/Config.scala
new file mode 100644
index 0000000000000000000000000000000000000000..94f73bf979dc26e67368bd26ed582aaf8d3fba7b
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/Config.scala
@@ -0,0 +1,10 @@
+package org.rosi_project.model_sync.generator
+
+import java.io.File
+
+/**
+  * @author Rico Bergmann
+  */
+case class Config(source: String = "", cleanUp: Boolean = false, outDir: File = new File(System.getProperty("user.dir"))) {
+
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..80a73165cf5b4295139a1b73e6d0aeb29b016cce
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/Generator.scala
@@ -0,0 +1,67 @@
+package org.rosi_project.model_sync.generator
+
+import org.eclipse.emf.ecore._
+import org.eclipse.emf.ecore.resource.Resource
+import org.rosi_project.model_sync.generator.conversion.SModelGenerator
+import org.rosi_project.model_sync.generator.io.SModelFSWriter
+import org.rosi_project.model_sync.generator.sync_model.{GetterSetterGeneratingVisitor, SModel, SyncEnhancingVisitor}
+import scopt.OptionParser
+import scroll.internal.ecore.ECoreImporter
+
+import scala.reflect.io.File
+
+import java.{io => jio}
+
+/**
+  * @author Rico Bergmann
+  */
+object Generator extends App {
+
+  // TODO CLI parser (scopt) here
+  // gen -c(leanup) -o [outdir] ECOREFILE
+
+  val parser = new OptionParser[Config](programName="modelgen") {
+    head("modelgen", "0.1")
+
+    arg[jio.File]("ecore").required().action( (ef, conf) =>
+      conf.copy(source = ef.getAbsolutePath)
+    ).text("The ecore (XML) file of the model")
+
+    opt[jio.File]('o', "outdir").optional().action( (dir, conf) =>
+      conf.copy(outDir =  dir)
+    ).text("The directory to place the generated model in (current dir by default)")
+
+    opt[Unit]('c', "cleanup").optional().action( (_, conf) =>
+      conf.copy(cleanUp = true)
+    ).text("Remove the generated .scala files and only keep the compiled .class files")
+  }
+
+  parser.parse(args, Config()) match {
+    case Some(config) =>
+      val ecoreModel = loadEcore(config.source)
+      val sModel = SModelGenerator.convert(ecoreModel)
+      prepareModel(sModel)
+      sModel.accept(new SModelFSWriter(outputDir = File(config.outDir).toDirectory, keepClassFiles = !config.cleanUp))
+    case None =>
+  }
+
+
+
+  def loadEcore(path: String = "assets/ttc17.ecore"): EPackage = {
+    val importer = new ECoreImporter {
+      def lm(): Resource = loadModel()
+    }
+    importer.path = path
+    val res = importer.lm()
+    res.getContents.toArray(new Array[EObject](0)).toList.find(_.isInstanceOf[EPackage]).map((p: EObject) => p.asInstanceOf[EPackage]).orNull
+  }
+
+  def prepareModel(sModel: SModel): Unit = {
+    val getterSetterVisitor = new GetterSetterGeneratingVisitor
+    val syncNotificationVisitor = new SyncEnhancingVisitor
+
+    sModel.accept(getterSetterVisitor)
+    sModel.accept(syncNotificationVisitor)
+  }
+
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr/SAttribute.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr/SAttribute.scala
new file mode 100644
index 0000000000000000000000000000000000000000..ca51f699e8c8c53e1c0ebee4b6a07914300ce560
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/acr/SAttribute.scala
@@ -0,0 +1,13 @@
+package org.rosi_project.model_sync.generator.acr
+import org.rosi_project.model_sync.generator.sync_model.SModelVisitor
+
+/**
+  * @author Rico Bergmann
+  */
+case class SAttribute(name: String, attrType: STypedElement) extends SModelElement {
+
+  def getType: String = attrType.getName
+
+  override def accept(visitor: SModelVisitor): Unit = visitor.visit(this)
+
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr/SClass.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr/SClass.scala
new file mode 100644
index 0000000000000000000000000000000000000000..e7782503ab25181285604e4773959fb64f47d26c
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/acr/SClass.scala
@@ -0,0 +1,87 @@
+package org.rosi_project.model_sync.generator.acr
+
+import org.rosi_project.model_sync.generator.sync_model.SModelVisitor
+
+/** Abstraction of a model element class which should be synced.
+  *
+  * @author Rico Bergmann
+  */
+class SClass(val name: String,
+             var attributes: Seq[SAttribute] = Seq.empty,
+             val sPackage: String = "",
+             var parent: STypedElement = null,
+             var methods: Seq[SMethod] = Seq.empty)
+  extends STypedElement {
+
+  private var constructorStatements: Seq[SMethodStatement] = Seq.empty
+
+  def getAdditionalConstructorStatements: Seq[SMethodStatement] = constructorStatements
+
+  def isDefaultPackage: Boolean = sPackage == ""
+
+  def isRootClass: Boolean = parent == null
+
+  def collectImports: Set[String] = {
+    val parentImport: List[String] = if (isRootClass) List() else includeImportIfNecessary(parent.getPackage, parent.getName)
+
+    val attrTypeImports: List[String] =
+      attributes
+        .map(attr => includeImportIfNecessary(attr.attrType.getPackage, attr.getType))
+        .fold(List())((l1, l2) => l1 ++ l2)
+
+    val methodResultImports: List[String] =
+      methods
+        .map(_.result)
+        .map(res => includeImportIfNecessary(res.getPackage, res.getName))
+        .fold(List())((l1, l2) => l1 ++ l2)
+
+    val methodParamImports: List[String] =
+      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[String] =
+      methods
+        .map(_.implementationUsedTypes.toList)
+        .fold(List())((l1, l2) => l1 ++ l2)
+        .map(typ => includeImportIfNecessary(typ.getName, typ.getPackage))
+        .fold(List())((l1, l2) => l1 ++ l2)
+
+    (parentImport ++ attrTypeImports ++ methodResultImports ++ methodParamImports ++ methodImplImports).toSet
+  }
+
+  def addMethod(m: SMethod): Unit = methods = methods :+ m
+
+  def augmentConstructor(statement: SMethodStatement): Unit = constructorStatements = constructorStatements :+ statement
+
+  def setParent(parent: STypedElement): Unit = this.parent = parent
+
+  def setAttributes(attrs: Seq[SAttribute]): Unit = this.attributes = attrs
+
+  override def getName: String = name
+
+  override def getPackage: String = sPackage
+
+  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
+  }
+
+  override def getInheritanceHierarchy: Seq[STypedElement] = if (isRootClass) List(this) else this +: parent.getInheritanceHierarchy
+
+  override def accept(visitor: SModelVisitor): Unit = {
+    attributes.foreach(_.accept(visitor))
+    methods.foreach(_.accept(visitor))
+    visitor.visit(this)
+  }
+
+  private def includeImportIfNecessary(sPackage: String, sClass: String): List[String] = {
+    if (sPackage != this.sPackage && sPackage != "") List(s"$sPackage.$sClass") else List()
+  }
+
+  override def toString: String = s"$name"
+
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr/SGetter.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr/SGetter.scala
new file mode 100644
index 0000000000000000000000000000000000000000..160e39b243d656d910a0fa16f63243f7e27a0bbf
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/acr/SGetter.scala
@@ -0,0 +1,15 @@
+package org.rosi_project.model_sync.generator.acr
+
+import org.rosi_project.model_sync.generator.support.StringUtils
+
+
+/**
+  * @author Rico Bergmann
+  */
+class SGetter(attr: SAttribute) extends SMethod(
+  name = s"get${StringUtils.firstLetterToUpperCase(attr.name)}",
+  result = attr.attrType,
+  params = Seq.empty,
+  implementation = Seq(SMethodStatement(attr.name))) {
+
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr/SMethod.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr/SMethod.scala
new file mode 100644
index 0000000000000000000000000000000000000000..7bf7e1d8ad7b031eaeaac23a8f069fba44c0ea95
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/acr/SMethod.scala
@@ -0,0 +1,27 @@
+package org.rosi_project.model_sync.generator.acr
+
+import org.rosi_project.model_sync.generator.sync_model.SModelVisitor
+
+// TODO use a simple DSL to represent the method body
+
+/**
+  * @author Rico Bergmann
+  */
+class SMethod(val name: String,
+              val result: STypedElement,
+              val params: Seq[SMethodParameter],
+              var implementation: Seq[SMethodStatement],
+              var implementationUsedTypes: Set[STypedElement] = Set.empty)
+  extends SModelElement {
+
+  def getResultType: String = result.getName
+
+  def updateImplementation(impl: Seq[SMethodStatement]): Unit = this.implementation = impl
+
+  def augmentImplementation(statement: SMethodStatement): Unit = this.implementation = this.implementation :+ statement
+
+  override def accept(visitor: SModelVisitor): Unit = visitor.visit(this)
+
+  override def toString: String = s"$name"
+
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr/SMethodParameter.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr/SMethodParameter.scala
new file mode 100644
index 0000000000000000000000000000000000000000..5951f01975dc466b906912e8fdb58ae9df6ff73e
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/acr/SMethodParameter.scala
@@ -0,0 +1,10 @@
+package org.rosi_project.model_sync.generator.acr
+
+/**
+  * @author Rico Bergmann
+  */
+case class SMethodParameter(name: String, paramType: STypedElement) {
+
+  def getType: String = paramType.getName
+
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr/SMethodStatement.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr/SMethodStatement.scala
new file mode 100644
index 0000000000000000000000000000000000000000..5bfa5f74cd5065bded80b46fc3e7a36532877495
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/acr/SMethodStatement.scala
@@ -0,0 +1,8 @@
+package org.rosi_project.model_sync.generator.acr
+
+/**
+  * @author Rico Bergmann
+  */
+case class SMethodStatement(content: String) {
+
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr/SModelElement.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr/SModelElement.scala
new file mode 100644
index 0000000000000000000000000000000000000000..193fa526dd59a0bf60c0c6e407e5dc5a69e602e5
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/acr/SModelElement.scala
@@ -0,0 +1,12 @@
+package org.rosi_project.model_sync.generator.acr
+
+import org.rosi_project.model_sync.generator.sync_model.SModelVisitor
+
+/**
+  * @author Rico Bergmann
+  */
+trait SModelElement {
+
+  def accept(visitor: SModelVisitor)
+
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr/SSetter.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr/SSetter.scala
new file mode 100644
index 0000000000000000000000000000000000000000..09e65ecba2dd354a6994b2256b1ae45dfd8647d4
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/acr/SSetter.scala
@@ -0,0 +1,14 @@
+package org.rosi_project.model_sync.generator.acr
+
+import org.rosi_project.model_sync.generator.support.StringUtils
+
+/**
+  * @author Rico Bergmann
+  */
+class SSetter(attr: SAttribute) extends SMethod(
+  name = s"set${StringUtils.firstLetterToUpperCase(attr.name)}",
+  result = SType.UNIT,
+  params = Seq(SMethodParameter(attr.name.head.toString, attr.attrType)),
+  implementation = Seq(SMethodStatement(s"${attr.name} = ${attr.name.head}"))) {
+
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr/SType.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr/SType.scala
new file mode 100644
index 0000000000000000000000000000000000000000..a7de086a5d0f6b397d2fa676cf666a746d943520
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/acr/SType.scala
@@ -0,0 +1,21 @@
+package org.rosi_project.model_sync.generator.acr
+import org.rosi_project.model_sync.generator.sync_model.SModelVisitor
+
+/**
+  * @author Rico Bergmann
+  */
+case class SType(name: String, sPackage: String = "") extends STypedElement {
+
+  override def getName: String = name
+
+  override def getPackage: String = sPackage
+
+  override def accept(visitor: SModelVisitor): Unit = visitor.visit(this)
+
+}
+
+object SType {
+
+  val UNIT = SType("Unit")
+
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr/STypedElement.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr/STypedElement.scala
new file mode 100644
index 0000000000000000000000000000000000000000..faa239e919c3a20b214b5a256c9e7d829f00f529
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/acr/STypedElement.scala
@@ -0,0 +1,16 @@
+package org.rosi_project.model_sync.generator.acr
+
+/**
+  * @author Rico Bergmann
+  */
+trait STypedElement extends SModelElement {
+
+  def getName: String
+
+  def getPackage: String
+
+  def getConstructorParameters: Seq[SMethodParameter] = Seq.empty
+
+  def getInheritanceHierarchy: Seq[STypedElement] = Seq.empty
+
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/acr/package.scala b/src/main/scala/org/rosi_project/model_sync/generator/acr/package.scala
new file mode 100644
index 0000000000000000000000000000000000000000..62fc1c074a125a94d79a8438c0b8217ca4c70701
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/acr/package.scala
@@ -0,0 +1,8 @@
+package org.rosi_project.model_sync.generator
+
+/** Abstract class representation of the Scala code to generate
+  * @author Rico Bergmann
+  */
+package object acr {
+
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..776643f8ef3be5d7049d4cf74898ecf15e58e87e
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/conversion/Converter.scala
@@ -0,0 +1,10 @@
+package org.rosi_project.model_sync.generator.conversion
+
+/**
+  * @author Rico Bergmann
+  */
+trait Converter[S, T] {
+
+  def convert(source: S): 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
new file mode 100644
index 0000000000000000000000000000000000000000..463f272e655c8ea6a88542a28058d32b6e517a99
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/conversion/EmfTypeTranslator.scala
@@ -0,0 +1,17 @@
+package org.rosi_project.model_sync.generator.conversion
+
+import org.eclipse.emf.ecore.EDataType
+import org.rosi_project.model_sync.generator.acr.SType
+
+/**
+  * @author Rico Bergmann
+  */
+object EmfTypeTranslator {
+
+  private val typeMap: Map[String, SType] = Map(
+    "EString" -> SType("String")
+  )
+
+  def getSClassFromEmf(dataType: EDataType): Option[SType] = typeMap.get(dataType.getName)
+
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..e56125f6373cc455ab0abe0cdc99087818d90271
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/conversion/SClassConverter.scala
@@ -0,0 +1,59 @@
+package org.rosi_project.model_sync.generator.conversion
+
+import org.eclipse.emf.ecore.{EAttribute, EClass}
+import org.rosi_project.model_sync.generator.acr.{SAttribute, SClass, STypedElement}
+import org.rosi_project.model_sync.generator.sync_model.STypeRegistry
+
+/**
+  * @author Rico Bergmann
+  */
+class SClassConverter extends Converter[EClass, SClass] {
+
+  override def convert(source: EClass): SClass = {
+    var attrs: List[SAttribute] = List.empty
+
+    (source.getEAttributes: List[EAttribute]).foreach(eAttr => {
+      val attrType: STypedElement = STypeRegistry.query(eAttr.getEAttributeType.getName, eAttr.getEAttributeType.getEPackage.getName).getOrElse {
+        val newAttr = EmfTypeTranslator.getSClassFromEmf(eAttr.getEAttributeType).getOrElse(new SClass(eAttr.getEAttributeType.getName, sPackage = eAttr.getEAttributeType.getEPackage.getName))
+        STypeRegistry.addType(newAttr)
+      }
+      attrs ::= SAttribute(eAttr.getName, attrType)
+    })
+
+    val parents: List[EClass] = source.getESuperTypes.toArray(new Array[EClass](0)).toList
+
+    if (violatesSingleInheritance(parents)) {
+      throw new UnconvertibleEmfException(source.getEPackage, s"For class: $source")
+    }
+
+    val parent: STypedElement = parents.headOption.map((p: EClass) => {
+      STypeRegistry.queryForName(p.getName).getOrElse {
+        val parentSClass: SClass = new SClass(p.getName, sPackage = p.getEPackage.getName)
+        STypeRegistry.addType(parentSClass)
+        parentSClass
+      }
+    }).orNull
+
+
+    // TODO add methods to SClass
+
+    val currentClass: Option[STypedElement] = STypeRegistry.query(source.getName, source.getEPackage.getName)
+
+    currentClass.map {
+      case clazz: SClass =>
+        clazz.attributes = attrs
+        clazz.parent = parent
+        clazz
+      case sType =>
+        sys.error(s"sType should have been a class: $sType")
+    }.getOrElse {
+      val createdClass: SClass = new SClass(source.getName, attrs, source.getEPackage.getName, parent)
+      STypeRegistry.addType(createdClass)
+      createdClass
+    }
+
+  }
+
+  private def violatesSingleInheritance(parents: List[EClass]): Boolean = parents.length > 1
+
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..170416c884b40133348cf258857a49482b9a6620
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/conversion/SModelGenerator.scala
@@ -0,0 +1,39 @@
+package org.rosi_project.model_sync.generator.conversion
+
+import org.eclipse.emf.ecore.{EClass, EGenericType, EPackage}
+import org.rosi_project.model_sync.generator.acr.SType
+import org.rosi_project.model_sync.generator.sync_model.{SModel, STypeRegistry, SimpleSModel}
+
+import scala.collection.JavaConverters._
+
+/**
+  * @author Rico Bergmann
+  */
+object 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(packageName)
+
+    contents.foreach {
+      case ec: EClass =>
+        model.addModelClass(new SClassConverter convert ec)
+
+        STypeRegistry.addType(SType(ec.getName, packageName))
+        println(s"Found class $ec")
+      case et: EGenericType=>
+        //STypeRegistry.addType(SType(et.eClass().getName, packageName))
+        println(s"Found type $et")
+      case obj =>
+        println(s"Found something else: $obj")
+    }
+
+    println(s"The TypeRegistry:\n${STypeRegistry.allTypes}")
+    println(s"The model:\n$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
new file mode 100644
index 0000000000000000000000000000000000000000..a10220112001e3e74c695edeb35fe8bc2edf3512
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/conversion/SModelGeneratorTest.scala
@@ -0,0 +1,21 @@
+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 => SModelGenerator.convert(e.asInstanceOf[EPackage]))
+
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/conversion/UnconvertibleEmfException.scala b/src/main/scala/org/rosi_project/model_sync/generator/conversion/UnconvertibleEmfException.scala
new file mode 100644
index 0000000000000000000000000000000000000000..86b2857b79291e4c0dbd528d26b2fd0593d1bbab
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/conversion/UnconvertibleEmfException.scala
@@ -0,0 +1,12 @@
+package org.rosi_project.model_sync.generator.conversion
+
+import org.eclipse.emf.ecore.EPackage
+
+/**
+  * @author Rico Bergmann
+  */
+class UnconvertibleEmfException(val model: EPackage, val message: String = "") extends RuntimeException(message) {
+
+  override def toString: String = s"UnconvertibleException: $model ${if (message.isEmpty) "" else s"($message)"}"
+
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/conversion/package.scala b/src/main/scala/org/rosi_project/model_sync/generator/conversion/package.scala
new file mode 100644
index 0000000000000000000000000000000000000000..436c3f61beeb2d87c1b321eb4c5aa7e08fb7748d
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/conversion/package.scala
@@ -0,0 +1,20 @@
+package org.rosi_project.model_sync.generator
+
+import org.eclipse.emf.common.util.EList
+
+/**
+  * @author Rico Bergmann
+  */
+package object conversion {
+
+  implicit def elist2slist[T](elst: EList[T]): List[T] = {
+    if (elst == null) {
+      null
+    } else {
+      var res: List[T] = List()
+      elst.forEach(elem => res = res :+ elem)
+      res
+    }
+  }
+
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/io/EmfImporter.scala b/src/main/scala/org/rosi_project/model_sync/generator/io/EmfImporter.scala
new file mode 100644
index 0000000000000000000000000000000000000000..f1eb7eedd5a6e49943aeee56be84d3b3811661f0
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/io/EmfImporter.scala
@@ -0,0 +1,8 @@
+package org.rosi_project.model_sync.generator.io
+
+/**
+  * @author Rico Bergmann
+  */
+class EmfImporter {
+
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..748a7e69fdccac4297551d3be4db75fd9097c191
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/io/SClassWriter.scala
@@ -0,0 +1,70 @@
+package org.rosi_project.model_sync.generator.io
+
+import org.rosi_project.model_sync.generator.acr.{SAttribute, SMethod, SClass}
+
+/**
+  * @author Rico Bergmann
+  */
+class SClassWriter(val modelClass: SClass) {
+
+  private val pckg: String = if (modelClass.isDefaultPackage) "" else s"package ${modelClass.sPackage}"
+  private val imports: Seq[String] = modelClass.collectImports.toSeq
+
+  private val clazzFixture: String = generateClassFixture
+
+  def stringify: String = {
+    s"""$pckg
+       |
+       |${imports.map(i => s"import $i").mkString("\n")}
+       |
+       |class $clazzFixture {
+       |
+       |  ${modelClass.getAdditionalConstructorStatements.map(_.content).mkString("\n")}
+       |
+       |  ${modelClass.methods.map(stringifyMethod).mkString("\n")}
+       |
+       |}
+    """.stripMargin
+  }
+
+  protected def generateGetter(attr: SAttribute): String =
+    s"def get${firstLetterToUpperCase(attr.name)}(): ${attr.getType} = ${attr.name}"
+
+  protected def generateSetter(attr: SAttribute): String = {
+    s"""def set${firstLetterToUpperCase(attr.name)}(${attr.name.head}: ${attr.getType}): Unit = {
+       |  this.${attr.name} = ${attr.name.head}
+       |}
+     """.stripMargin
+  }
+
+  protected def stringifyMethod(m: SMethod): String = {
+    s"""def ${m.name}(${m.params.map(param => s"${param.name}: ${param.getType}").mkString(", ")}): ${m.getResultType} = {
+       |  ${m.implementation.map(_.content).mkString("\n")}
+       |}
+     """.stripMargin
+  }
+
+  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(", ")
+
+    val parentConstructor: String = if (modelClass.isRootClass) "" else s"(${modelClass.parent.getConstructorParameters.map(_.name).toList.mkString(", ")})"
+
+    if (parentConstructorParams != "")
+      params ::= parentConstructorParams
+
+    val constructor = s"(${params.mkString(", ")})"
+    var baseFixture = s"${modelClass.getName}$constructor"
+
+    if (modelClass.isRootClass) baseFixture else s"$baseFixture extends ${modelClass.parent.getName}$parentConstructor"
+  }
+
+  private def firstLetterToUpperCase(str: String): String = {
+    str.head.toUpper + str.tail
+  }
+
+}
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/io/SClassWriterTest.scala
new file mode 100644
index 0000000000000000000000000000000000000000..ecd08594aa7bbbc833bfd3cce000799776201c36
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/io/SClassWriterTest.scala
@@ -0,0 +1,26 @@
+package org.rosi_project.model_sync.generator.io
+
+import org.rosi_project.model_sync.generator.acr._
+import org.rosi_project.model_sync.generator.sync_model.{GetterSetterGeneratingVisitor, SyncEnhancingVisitor}
+
+/**
+  * @author Rico Bergmann
+  */
+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", attrs, methods = Seq(sayHelloMethod))
+
+  val getterSetterVisitor = new GetterSetterGeneratingVisitor
+  modelClass.accept(getterSetterVisitor)
+
+  val syncNotificationVisitor = new SyncEnhancingVisitor
+  modelClass.accept(syncNotificationVisitor)
+
+  val writer = new SClassWriter(modelClass)
+
+  println(writer.stringify)
+
+}
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
new file mode 100644
index 0000000000000000000000000000000000000000..133c07a5f4acc140b62dc38b581adac661f37bf8
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/io/SModelFSWriter.scala
@@ -0,0 +1,170 @@
+package org.rosi_project.model_sync.generator.io
+
+import java.io.{ BufferedInputStream, FileInputStream, FileOutputStream, PrintWriter }
+import java.net.URLClassLoader
+import java.nio.file.Files
+import java.util.jar.{ Attributes, JarEntry, JarOutputStream, Manifest }
+
+import org.rosi_project.model_sync.generator.acr.{ SAttribute, SClass, SMethod, SType }
+import org.rosi_project.model_sync.generator.sync_model.{ SModel, SModelVisitor }
+
+import scala.reflect.io.{ File, Path }
+import scala.tools.nsc.reporters.ConsoleReporter
+import scala.tools.nsc.{ GenericRunnerSettings, Global, Settings }
+import scala.util.control.Breaks._
+import scala.reflect.io.Directory
+
+/** @author Rico Bergmann
+  */
+class SModelFSWriter(
+    workingDir: File = File(Files.createTempDirectory("model").toFile),
+    outputDir: Directory = File("output").toDirectory,
+    keepClassFiles: Boolean = false) extends SModelVisitor {
+
+  workingDir.jfile.mkdirs()
+  outputDir.jfile.mkdirs()
+
+  private var sFilesToCompile: List[File] = List.empty
+
+  println(s"... Temp dir (sources) is $workingDir")
+
+  override def visit(sModel: SModel): Unit = {
+    println(s"... Wrote files (sources) $sFilesToCompile")
+
+    println("... Starting compilation")
+    // see: https://stackoverflow.com/a/20323371/5161760
+    val out = new PrintWriter(System.out)
+    val compilationSettings: Settings = new GenericRunnerSettings(out.println)
+    // TODO do we want to reuse the whole classpath? Or just the parts we _actually_ need
+    compilationSettings.classpath.value = adaptClassPathToOSEnv(fetchCurrentClassPath).distinct.mkString(File.pathSeparator)
+    println(s"Using classpath ${compilationSettings.classpath.value}")
+    compilationSettings.outdir.value = workingDir.toAbsolute.toString
+    val reporter = new ConsoleReporter(compilationSettings)
+    val compiler = new Global(compilationSettings, reporter)
+    val runner = new compiler.Run
+    runner.compile(sFilesToCompile.map(_.toAbsolute.toString))
+    println("... Compilation done")
+
+    if (!keepClassFiles) {
+      println("... Cleaning up")
+      sFilesToCompile.foreach {
+        _.delete
+      }
+    } else {
+      println("... No clean-up requested")
+    }
+
+    println("... Generating JAR")
+    // see: https://stackoverflow.com/a/1281295/5161760
+    val mf = new Manifest
+    mf.getMainAttributes.put(Attributes.Name.MANIFEST_VERSION, "1.0")
+    val targetJar = new JarOutputStream(new FileOutputStream(outputDir + File.separator + "model.jar"), mf)
+    var filesToAdd: List[java.io.File] = workingDir.jfile.listFiles.toList
+
+    while (filesToAdd.nonEmpty) {
+      val file = filesToAdd.head
+      var fname = file.getAbsolutePath.replace(workingDir.jfile.getAbsolutePath + File.separator, "").replaceAll("\\\\", "/")
+      println(s"Adding to JAR: $fname")
+      if (file.isDirectory) {
+        if (!fname.endsWith("/")) {
+          fname += "/"
+        }
+        filesToAdd ++= file.listFiles.toList
+
+        val entry = new JarEntry(fname)
+        entry.setTime(file.lastModified)
+        targetJar.putNextEntry(entry)
+        targetJar.closeEntry()
+      } else {
+        val entry = new JarEntry(fname)
+        entry.setTime(file.lastModified)
+        targetJar.putNextEntry(entry)
+
+        val in = new BufferedInputStream(new FileInputStream(file))
+        var buffer = new Array[Byte](1024)
+        breakable {
+          while (true) {
+            val bytesRead = in.read(buffer)
+            if (bytesRead == -1) {
+              break
+            }
+            targetJar.write(buffer, 0, bytesRead)
+          }
+        }
+        targetJar.closeEntry()
+        in.close()
+      }
+
+      filesToAdd = filesToAdd.tail
+    }
+
+    targetJar.close()
+    println("... Done")
+  }
+
+  override def visit(sClass: SClass): Unit = {
+    println(s"Writing class $sClass")
+    val classNameWithPath = workingDir.toAbsolute.toString() + File.separator + pckg2Path(sClass.getPackage) + File.separator + s"${sClass.name}.scala"
+    val writer = new SClassWriter(sClass)
+
+    val classFile = File(classNameWithPath)
+
+    classFile.jfile.getParentFile.mkdirs()
+    classFile.writeAll(writer.stringify)
+    sFilesToCompile ::= classFile
+  }
+
+  override def visit(sAttr: SAttribute): Unit = {
+    // pass
+  }
+
+  override def visit(sMethod: SMethod): Unit = {
+    // pass
+  }
+
+  override def visit(sType: SType): Unit = {
+    // pass
+  }
+
+  private def pckg2Path(pckg: String): Path = Path(pckg.replace(".", File.separator))
+
+  private def fetchCurrentClassPath: List[String] = {
+    val ctxLoader = Thread.currentThread().getContextClassLoader
+    ctxLoader match {
+      case urlCL: URLClassLoader =>
+        urlCL.getURLs.toList.map {
+          _.toString
+        }
+      case wrappedCL =>
+        wrappedCL.getParent match {
+          case urlCL: URLClassLoader =>
+            urlCL.getURLs.toList.map {
+              _.toString
+            }
+          case something => sys.error(s"Could not unwrap class loader: $something")
+        }
+    }
+  }
+
+  private def adaptClassPathToOSEnv(cp: List[String]): List[String] = {
+    sys.props("os.name").toLowerCase match {
+      case win if win contains "windows" =>
+        cp.map(entry => {
+          val WinUrl = """file:/(.*)""".r
+          entry match {
+            case WinUrl(path) => path
+            case p => p
+          }
+        }).map(_.replaceAll("/", "\\\\").replaceAll("%20", " "))
+      case unix =>
+        val UnixUrl = """file:(.*)""".r
+        cp.map(entry => {
+          entry match {
+            case UnixUrl(path) => path
+            case p => p
+          }
+        })
+    }
+  }
+
+}
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/io/SModelFSWriterTest.scala
new file mode 100644
index 0000000000000000000000000000000000000000..461367d73a1eb5fa3f9a65a831690811fea2d185
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/io/SModelFSWriterTest.scala
@@ -0,0 +1,27 @@
+package org.rosi_project.model_sync.generator.io
+
+import org.rosi_project.model_sync.generator.acr._
+import org.rosi_project.model_sync.generator.sync_model.{ GetterSetterGeneratingVisitor, SimpleSModel, SyncEnhancingVisitor }
+import scala.reflect.io.File
+
+/** @author Rico Bergmann
+  */
+object SModelFSWriterTest/* extends App */{
+
+  val model = new SimpleSModel("org.foo")
+
+  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", personAttrs, methods = Seq(personSayHelloMethod), sPackage = "foo")
+
+  val getterSetterVisitor = new GetterSetterGeneratingVisitor
+  val syncNotificationVisitor = new SyncEnhancingVisitor
+
+  model.addModelClass(personClass)
+
+  model.accept(getterSetterVisitor)
+  model.accept(syncNotificationVisitor)
+  model.accept(new SModelFSWriter(workingDir = File("output/raw"), keepClassFiles = true))
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/support/Assert.scala b/src/main/scala/org/rosi_project/model_sync/generator/support/Assert.scala
new file mode 100644
index 0000000000000000000000000000000000000000..abf3f38aa107c6b2887cc286bc062e93fe89025b
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/support/Assert.scala
@@ -0,0 +1,16 @@
+package org.rosi_project.model_sync.generator.support
+
+/**
+  * @author Rico Bergmann
+  */
+object Assert {
+
+  def notNull(obj: AnyRef, msg: String): Unit = isTrue(obj != null, msg)
+
+  def isTrue(cond: Boolean, msg: String): Unit = if (!cond) {
+      throw new AssertionError(msg)
+  }
+
+  def isFalse(cond: Boolean, msg: String): Unit = isTrue(!cond, msg)
+
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/support/GenericRegistry.scala b/src/main/scala/org/rosi_project/model_sync/generator/support/GenericRegistry.scala
new file mode 100644
index 0000000000000000000000000000000000000000..81889257cfceb9effc6b20a56ad4aaa60729f803
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/support/GenericRegistry.scala
@@ -0,0 +1,10 @@
+package org.rosi_project.model_sync.generator.support
+
+/**
+  * @author Rico Bergmann
+  */
+class GenericRegistry[T](val unique: Boolean = true) {
+
+  
+
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/support/StringUtils.scala b/src/main/scala/org/rosi_project/model_sync/generator/support/StringUtils.scala
new file mode 100644
index 0000000000000000000000000000000000000000..338834dd93d4afe054adfd8edad772e7f38bb521
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/support/StringUtils.scala
@@ -0,0 +1,12 @@
+package org.rosi_project.model_sync.generator.support
+
+/**
+  * @author Rico Bergmann
+  */
+object StringUtils {
+
+  def firstLetterToUpperCase(str: String): String =
+    str.headOption.map(h => h.toUpper + str.tail).getOrElse("")
+
+
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync_model/GetterSetterGeneratingVisitor.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync_model/GetterSetterGeneratingVisitor.scala
new file mode 100644
index 0000000000000000000000000000000000000000..11207a6861fef44b0b06eca25c42f8ac279282d8
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/sync_model/GetterSetterGeneratingVisitor.scala
@@ -0,0 +1,34 @@
+package org.rosi_project.model_sync.generator.sync_model
+import org.rosi_project.model_sync.generator.acr._
+
+/**
+  * @author Rico Bergmann
+  */
+class GetterSetterGeneratingVisitor extends SModelVisitor {
+
+  override def visit(sModel: SModel): Unit = {
+    // pass
+  }
+
+  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)
+    })
+
+  }
+
+  override def visit(sAttr: SAttribute): Unit = {
+    // pass
+  }
+
+  override def visit(sMethod: SMethod): Unit = {
+    // pass
+  }
+
+  override def visit(sType: SType): Unit = {
+    // pass
+  }
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync_model/SModel.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync_model/SModel.scala
new file mode 100644
index 0000000000000000000000000000000000000000..b2bd7883623e3770b89e44c7cb66e7bd0315b950
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/sync_model/SModel.scala
@@ -0,0 +1,16 @@
+package org.rosi_project.model_sync.generator.sync_model
+
+import org.rosi_project.model_sync.generator.acr.{SClass, SModelElement}
+
+/**
+  * @author Rico Bergmann
+  */
+trait SModel extends SModelElement {
+
+  def getPackageName: String
+
+  def getAllClasses: Set[SClass]
+
+  override def toString: String = s"SModel: pckg=$getPackageName, classes=$getAllClasses"
+
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync_model/SModelVisitor.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync_model/SModelVisitor.scala
new file mode 100644
index 0000000000000000000000000000000000000000..0d1dd128e214e33c2044bdd2554745c1ad6faed3
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/sync_model/SModelVisitor.scala
@@ -0,0 +1,22 @@
+package org.rosi_project.model_sync.generator.sync_model
+
+import org.rosi_project.model_sync.generator.acr.{SAttribute, SMethod, SClass, SType}
+
+// TODO fix cyclic imports with classes from acr package
+
+/**
+  * @author Rico Bergmann
+  */
+trait SModelVisitor {
+
+  def visit(sModel: SModel): Unit
+
+  def visit(sClass: SClass): Unit
+
+  def visit(sAttr: SAttribute): Unit
+
+  def visit(sMethod: SMethod): Unit
+
+  def visit(sType: SType): Unit
+
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync_model/STypeRegistry.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync_model/STypeRegistry.scala
new file mode 100644
index 0000000000000000000000000000000000000000..a0be35f80cb61e92ae776de81fb86d87bcc6892b
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/sync_model/STypeRegistry.scala
@@ -0,0 +1,49 @@
+package org.rosi_project.model_sync.generator.sync_model
+
+import org.rosi_project.model_sync.generator.acr.{SType, STypedElement}
+
+/**
+  * @author Rico Bergmann
+  */
+object STypeRegistry {
+
+  private var registeredTypes: Set[STypedElement] = Set()
+
+  registerDefaultTypes()
+
+  def addType(theType: STypedElement): STypedElement = {
+    if (!registeredTypes.contains(theType)) {
+      registeredTypes += theType
+    }
+    theType
+  }
+
+  def query(name: String, sPackage: String): Option[STypedElement] = {
+    registeredTypes.find(t => t.getName == name && t.getPackage == sPackage)
+  }
+
+  def queryForName(name: String): Option[STypedElement] = {
+    registeredTypes.find(_.getName == name)
+  }
+
+  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"),
+      SType("Set"),
+      SType("List"),
+      SType("Map")
+    )
+  }
+
+  override def toString: String = s"Registry: $registeredTypes"
+
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync_model/SimpleSModel.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync_model/SimpleSModel.scala
new file mode 100644
index 0000000000000000000000000000000000000000..4bb43ec9bba28a9fdb01342d230f1f54898ebf14
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/sync_model/SimpleSModel.scala
@@ -0,0 +1,22 @@
+package org.rosi_project.model_sync.generator.sync_model
+import org.rosi_project.model_sync.generator.acr.SClass
+
+/**
+  * @author Rico Bergmann
+  */
+class SimpleSModel(val sPackage: String = "") extends SModel {
+
+  var sClasses: Set[SClass] = Set.empty
+
+  def addModelClass(mClass: SClass): Unit = sClasses += mClass
+
+  override def getPackageName: String = sPackage
+
+  override def getAllClasses: Set[SClass] = sClasses
+
+  override def accept(visitor: SModelVisitor): Unit = {
+    sClasses.foreach(_.accept(visitor))
+    visitor.visit(this)
+  }
+
+}
diff --git a/src/main/scala/org/rosi_project/model_sync/generator/sync_model/SyncEnhancingVisitor.scala b/src/main/scala/org/rosi_project/model_sync/generator/sync_model/SyncEnhancingVisitor.scala
new file mode 100644
index 0000000000000000000000000000000000000000..8306d15a07554312bd98df0d67fc34e3dc53e27b
--- /dev/null
+++ b/src/main/scala/org/rosi_project/model_sync/generator/sync_model/SyncEnhancingVisitor.scala
@@ -0,0 +1,57 @@
+package org.rosi_project.model_sync.generator.sync_model
+import org.rosi_project.model_sync.generator.acr._
+import org.rosi_project.model_sync.sync.PlayerSync
+
+/**
+  * @author Rico Bergmann
+  */
+class SyncEnhancingVisitor extends SModelVisitor {
+
+  override def visit(sModel: SModel): Unit = {
+    // pass
+  }
+
+  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)
+
+  }
+
+  override def visit(sAttr: SAttribute): Unit = {
+    // pass
+  }
+
+  override def visit(sMethod: SMethod): Unit = {
+    extractSetterAttr(sMethod).foreach(attr => sMethod.augmentImplementation(SMethodStatement(s"+this change$attr ()")))
+  }
+
+  override def visit(sType: SType): Unit = {
+    // pass
+  }
+
+  private def extractSetterAttr(sMethod: SMethod): Option[String] = {
+    sMethod.name match {
+      case SyncEnhancingVisitor.Setter(attrName) =>
+        Option(attrName)
+      case _ =>
+        None
+    }
+
+  }
+
+}
+
+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 PLAYER_SYNC_INIT = SMethodStatement("buildClass()")
+
+}