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[_]
}