diff --git a/codegen/core/src/main/scala/com/lightbend/akkasls/codegen/ModelBuilder.scala b/codegen/core/src/main/scala/com/lightbend/akkasls/codegen/ModelBuilder.scala index c447810757..5e26c798c3 100644 --- a/codegen/core/src/main/scala/com/lightbend/akkasls/codegen/ModelBuilder.scala +++ b/codegen/core/src/main/scala/com/lightbend/akkasls/codegen/ModelBuilder.scala @@ -77,7 +77,7 @@ object ModelBuilder { state: State) extends Entity(fqn, entityType) { val abstractEntityName = "Abstract" + fqn.name - + val handlerName = fqn.name + "Handler" } /** diff --git a/codegen/scala-gen/src/main/scala/com/akkaserverless/codegen/scalasdk/impl/ValueEntitySourceGenerator.scala b/codegen/scala-gen/src/main/scala/com/akkaserverless/codegen/scalasdk/impl/ValueEntitySourceGenerator.scala index d6c8a4ef4b..4cd99491a4 100644 --- a/codegen/scala-gen/src/main/scala/com/akkaserverless/codegen/scalasdk/impl/ValueEntitySourceGenerator.scala +++ b/codegen/scala-gen/src/main/scala/com/akkaserverless/codegen/scalasdk/impl/ValueEntitySourceGenerator.scala @@ -41,7 +41,8 @@ object ValueEntitySourceGenerator { generatedSources += File( s"$packagePath/${valueEntity.abstractEntityName}.scala", abstractEntity(valueEntity, service)) - //FIXME add Handler and Provider + generatedSources += File(s"$packagePath/${valueEntity.handlerName}.scala", handler(valueEntity, service)) + //FIXME add Provider generatedSources.result() } @@ -86,6 +87,54 @@ object ValueEntitySourceGenerator { |""".stripMargin } + private[codegen] def handler(valueEntity: ModelBuilder.ValueEntity, service: ModelBuilder.EntityService): String = { + val stateType = valueEntity.state.fqn.name + val packageName = valueEntity.fqn.parent.scalaPackage + val valueEntityName = valueEntity.fqn.name + implicit val imports = + generateImports( + Seq(valueEntity.state.fqn) ++ + service.commands.map(_.inputType) ++ + service.commands.map(_.outputType), + valueEntity.fqn.parent.scalaPackage, + otherImports = Seq( + "com.akkaserverless.scalasdk.valueentity.CommandContext", + "com.akkaserverless.scalasdk.valueentity.ValueEntity", + "com.akkaserverless.scalasdk.impl.valueentity.ValueEntityHandler", + "com.akkaserverless.scalasdk.impl.valueentity.ValueEntityHandler.CommandHandlerNotFound"), + packageImports = Seq(service.fqn.parent.scalaPackage), + semi = false) + + val commandCases = service.commands + .map { cmd => + val methodName = cmd.name + val inputType = typeName(cmd.inputType) + s"""|case "$methodName" => + | entity.${lowerFirst(methodName)}(state, command.asInstanceOf[$inputType]) + |""".stripMargin + } + + s"""|package $packageName + | + |$imports + | + |/** + | * A value entity handler that is the glue between the Protobuf service CounterService + | * and the command handler methods in the Counter class. + | */ + |class ${valueEntityName}Handler(entity: ${valueEntityName}) extends ValueEntityHandler[$stateType, ${valueEntityName}](entity) { + | def handleCommand(commandName: String, state: $stateType, command: Any, context: CommandContext): ValueEntity.Effect[_] = { + | commandName match { + | ${Format.indent(commandCases, 6)} + | + | case _ => + | throw new ValueEntityHandler.CommandHandlerNotFound(commandName) + | } + | } + |} + |""".stripMargin + } + def generateImplementationSkeleton( valueEntity: ModelBuilder.ValueEntity, service: ModelBuilder.EntityService): File = { diff --git a/codegen/scala-gen/src/test/scala/com/akkaserverless/codegen/scalasdk/ValueEntitySourceGeneratorSuite.scala b/codegen/scala-gen/src/test/scala/com/akkaserverless/codegen/scalasdk/ValueEntitySourceGeneratorSuite.scala index ef2eb3de7d..1753bda006 100644 --- a/codegen/scala-gen/src/test/scala/com/akkaserverless/codegen/scalasdk/ValueEntitySourceGeneratorSuite.scala +++ b/codegen/scala-gen/src/test/scala/com/akkaserverless/codegen/scalasdk/ValueEntitySourceGeneratorSuite.scala @@ -77,4 +77,38 @@ class ValueEntitySourceGeneratorSuite extends munit.FunSuite { |""".stripMargin) } + test("it can generate a value entity handler implementation") { + val str = handler(testData.valueEntity(domainParent), testData.simpleEntityService(apiParent)) + assertNoDiff( + str, + s"""package com.example.service.domain + | + |import com.akkaserverless.scalasdk.impl.valueentity.ValueEntityHandler + |import com.akkaserverless.scalasdk.impl.valueentity.ValueEntityHandler.CommandHandlerNotFound + |import com.akkaserverless.scalasdk.valueentity.CommandContext + |import com.akkaserverless.scalasdk.valueentity.ValueEntity + |import com.example.service + |import com.external.Empty + | + |/** + | * A value entity handler that is the glue between the Protobuf service CounterService + | * and the command handler methods in the Counter class. + | */ + |class MyValueEntityHandler(entity: MyValueEntity) extends ValueEntityHandler[MyState, MyValueEntity](entity) { + | def handleCommand(commandName: String, state: MyState, command: Any, context: CommandContext): ValueEntity.Effect[_] = { + | commandName match { + | case "Set" => + | entity.set(state, command.asInstanceOf[service.SetValue]) + | + | case "Get" => + | entity.get(state, command.asInstanceOf[service.GetValue]) + | + | case _ => + | throw new ValueEntityHandler.CommandHandlerNotFound(commandName) + | } + | } + |} + |""".stripMargin) + } + } diff --git a/sdk/scala-sdk/src/main/scala/com/akkaserverless/scalasdk/impl/valueentity/ValueEntityHandler.scala b/sdk/scala-sdk/src/main/scala/com/akkaserverless/scalasdk/impl/valueentity/ValueEntityHandler.scala index 9ae63beb73..e1265905e7 100644 --- a/sdk/scala-sdk/src/main/scala/com/akkaserverless/scalasdk/impl/valueentity/ValueEntityHandler.scala +++ b/sdk/scala-sdk/src/main/scala/com/akkaserverless/scalasdk/impl/valueentity/ValueEntityHandler.scala @@ -19,6 +19,10 @@ package com.akkaserverless.scalasdk.impl.valueentity import com.akkaserverless.scalasdk.valueentity.CommandContext import com.akkaserverless.scalasdk.valueentity.ValueEntity +object ValueEntityHandler { + final case class CommandHandlerNotFound(commandName: String) extends RuntimeException +} + abstract class ValueEntityHandler[S, E <: ValueEntity[S]](val entity: E) { def handleCommand(commandName: String, state: S, command: Any, context: CommandContext): ValueEntity.Effect[_] }