Skip to content
Snippets Groups Projects
Verified Commit bae4609f authored by Rico Bergmann's avatar Rico Bergmann
Browse files

Merge branch 'develop' of https://git-st.inf.tu-dresden.de/cwerner/code_generator into develop

This resolves conflicts due to updates in the SUMProvider submodule
which were not included originally (which is one of the reasons why we
wanted to get rid of them!)
parents 538e567b 61aa52b4
No related branches found
No related tags found
No related merge requests found
Showing
with 292 additions and 113 deletions
...@@ -49,8 +49,6 @@ ...@@ -49,8 +49,6 @@
</eClassifiers> </eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="Library"> <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:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
<eStructuralFeatures xsi:type="ecore:EAttribute" name="people" upperBound="-1"
eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFeatureMapEntry"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="stock" upperBound="-1" <eStructuralFeatures xsi:type="ecore:EReference" name="stock" upperBound="-1"
eType="#//Item" containment="true"/> eType="#//Item" containment="true"/>
<eStructuralFeatures xsi:type="ecore:EReference" name="books" upperBound="-1" <eStructuralFeatures xsi:type="ecore:EReference" name="books" upperBound="-1"
......
...@@ -20,8 +20,8 @@ object CLIGenerator extends App { ...@@ -20,8 +20,8 @@ object CLIGenerator extends App {
val parser = new OptionParser[GeneratorConfig](programName="modelgen") { val parser = new OptionParser[GeneratorConfig](programName="modelgen") {
head("modelgen", "0.1") head("modelgen", "0.1")
arg[jio.File]("ecore").required().action( (ef, conf) => arg[Seq[jio.File]]("ecore").required().action( (ef, conf) =>
conf.copy(source = ef.getAbsolutePath) conf.copy(sources = ef.map(f => f.getAbsolutePath))
).text("The ecore (XML) file of the model") ).text("The ecore (XML) file of the model")
opt[jio.File]('o', "outdir").optional().action( (dir, conf) => opt[jio.File]('o', "outdir").optional().action( (dir, conf) =>
...@@ -32,13 +32,17 @@ object CLIGenerator extends App { ...@@ -32,13 +32,17 @@ object CLIGenerator extends App {
conf.copy(workDir = dir) conf.copy(workDir = dir)
).text("The directory to place the generated .scala files in (temp dir by default)") ).text("The directory to place the generated .scala files in (temp dir by default)")
opt[jio.File]('m', "model").optional().action( (mj, conf) => opt[Boolean]('c', "cleanup").optional().action( (c, conf) =>
conf.copy(modelFile = mj.getAbsolutePath) conf.copy(cleanUp = c)
).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)
).text("Remove the generated .scala files and only keep the compiled .class files") ).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 { parser.parse(args, GeneratorConfig()) match {
......
package org.rosi_project.model_sync.generator package org.rosi_project.model_sync.generator
import net.liftweb.json._
import org.eclipse.emf.ecore._ import org.eclipse.emf.ecore._
import org.rosi_project.model_sync.generator.conversion.SModelGenerator 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.env.{CompilationException, JarPackaginException}
import org.rosi_project.model_sync.generator.io.{ClassWritingException, ModelImagePreparationException, SModelFSWriter} import org.rosi_project.model_sync.generator.io.{ClassWritingException, ModelImagePreparationException, SModelFSWriter}
import scala.io.Source
import scala.reflect.io.File import scala.reflect.io.File
import org.rosi_project.model_sync.generator.acr_model.SModel
import org.rosi_project.model_sync.model_join.representation.parser.legacy.DefaultModelJoinParser
/** The `Generator` runs the whole workflow of generating a JAR of compiled Scala source files /** The `Generator` runs the whole workflow of generating a JAR of compiled Scala source files
* based on an ECORE file of some sync model. * based on an ECORE file of some sync model.
...@@ -23,51 +23,82 @@ class Generator(config: GeneratorConfig) { ...@@ -23,51 +23,82 @@ class Generator(config: GeneratorConfig) {
*/ */
def run(): Unit = { def run(): Unit = {
try { try {
var modelCfg: ModelConfig = null if (config.sources.isEmpty) {
if (config.getModelFile.exists()) { println("Error: There must be any source file to generate something!!!")
val modelJson = Source.fromFile(config.getModelFile).getLines.mkString return
implicit val jsonFormats: Formats = DefaultFormats
modelCfg = parse(modelJson).extract[ModelConfig]
} }
var ecoreModel: EPackage = null //read the ecore models
var ecoreModels: Map[String, EPackage] = Map.empty
try { try {
ecoreModel = new EcoreLoader loadEcore config.source config.sources.foreach(s => {
ecoreModels = ecoreModels + (s -> (new EcoreLoader loadEcore s))
})
} catch { } catch {
case e: Exception => throw new EcoreLoadException(e) case e: Exception => throw new EcoreLoadException(e)
} }
val sModel = new SModelGenerator convert ecoreModel //create s models from the incoming ecore models
var sModels: Seq[SModel] = Seq.empty
ecoreModels.foreach(ec => {
sModels = sModels :+ (new SModelGenerator convert (ec._2, ec._1))
})
//double the class to create the code for the RSUM //create the new classes for rsum and rsync
if (config.getCreate == Creation.rsync) { if (config.getCreate == Creation.rsync) {
new SModelSyncPreparationService prepareModel(sModel, modelCfg) sModels.foreach(sm => {
} else { new SModelSyncPreparationService prepareModel(sm)
new SModelSyncUiPreparationService prepareModel(sm, config.getModelConfigFromEcore(sm.getSourceName))
})
}
if (config.getCreate == Creation.rsum) { if (config.getCreate == Creation.rsum) {
new SModelSUMPreparationService prepareModel(sModel) sModels.foreach(sm => {
//new SModelViewPreparationService prepareModel(sModel, modelCfg) new SModelSUMPreparationService prepareModel(sm)
val modelJoinFile = config.getModelJoinFile
println("ModelJoin File: " + modelJoinFile)
if (modelJoinFile != null && modelJoinFile.exists()) {
val expression = DefaultModelJoinParser.read(modelJoinFile).get
expression.getJoins.forEach(j => {
println("Type: " + j.getType + " Left: " + j.getLeft.getResourcePath + " " + j.getLeft.getResourceName + " Right: " + j.getRight + " Target: " + j.getTarget)
println(j)
j.getKeeps.forEach(k => {
println(k)
})
})
} }
})
} }
// write the model and create the JAR // write the model and create the JAR
println("... Writing model") println("... Writing model")
var finalModel: SModel = null
sModels.foreach(s => {
if (finalModel == null) {
finalModel = s
} else {
finalModel.addOtherModel(s)
}
})
if (config.hasWorkDir) { if (config.hasWorkDir) {
sModel.accept( finalModel.accept(
new SModelFSWriter( new SModelFSWriter(
config, config,
outputDir = File(config.outDir).toDirectory, outputDir = File(config.outDir).toDirectory,
workingDir = File(config.workDir), workingDir = File(config.workDir),
keepClassFiles = !config.cleanUp, keepClassFiles = !config.cleanUp,
modelCfg = modelCfg, modelCfgs = config.getAllModelConfigs,
currentDir = config.getModelPath)) currentDir = config.getModelPath(finalModel.getSourceName)))
} else { } else {
sModel.accept( finalModel.accept(
new SModelFSWriter( new SModelFSWriter(
config, config,
outputDir = File(config.outDir).toDirectory, outputDir = File(config.outDir).toDirectory,
keepClassFiles = !config.cleanUp, keepClassFiles = !config.cleanUp,
modelCfg = modelCfg, modelCfgs = config.getAllModelConfigs,
currentDir = config.getModelPath)) currentDir = config.getModelPath(finalModel.getSourceName)))
} }
println("... Done") println("... Done")
} }
......
package org.rosi_project.model_sync.generator package org.rosi_project.model_sync.generator
import java.io.File import java.io.File
import scala.io.Source
import net.liftweb.json._
/** Wrapper for the different command line options for the [[Generator]] /** Wrapper for the different command line options for the [[Generator]]
* *
* @author Rico Bergmann * @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
private var create = Creation.rsync private var create = Creation.rsync
...@@ -18,10 +25,35 @@ case class GeneratorConfig(source: String = "", cleanUp: Boolean = false, outDir ...@@ -18,10 +25,35 @@ case class GeneratorConfig(source: String = "", cleanUp: Boolean = false, outDir
def hasWorkDir: Boolean = workDir != null def hasWorkDir: Boolean = workDir != null
def getEcoreName: String = source.split("/").last.replace(".ecore", "") private def getEcoreNames: Seq[String] = sources.map(_.split("/").last.replace(".ecore", ""))
def getModelFile: File = if (modelFile.isEmpty) new File(source.replace(".ecore", ".sync.json")) else new File(modelFile) def getCombinedEcoreName: String = getEcoreNames.mkString
def getModelPath: File = new File(source).getParentFile 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 getModelPath(source: String): File = new File(source).getParentFile
def getModelJoinFile: File = if(modelJoin == null) null else new File(modelJoin)
def getSnchronizationFile: File = if(syncLanguage == null) null else new File(syncLanguage)
} }
...@@ -2,7 +2,6 @@ package org.rosi_project.model_sync.generator ...@@ -2,7 +2,6 @@ package org.rosi_project.model_sync.generator
import org.rosi_project.model_sync.generator.acr_model.SModel import org.rosi_project.model_sync.generator.acr_model.SModel
import org.rosi_project.model_sync.generator.sync.{GetterSetterGeneratingVisitor, SyncEnhancingVisitor} import org.rosi_project.model_sync.generator.sync.{GetterSetterGeneratingVisitor, SyncEnhancingVisitor}
import org.rosi_project.model_sync.generator.ui.SyncUiVisitor
/** Simple service to perform all the necessary adaptions of an [[SModel]] to make applicable for /** Simple service to perform all the necessary adaptions of an [[SModel]] to make applicable for
* synchronization. * synchronization.
...@@ -16,16 +15,11 @@ class SModelSyncPreparationService { ...@@ -16,16 +15,11 @@ class SModelSyncPreparationService {
* *
* @param sModel the model to augment * @param sModel the model to augment
*/ */
def prepareModel(sModel: SModel, modelCfg: ModelConfig): Unit = { def prepareModel(sModel: SModel): Unit = {
val getterSetterVisitor = new GetterSetterGeneratingVisitor val getterSetterVisitor = new GetterSetterGeneratingVisitor
sModel.accept(getterSetterVisitor) sModel.accept(getterSetterVisitor)
val syncNotificationVisitor = new SyncEnhancingVisitor() val syncNotificationVisitor = new SyncEnhancingVisitor()
sModel.accept(syncNotificationVisitor) sModel.accept(syncNotificationVisitor)
if (modelCfg != null) {
val syncUiVisitor = new SyncUiVisitor(modelCfg)
sModel.accept(syncUiVisitor)
}
} }
} }
package org.rosi_project.model_sync.generator package org.rosi_project.model_sync.generator
import org.rosi_project.model_sync.generator.acr_model.SModel import org.rosi_project.model_sync.generator.acr_model.SModel
import org.rosi_project.model_sync.generator.ui.SyncUiVisitor
/** Simple service to add views to an [[SModel]] starting with the complete view for /** Simple service to add all the necessary adaption classes of an [[SModel]] to make applicable for
* single underlying model. * synchronization user interface.
* *
* @author Christopher Werner * @author Christopher Werner
*/ */
class SModelViewPreparationService { class SModelSyncUiPreparationService {
/** Augments a [[SModel]] with the necessary methods and statements to make it usable in a /** Add UI provider functionality too a [[SModel]] with the necessary methods and statements to make it usable
* single underlying model context. * in the user interface.
* *
* @param sModel the model to augment * @param sModel the model to augment
*/ */
def prepareModel(sModel: SModel, modelCfg: ModelConfig): Unit = { def prepareModel(sModel: SModel, modelCfg: ModelConfig): Unit = {
/*val completeViewCompartmentVisitor = new CompleteViewCompartmentGeneratingVisitor if (modelCfg != null) {
val syncUiVisitor = new SyncUiVisitor(modelCfg)
sModel.accept(completeViewCompartmentVisitor)*/ sModel.accept(syncUiVisitor)
}
} }
} }
\ No newline at end of file
...@@ -6,12 +6,13 @@ import org.rosi_project.model_sync.generator.support.Assert ...@@ -6,12 +6,13 @@ import org.rosi_project.model_sync.generator.support.Assert
* *
* @author Christopher Werner * @author Christopher Werner
*/ */
class ComplexSModel(name: String) extends SModel(name) { class ComplexSModel(name: String, sourceName: String) extends SModel(name, sourceName) {
private var modelClasses: Set[SClass] = Set.empty private var modelClasses: Set[SClass] = Set.empty
private var providerClasses: Set[SClass] = Set.empty private var providerClasses: Set[SClass] = Set.empty
private var relationalCompartments: Set[SClass] = Set.empty private var relationalCompartments: Set[SClass] = Set.empty
private var viewCompartments: Set[SClass] = Set.empty private var viewCompartments: Set[SClass] = Set.empty
private var sEnums: Set[SEnum] = Set.empty
/** Provides all model classes in `this` model. */ /** Provides all model classes in `this` model. */
override def getModelClasses: Set[SClass] = modelClasses override def getModelClasses: Set[SClass] = modelClasses
...@@ -28,6 +29,9 @@ class ComplexSModel(name: String) extends SModel(name) { ...@@ -28,6 +29,9 @@ class ComplexSModel(name: String) extends SModel(name) {
/** Provides all the classes in `this` model. */ /** Provides all the classes in `this` model. */
override def getAllClasses: Set[SClass] = modelClasses ++ providerClasses ++ relationalCompartments ++ viewCompartments override def getAllClasses: Set[SClass] = modelClasses ++ providerClasses ++ relationalCompartments ++ viewCompartments
/** Provides all model enums in `this` model. */
def getModelEnums: Set[SEnum] = sEnums
/** Extends the model by a new provder class. /** Extends the model by a new provder class.
* *
* @param mClass the class to add. May never `null`. * @param mClass the class to add. May never `null`.
...@@ -64,6 +68,15 @@ class ComplexSModel(name: String) extends SModel(name) { ...@@ -64,6 +68,15 @@ class ComplexSModel(name: String) extends SModel(name) {
modelClasses += mClass modelClasses += mClass
} }
/** Extends the model by a new enum.
*
* @param mEnum the enum to add. May never `null`.
*/
def addModelEnums(mEnum: SEnum): Unit = {
Assert.notNull(mEnum, "Enum may not be null")
sEnums += mEnum
}
override def accept(visitor: SModelVisitor): Unit = { override def accept(visitor: SModelVisitor): Unit = {
getAllClasses.foreach(_.accept(visitor)) getAllClasses.foreach(_.accept(visitor))
visitor.visit(this) visitor.visit(this)
...@@ -77,10 +90,20 @@ class ComplexSModel(name: String) extends SModel(name) { ...@@ -77,10 +90,20 @@ class ComplexSModel(name: String) extends SModel(name) {
modelClasses == that.modelClasses && modelClasses == that.modelClasses &&
providerClasses == that.providerClasses && providerClasses == that.providerClasses &&
viewCompartments == that.viewCompartments && viewCompartments == that.viewCompartments &&
sEnums == that.sEnums &&
relationalCompartments == that.relationalCompartments relationalCompartments == that.relationalCompartments
case _ => false case _ => false
} }
override def addOtherModel(model: SModel): SModel = {
modelClasses = modelClasses ++ model.getModelClasses
providerClasses = providerClasses ++ model.getProviderClasses
viewCompartments = viewCompartments ++ model.getViewCompartments
relationalCompartments = relationalCompartments ++ model.getRelationalCompartments
sEnums = sEnums ++ model.getModelEnums
return this
}
override def hashCode(): Int = { override def hashCode(): Int = {
val state = Seq(getAllClasses) val state = Seq(getAllClasses)
state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b) state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b)
......
...@@ -3,6 +3,7 @@ package org.rosi_project.model_sync.generator.acr_model ...@@ -3,6 +3,7 @@ package org.rosi_project.model_sync.generator.acr_model
import java.util.Objects 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.SSeq
import org.rosi_project.model_sync.generator.acr_model.types.GenericSequence import org.rosi_project.model_sync.generator.acr_model.types.GenericSequence
import org.rosi_project.model_sync.generator.acr_model.types.PredefTypes
/** Representation of Scala classes. Attributes, methods, etc. have their own wrappers which should /** Representation of Scala classes. Attributes, methods, etc. have their own wrappers which should
* be used to modify these individual parts of the class. * be used to modify these individual parts of the class.
...@@ -95,7 +96,7 @@ class SClass(_name: String, ...@@ -95,7 +96,7 @@ class SClass(_name: String,
} else { } else {
methods :+ new SMethod( methods :+ new SMethod(
name = "toString", name = "toString",
result = SType.String, result = PredefTypes.String,
params = Seq.empty, params = Seq.empty,
implementation = Seq(SMethodStatement((List(s""" "${getName}: " """) ++ getOnlyDeepAttributes.map(attr => s""" "${attr.getName}=" + ${attr.getName} + " " """)).mkString(" + "))), implementation = Seq(SMethodStatement((List(s""" "${getName}: " """) ++ getOnlyDeepAttributes.map(attr => s""" "${attr.getName}=" + ${attr.getName} + " " """)).mkString(" + "))),
overrides = true overrides = true
...@@ -148,8 +149,7 @@ class SClass(_name: String, ...@@ -148,8 +149,7 @@ class SClass(_name: String,
if (parentClass == null) { if (parentClass == null) {
parentClass = parent parentClass = parent
} else { } else {
//TODO: print error message here //print error message here
//println("Parent: " + parentClass + " NewParent: " + parent)
println("!!!Cannot add parent because their is one parent that is no interface!!!") println("!!!Cannot add parent because their is one parent that is no interface!!!")
} }
} }
...@@ -185,8 +185,7 @@ class SClass(_name: String, ...@@ -185,8 +185,7 @@ class SClass(_name: String,
} }
} }
/** Provides code that should be executed when invoking the constructor. /** Provides code that should be executed when invoking the constructor. */
*/
def getAdditionalConstructorStatements: Seq[SMethodStatement] = constructorStatements def getAdditionalConstructorStatements: Seq[SMethodStatement] = constructorStatements
/** Checks, whether `this` extends any other classes. If this is the case, it is '''not''' /** Checks, whether `this` extends any other classes. If this is the case, it is '''not'''
...@@ -210,9 +209,23 @@ class SClass(_name: String, ...@@ -210,9 +209,23 @@ class SClass(_name: String,
constructorStatements = constructorStatements :+ statement 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. */ /** Provides all types `this` classes accesses in some way. */
def getUsedTypes: Set[STypedElement] = { def getUsedTypes: Set[STypedElement] = {
//parent constructor parameter types //iterate over construction features of parent types
val parentConstructorParamImports: Seq[STypedElement] = if (isRootClass) List() else getClassParent match { val parentConstructorParamImports: Seq[STypedElement] = if (isRootClass) List() else getClassParent match {
case parent: SClass => case parent: SClass =>
parent.getDeepStructuralFeatures.map(_.getTypeElement) parent.getDeepStructuralFeatures.map(_.getTypeElement)
...@@ -256,66 +269,52 @@ class SClass(_name: String, ...@@ -256,66 +269,52 @@ class SClass(_name: String,
allCleanImports.toSet allCleanImports.toSet
} }
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
override def getNecessaryImports: Set[SImport] = { override def getNecessaryImports: Set[SImport] = {
var allImports: List[SImport] = List.empty var allImports: List[SImport] = List.empty
//iterate over all parent types //iterate over all parent types
getAllParents().foreach(p => { getAllParents().foreach(p => {
allImports = includeImportIfNecessary(p.sPackage, p.getName, allImports) allImports = includeImportIfNecessary(p, allImports)
}) })
//iterate over construction features of parent types //iterate over construction features of parent types
if (!isRootClass) { if (!isRootClass) {
getClassParent match { getClassParent match {
case parent: SClass => case parent: SClass =>
parent.getStructuralFeatures.foreach(p => { parent.getDeepStructuralFeatures.foreach(p => {
allImports = includeImportIfNecessary(p.getTypeElement.getPackage, p.getTypeElement.getName, allImports) allImports = includeImportIfNecessary(p.getTypeElement, allImports)
}) })
case _ => List() case _ =>
} }
} }
//iterate over all attributes //iterate over all attributes
attributes.foreach(a => { attributes.foreach(a => {
allImports = includeImportIfNecessary(a.getTypeElement.getPackage, a.getTypeElement.getName, allImports) allImports = includeImportIfNecessary(a.getTypeElement, allImports)
}) })
//iterate over all references //iterate over all references
references.foreach(r => { references.foreach(r => {
allImports = includeImportIfNecessary(r.getTypeElement.getPackage, r.getTypeElement.getName, allImports) allImports = includeImportIfNecessary(r.getTypeElement, allImports)
}) })
//iterated over all methods //iterated over all methods
methods.foreach(m => { methods.foreach(m => {
//iterate over result types //iterate over result types
allImports = includeImportIfNecessary(m.result.getPackage, m.result.getName, allImports) allImports = includeImportIfNecessary(m.result, allImports)
//iterate over parameter types //iterate over parameter types
m.params.foreach(p => { m.params.foreach(p => {
allImports = includeImportIfNecessary(p.getType.getPackage, p.getType.getName, allImports) allImports = includeImportIfNecessary(p.getType, allImports)
}) })
//iterate over used types in the method //iterate over used types in the method
m.getUsedTypes.foreach(t => { m.getUsedTypes.foreach(t => {
allImports = includeImportIfNecessary(t.getPackage, t.getName, allImports) allImports = includeImportIfNecessary(t, allImports)
}) })
}) })
//iterate over all construction statements //iterate over all construction statements
constructorStatements.foreach(s => { constructorStatements.foreach(s => {
s.usedTypes.foreach(t => { s.usedTypes.foreach(t => {
allImports = includeImportIfNecessary(t.getPackage, t.getName, allImports) allImports = includeImportIfNecessary(t, allImports)
}) })
}) })
...@@ -340,9 +339,16 @@ class SClass(_name: String, ...@@ -340,9 +339,16 @@ class SClass(_name: String,
* @return an empty list if the class does not need to be imported, or the necessary import * @return an empty list if the class does not need to be imported, or the necessary import
* otherwise * otherwise
*/ */
private def includeImportIfNecessary(sPackage: String, sClass: String, list: List[SImport]): List[SImport] = { private def includeImportIfNecessary(sTypeElement: STypedElement, list: List[SImport]): List[SImport] = {
//TODO: normally we must somehow catch SList and SSeq to get the internal types //catch GenericSequence types and there use internal type param
if (sPackage != this.sPackage && sPackage != "") list :+ SImport(sPackage, sClass) else list 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 { override def equals(other: Any): Boolean = other match {
......
package org.rosi_project.model_sync.generator.acr_model
class SEnum (_name: String, _sPackage: String, val enums: Set[String]) extends STypedElement(_name, _sPackage, false) {
override def getDeepName: String = _name + ".Value"
override def accept(visitor: SModelVisitor): Unit = {
//pass never change an incoming enum
}
}
\ No newline at end of file
package org.rosi_project.model_sync.generator.acr_model package org.rosi_project.model_sync.generator.acr_model
import java.util.Objects 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? // TODO use a simple DSL to represent the method body?
...@@ -56,7 +57,7 @@ class SMethod(name: String, ...@@ -56,7 +57,7 @@ class SMethod(name: String,
def getUsedTypes: Set[STypedElement] = { def getUsedTypes: Set[STypedElement] = {
val resultType = result match { val resultType = result match {
case GenericSType(_, _, typeParam) => Seq(result, typeParam) case GenericSType(_, _, typeParam) => Seq(result, typeParam)
case SType.Unit => Seq.empty case PredefTypes.Unit => Seq.empty
case _ => Seq(result) case _ => Seq(result)
} }
val paramTypes = params.map(_.getType) val paramTypes = params.map(_.getType)
......
...@@ -5,7 +5,10 @@ package org.rosi_project.model_sync.generator.acr_model ...@@ -5,7 +5,10 @@ package org.rosi_project.model_sync.generator.acr_model
* *
* @author Rico Bergmann * @author Rico Bergmann
*/ */
abstract class SModel(private val name: String) extends SModelElement { abstract class SModel(private val name: String, private val sourceName: String) extends SModelElement {
/** Get source name from the model. */
def getSourceName: String = sourceName
/** Get the name from the model. */ /** Get the name from the model. */
def getName: String = name def getName: String = name
...@@ -25,6 +28,9 @@ abstract class SModel(private val name: String) extends SModelElement { ...@@ -25,6 +28,9 @@ abstract class SModel(private val name: String) extends SModelElement {
/** Provides all view compartments in `this` model. */ /** Provides all view compartments in `this` model. */
def getViewCompartments: Set[SClass] def getViewCompartments: Set[SClass]
/** Provides all model enums in `this` model. */
def getModelEnums: Set[SEnum]
/** Extends the model by a new provder class. /** Extends the model by a new provder class.
* *
* @param mClass the class to add. May never `null`. * @param mClass the class to add. May never `null`.
...@@ -49,6 +55,17 @@ abstract class SModel(private val name: String) extends SModelElement { ...@@ -49,6 +55,17 @@ abstract class SModel(private val name: String) extends SModelElement {
*/ */
def addModelClass(mClass: SClass): Unit def addModelClass(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" override def toString: String = s"SModel: classes=$getAllClasses"
} }
package org.rosi_project.model_sync.generator.acr_model 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.support.ExtendedString.stringToExtended
import org.rosi_project.model_sync.generator.acr_model.types.PredefTypes
/** Simple representation of a setter method. /** Simple representation of a setter method.
* *
...@@ -8,7 +9,7 @@ import org.rosi_project.model_sync.generator.support.ExtendedString.stringToExte ...@@ -8,7 +9,7 @@ import org.rosi_project.model_sync.generator.support.ExtendedString.stringToExte
*/ */
class SSetter(struc: SStructuralFeature) extends SMethod( class SSetter(struc: SStructuralFeature) extends SMethod(
name = s"set${struc.getName.firstLetterToUpperCase}", name = s"set${struc.getName.firstLetterToUpperCase}",
result = SType.Unit, result = PredefTypes.Unit,
params = Seq(SMethodParameter(struc.getName.head.toString, struc.getTypeElement)), params = Seq(SMethodParameter(struc.getName.head.toString, struc.getTypeElement)),
implementation = Seq(SMethodStatement(content = s"${struc.getName} = ${struc.getName.head}", usedTypes = Set(struc.getTypeElement)))) { implementation = Seq(SMethodStatement(content = s"${struc.getName} = ${struc.getName.head}", usedTypes = Set(struc.getTypeElement)))) {
......
...@@ -17,25 +17,3 @@ case class SType(_name: String, _sPackage: String = "", _isInterface: Boolean = ...@@ -17,25 +17,3 @@ case class SType(_name: String, _sPackage: String = "", _isInterface: Boolean =
override def toString: String = s"ST: $getName($sPackage, $isInterface)" override def toString: String = s"ST: $getName($sPackage, $isInterface)"
} }
/** The companion defines frequently used types.
*/
object SType {
/** The empty type.
*/
val Unit = SType("Unit")
/** Wrapper for `AnyRef`.
*/
val AnyRef = SType("AnyRef")
/** Wrapper for `Any`.
*/
val Any = SType("Any")
/** Wrapper for `String`.
*/
val String = SType("String")
}
...@@ -21,6 +21,7 @@ object STypeRegistry { ...@@ -21,6 +21,7 @@ object STypeRegistry {
PredefTypes.Float, PredefTypes.Float,
PredefTypes.Double, PredefTypes.Double,
PredefTypes.String, PredefTypes.String,
PredefTypes.Date
) )
registeredTypes ++= defaultTypes registeredTypes ++= defaultTypes
......
...@@ -6,9 +6,10 @@ import org.rosi_project.model_sync.generator.support.Assert ...@@ -6,9 +6,10 @@ import org.rosi_project.model_sync.generator.support.Assert
* *
* @author Rico Bergmann * @author Rico Bergmann
*/ */
class SimpleSModel(name: String) extends SModel(name) { class SimpleSModel(name: String, sourceName: String) extends SModel(name, sourceName) {
private var sClasses: Set[SClass] = Set.empty private var sClasses: Set[SClass] = Set.empty
private var sEnums: Set[SEnum] = Set.empty
/** Provides all the classes in `this` model. */ /** Provides all the classes in `this` model. */
override def getAllClasses: Set[SClass] = sClasses override def getAllClasses: Set[SClass] = sClasses
...@@ -25,6 +26,9 @@ class SimpleSModel(name: String) extends SModel(name) { ...@@ -25,6 +26,9 @@ class SimpleSModel(name: String) extends SModel(name) {
/** Provides all view compartments in `this` model. */ /** Provides all view compartments in `this` model. */
override def getViewCompartments: Set[SClass] = sClasses override def getViewCompartments: Set[SClass] = sClasses
/** Provides all model enums in `this` model. */
def getModelEnums: Set[SEnum] = sEnums
/** Extends the model by a new class. /** Extends the model by a new class.
* *
* @param mClass the class to add. May never `null`. * @param mClass the class to add. May never `null`.
...@@ -43,6 +47,15 @@ class SimpleSModel(name: String) extends SModel(name) { ...@@ -43,6 +47,15 @@ class SimpleSModel(name: String) extends SModel(name) {
sClasses += mClass sClasses += mClass
} }
/** Extends the model by a new enum.
*
* @param mEnum the enum to add. May never `null`.
*/
def addModelEnums(mEnum: SEnum): Unit = {
Assert.notNull(mEnum, "Enum may not be null")
sEnums += mEnum
}
/** Extends the model by a new relational compartment. /** Extends the model by a new relational compartment.
* *
* @param mClass the class to add. May never `null`. * @param mClass the class to add. May never `null`.
...@@ -71,10 +84,17 @@ class SimpleSModel(name: String) extends SModel(name) { ...@@ -71,10 +84,17 @@ class SimpleSModel(name: String) extends SModel(name) {
override def equals(other: Any): Boolean = other match { override def equals(other: Any): Boolean = other match {
case that: SimpleSModel => case that: SimpleSModel =>
(that canEqual this) && (that canEqual this) &&
sEnums == that.sEnums &&
sClasses == that.sClasses sClasses == that.sClasses
case _ => false case _ => false
} }
override def addOtherModel(model: SModel): SModel = {
sClasses = sClasses ++ model.getModelClasses
sEnums = sEnums ++ model.getModelEnums
return this
}
override def hashCode(): Int = { override def hashCode(): Int = {
val state = Seq(sClasses) val state = Seq(sClasses)
state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b) state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b)
......
...@@ -41,9 +41,21 @@ object PredefTypes { ...@@ -41,9 +41,21 @@ object PredefTypes {
/** `java.io.File` */ /** `java.io.File` */
val File = SType("File", "java.io") 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") 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]` /** `java.lang.Class[typ]`
* *
* @param typ the type parameter for the class type * @param typ the type parameter for the class type
......
...@@ -13,6 +13,6 @@ trait Converter[S, T] { ...@@ -13,6 +13,6 @@ trait Converter[S, T] {
* @param source the object to convert * @param source the object to convert
* @return the converted object * @return the converted object
*/ */
def convert(source: S): T def convert(source: S, sourceName: String): T
} }
...@@ -11,7 +11,7 @@ import org.rosi_project.model_sync.generator.acr_model.types.SSet ...@@ -11,7 +11,7 @@ import org.rosi_project.model_sync.generator.acr_model.types.SSet
*/ */
class SClassConverter extends Converter[EClass, SClass] { 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 attrs: List[SAttribute] = List.empty
var refs: List[SReference] = List.empty var refs: List[SReference] = List.empty
var pars: List[STypedElement] = List.empty var pars: List[STypedElement] = List.empty
......
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
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, source.getEPackage.getName, strings)
STypeRegistry.addType(createdEnum)
createdEnum
}
}
\ No newline at end of file
...@@ -5,6 +5,7 @@ import org.rosi_project.model_sync.generator.acr_model.{SModel, SType, STypeRegi ...@@ -5,6 +5,7 @@ import org.rosi_project.model_sync.generator.acr_model.{SModel, SType, STypeRegi
import scala.collection.JavaConverters._ import scala.collection.JavaConverters._
import org.rosi_project.model_sync.generator.acr_model.SClass import org.rosi_project.model_sync.generator.acr_model.SClass
import org.eclipse.emf.ecore.EEnum
/** Converter to generate an [[SModel]] from ecore. /** Converter to generate an [[SModel]] from ecore.
* *
...@@ -12,10 +13,10 @@ import org.rosi_project.model_sync.generator.acr_model.SClass ...@@ -12,10 +13,10 @@ import org.rosi_project.model_sync.generator.acr_model.SClass
*/ */
class SModelGenerator extends Converter[EPackage, SModel] { class SModelGenerator extends Converter[EPackage, SModel] {
override def convert(source: EPackage): SModel = { override def convert(source: EPackage, sourceName: String): SModel = {
val packageName = if (source.getName != null) source.getName else "" val packageName = if (source.getName != null) source.getName else ""
var contents = source.eAllContents().asScala var contents = source.eAllContents().asScala
val model = new ComplexSModel(source.getName) val model = new ComplexSModel(source.getName, sourceName)
println("... Converting ecore model") println("... Converting ecore model")
println("First run creates all classes, important for abstract and interface relations") println("First run creates all classes, important for abstract and interface relations")
...@@ -23,6 +24,9 @@ class SModelGenerator extends Converter[EPackage, SModel] { ...@@ -23,6 +24,9 @@ class SModelGenerator extends Converter[EPackage, SModel] {
case ec: EClass => case ec: EClass =>
//println(ec) //println(ec)
STypeRegistry.addType(new SClass(ec.getName, ec.getEPackage.getName, ec.isAbstract, ec.isInterface)) STypeRegistry.addType(new SClass(ec.getName, ec.getEPackage.getName, ec.isAbstract, ec.isInterface))
case ee: EEnum =>
//prinltn(ee)
model.addModelEnums(new SEnumConverter convert (ee, sourceName))
case _ => case _ =>
// we only care about classes. Types will be registered as soon as they are needed as // we only care about classes. Types will be registered as soon as they are needed as
// attributes // attributes
...@@ -32,7 +36,7 @@ class SModelGenerator extends Converter[EPackage, SModel] { ...@@ -32,7 +36,7 @@ class SModelGenerator extends Converter[EPackage, SModel] {
contents.foreach { contents.foreach {
case ec: EClass => case ec: EClass =>
//println(ec) //println(ec)
model.addModelClass(new SClassConverter convert ec) model.addModelClass(new SClassConverter convert (ec, sourceName))
case _ => case _ =>
// we only care about classes. Types will be registered as soon as they are needed as // we only care about classes. Types will be registered as soon as they are needed as
// attributes // attributes
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment