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

Merge branch 'develop' into 'master'

Publish v0.1

Closes #6, #8, #7, #11, #10, and #5

See merge request !2
parents 3557b6af d859f286
No related branches found
No related tags found
1 merge request!2Publish v0.1
package org.rosi_project.model_sync.generator.sync
import org.rosi_project.model_sync.generator.Model
import org.rosi_project.model_sync.generator.acr_model.{SClass, SMethod, types => acr}
import org.rosi_project.model_sync.generator.support.ExtendedString.stringToExtended
import org.rosi_project.model_sync.provider.ModelSyncProvider
/** Creates implementations of [[ModelSyncProvider]] for models.
*
* @param model the model which should be initialized
* @author Rico Bergmann
*/
class ModelProviderTemplate(model: Model) extends SClass(name = "ModelProvider") {
parent = PredefTypes.ModelProvider
methods = Seq(
new SMethod (
name = "getInitialDisplayableModel",
result = PredefTypes.DisplayableModelForInitialization,
params = Seq.empty,
implementation = s"new Initialized${Model.parseClass(model.primaryClass)._2.firstLetterToUpperCase}"
),
new SMethod (
name = "getDisplayableModelsForIntegration",
result = acr.SSeq(PredefTypes.DisplayableModelForIntegration),
params = Seq.empty,
implementation = "Seq.empty"
)
)
}
package org.rosi_project.model_sync.generator.sync
import org.rosi_project.model_sync.generator.acr_model.{GenericSType, SAttribute, SClass, SImport, SMethod, SMethodParameter, SMethodStatement, SType, STypedElement, types => acr}
import org.rosi_project.model_sync.generator.support.ExtendedString.stringToExtended
import org.rosi_project.model_sync.instances.ModelInstanceModifier
/** Creates implementations of [[ModelInstanceModifier]] for attributes of model classes.
*
* @param modelClass the class which contains the attribute
* @param attribute the attribute for which the modifier should be created
* @author Rico Bergmann
*/
class ModifierTemplate(modelClass: SClass, attribute: SAttribute) extends SClass(name = s"${modelClass.name}${attribute.name.firstLetterToUpperCase}Modifier") {
parent = PredefTypes.ModelInstanceModifier
constructorStatements = constructorStatements :+
SMethodStatement(s"""private val ${ModifierTemplate.MethodAttr} = classOf[${modelClass.getName}].getMethod("set${attribute.name.firstLetterToUpperCase}", classOf[${attribute.getType}])""")
methods = Seq(
new SMethod (
name = "getParameters",
result = acr.SSeq(acr.PredefTypes.Parameter),
params = Seq.empty,
implementation = s"${ModifierTemplate.MethodAttr}.getParameters",
overrides = true
),
new SMethod (
name = "invoke",
result = SType.Unit,
params = Seq(SMethodParameter("instance", SType.AnyRef), SMethodParameter("args", acr.SSeq(SType.AnyRef))),
implementation = s"${ModifierTemplate.MethodAttr}.invoke(instance, args: _*)",
overrides = true
),
new SMethod(
name = "toString",
result = SType.String,
params = Seq.empty,
implementation = s""" "Change ${attribute.name}" """,
overrides = true
)
)
override def getNecessaryImports: Set[SImport] = {
val attrImports = attribute.attrType match {
case gt : GenericSType => SImport.generateImports(gt, gt.typeParam)
case t : STypedElement => SImport.generateImports(t)
}
modelClass.getNecessaryImports ++ super.getNecessaryImports + SImport(modelClass.getPackage, modelClass.getName) ++ attrImports
}
}
object ModifierTemplate {
val MethodAttr = "method"
}
package org.rosi_project.model_sync.generator.sync
import org.rosi_project.model_sync.generator.acr_model.SType
/** Contains a number of types which are used throughout the synchronization.
*
* Equivalent to [[org.rosi_project.model_sync.generator.acr_model.types.PredefTypes]], just for
* the sync types.
*
* @author Rico Bergmann
*/
object PredefTypes {
/** `org.rosi_project.model_sync.provider.DisplayableModel`
*/
val DisplayableModel = SType("DisplayableModel", "org.rosi_project.model_sync.provider")
/** `org.rosi_project.model_sync.provider.DisplayableModelForInitialization`
*/
val DisplayableModelForInitialization = SType("DisplayableModelForInitialization", "org.rosi_project.model_sync.provider")
/** `org.rosi_project.model_sync.provider.DisplayableModelForIntegration`
*/
val DisplayableModelForIntegration = SType("DisplayableModelForIntegration", "org.rosi_project.model_sync.provider")
/** `org.rosi_project.model_sync.provider.ModelSyncProvider`
*/
val ModelProvider = SType("ModelSyncProvider", "org.rosi_project.model_sync.provider")
/** `org.rosi_project.model_sync.provider.ModelRegistry`
*/
val ModelRegistry = SType("ModelRegistry", "org.rosi_project.model_sync.provider")
/** `org.rosi_project.model_sync.provider.instances.ModelInstanceConstructor`
*/
val ModelInstanceConstructor = SType("ModelInstanceConstructor", "org.rosi_project.model_sync.instances")
/** `org.rosi_project.model_sync.provider.instances.ModelInstanceModifier`
*/
val ModelInstanceModifier = SType("ModelInstanceModifier", "org.rosi_project.model_sync.instances")
}
package org.rosi_project.model_sync.generator.sync
import org.rosi_project.model_sync.generator.acr_model.SMethodStatement
/** Contains method statements which are used for throughout the synchronization.
*
* @see [[SMethodStatement]]
*
* @author Rico Bergmann
*/
object Statements {
val ModelRegistration = SMethodStatement("ModelRegistry.registerNewModel(this)", Set(PredefTypes.ModelRegistry))
}
package org.rosi_project.model_sync.generator.sync
import org.rosi_project.model_sync.generator.ModelConfig
import org.rosi_project.model_sync.generator.acr_model._
import org.rosi_project.model_sync.sync.PlayerSync
import org.rosi_project.model_sync.sync.ISynchronizationCompartment
/** Augments [[SClass SClasses]] with the necessary method calls to make it usable in a
* synchronization context.
*
* The following modifications are performed:
* - the class (or its furthest parent) becomes a subclass of [[PlayerSync]]
* - [[PlayerSync.buildClass()]] will be called in the constructor
* - each setter will notify the synchronization context about the change
*
* @see [[ISynchronizationCompartment]]
* @author Rico Bergmann
*/
class SyncEnhancingVisitor(val modelCfg: ModelConfig) extends SModelVisitor {
private var additionalSyncClasses: Seq[SClass] = Seq.empty
override def visit(sModel: SModel): Unit = {
additionalSyncClasses.foreach(sModel.addModelClass)
modelCfg.init.nested.foreach(_.foreach(model => sModel.addModelClass(new InitialModelTemplate(model))))
sModel.addModelClass(new InitialModelTemplate(modelCfg.init))
sModel.addModelClass(new ModelProviderTemplate(modelCfg.init))
}
override def visit(sClass: SClass): Unit = {
sClass.getInheritanceHierarchy.reverse.headOption.foreach{
case root: SClass => root.setParent(SyncEnhancingVisitor.PLAYER_SYNC_STYPE)
case tp => sys.error(s"May not enhance $tp as it is a type and not a class")
}
sClass.augmentConstructor(SyncEnhancingVisitor.PLAYER_SYNC_INIT)
additionalSyncClasses = additionalSyncClasses :+ new ConstructorTemplate(sClass)
sClass.attributes.foreach(attr => {
additionalSyncClasses = additionalSyncClasses :+ new ModifierTemplate(sClass, attr)
})
}
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
}
/** Tries to get the attribute's name from a setter method.
*
* A ''valid'' setter will have the following signature: `setXyz(x: T): Unit` (the parameter's
* name does not matter).
*
* Mind that the first letter will be left uppercase (i.e. `Xyz` will be returned although the
* actual attribute may be `xyz`)
*
* @param sMethod the method to analyze. May be any method (not necessarily a setter) but never
* `null`.
* @return the attribute's name if `sMethod` was a valid setter. '''The first letter will be left
* uppercase.'''
*/
private def extractSetterAttr(sMethod: SMethod): Option[String] = {
sMethod.name match {
case SyncEnhancingVisitor.Setter(attrName) =>
Option(attrName)
case _ =>
None
}
}
}
/** The companion contains some static values.
*/
object SyncEnhancingVisitor {
private val Setter = """set([A-Z][a-zA-z0-9]*)""".r
private val PLAYER_SYNC_CLASS = classOf[PlayerSync]
private val PLAYER_SYNC_STYPE = SType(PLAYER_SYNC_CLASS.getSimpleName, PLAYER_SYNC_CLASS.getPackage.getName)
private val PLAYER_SYNC_INIT = SMethodStatement("buildClass()")
}
package org.rosi_project.model_sync.generator
import org.rosi_project.model_sync.generator.acr_model.{SMethodStatement, SModel}
/** Contains services to adapt a [[SModel]] for usage in a ''Synchronization context''.
*
* @author Rico Bergmann
*/
package object sync {
val RES_PATH = "res/"
implicit def t2SeqT[T](t: T): Seq[T] = Seq(t)
implicit def string2SeqMethodImpl(impl: String): Seq[SMethodStatement] = Seq(SMethodStatement(impl))
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment