diff --git a/baas-node-client/src/main/scala/com/ing/baker/baas/javadsl/BakerClient.scala b/baas-node-client/src/main/scala/com/ing/baker/baas/javadsl/BakerClient.scala
new file mode 100644
index 000000000..eab67fe02
--- /dev/null
+++ b/baas-node-client/src/main/scala/com/ing/baker/baas/javadsl/BakerClient.scala
@@ -0,0 +1,13 @@
+package com.ing.baker.baas.javadsl
+
+import akka.actor.ActorSystem
+import akka.stream.Materializer
+import com.ing.baker.baas.scaladsl.{BakerClient => ScalaRemoteBaker}
+import com.ing.baker.runtime.javadsl.{Baker => JavaBaker}
+import com.ing.baker.runtime.serialization.Encryption
+
+object BakerClient {
+
+ def build(hostname: String, actorSystem: ActorSystem, mat: Materializer, encryption: Encryption = Encryption.NoEncryption): JavaBaker =
+ new JavaBaker(ScalaRemoteBaker.build(hostname, encryption)(actorSystem, mat))
+}
diff --git a/baas-node-client/src/main/scala/com/ing/baker/baas/scaladsl/BakerClient.scala b/baas-node-client/src/main/scala/com/ing/baker/baas/scaladsl/BakerClient.scala
new file mode 100644
index 000000000..be2194fb0
--- /dev/null
+++ b/baas-node-client/src/main/scala/com/ing/baker/baas/scaladsl/BakerClient.scala
@@ -0,0 +1,337 @@
+package com.ing.baker.baas.scaladsl
+
+import akka.actor.ActorSystem
+import akka.http.scaladsl.Http
+import akka.http.scaladsl.marshalling.Marshal
+import akka.http.scaladsl.model.Uri.Path
+import akka.http.scaladsl.model.{HttpMethods, HttpRequest, MessageEntity, Uri}
+import akka.stream.Materializer
+import com.ing.baker.baas.protocol.BaaSProtocol
+import com.ing.baker.baas.protocol.BaaSProto._
+import com.ing.baker.baas.protocol.MarshallingUtils._
+import com.ing.baker.il.{CompiledRecipe, RecipeVisualStyle}
+import com.ing.baker.runtime.common.SensoryEventStatus
+import com.ing.baker.runtime.scaladsl.{BakerEvent, EventInstance, EventMoment, EventResolutions, InteractionInstance, RecipeEventMetadata, RecipeInformation, RecipeInstanceMetadata, RecipeInstanceState, SensoryEventResult, Baker => ScalaBaker}
+import com.ing.baker.runtime.serialization.{Encryption, SerializersProvider}
+import com.ing.baker.types.Value
+
+import scala.concurrent.Future
+
+object BakerClient {
+
+ def build(hostname: String, encryption: Encryption = Encryption.NoEncryption)(implicit system: ActorSystem, mat: Materializer) =
+ BakerClient(Uri(hostname), encryption)
+}
+
+case class BakerClient(hostname: Uri, encryption: Encryption = Encryption.NoEncryption)(implicit system: ActorSystem, mat: Materializer) extends ScalaBaker {
+
+ import system.dispatcher
+
+ implicit val serializersProvider: SerializersProvider =
+ SerializersProvider(system, encryption)
+
+ val root: Path = Path./("api")./("v3")
+
+ def withPath(path: Path): Uri = hostname.withPath(path)
+
+ /**
+ * Adds a recipe to baker and returns a recipeId for the recipe.
+ *
+ * This function is idempotent, if the same (equal) recipe was added earlier this will return the same recipeId
+ *
+ * @param compiledRecipe The compiled recipe.
+ * @return A recipeId
+ */
+ override def addRecipe(compiledRecipe: CompiledRecipe): Future[String] =
+ for {
+ encoded <- Marshal(BaaSProtocol.AddRecipeRequest(compiledRecipe)).to[MessageEntity]
+ request = HttpRequest(method = HttpMethods.POST, uri = withPath(root./("addRecipe")), entity = encoded)
+ response <- Http().singleRequest(request)
+ decoded <- unmarshal[BaaSProtocol.AddRecipeResponse](response).withBakerExceptions
+ } yield decoded.recipeId
+
+ /**
+ * Returns the recipe information for the given RecipeId
+ *
+ * @param recipeId
+ * @return
+ */
+ override def getRecipe(recipeId: String): Future[RecipeInformation] =
+ for {
+ encoded <- Marshal(BaaSProtocol.GetRecipeRequest(recipeId)).to[MessageEntity]
+ request = HttpRequest(method = HttpMethods.POST, uri = withPath(root./("getRecipe")), entity = encoded)
+ response <- Http().singleRequest(request)
+ decoded <- unmarshal[BaaSProtocol.GetRecipeResponse](response).withBakerExceptions
+ } yield decoded.recipeInformation
+
+ /**
+ * Returns all recipes added to this baker instance.
+ *
+ * @return All recipes in the form of map of recipeId -> CompiledRecipe
+ */
+ override def getAllRecipes: Future[Map[String, RecipeInformation]] = {
+ val request = HttpRequest(method = HttpMethods.POST, uri = withPath(root./("getAllRecipes")))
+ for {
+ response <- Http().singleRequest(request)
+ decoded <- unmarshal[BaaSProtocol.GetAllRecipesResponse](response).withBakerExceptions
+ } yield decoded.map
+ }
+
+ /**
+ * Creates a process instance for the given recipeId with the given RecipeInstanceId as identifier
+ *
+ * @param recipeId The recipeId for the recipe to bake
+ * @param recipeInstanceId The identifier for the newly baked process
+ * @return
+ */
+ override def bake(recipeId: String, recipeInstanceId: String): Future[Unit] =
+ for {
+ encoded <- Marshal(BaaSProtocol.BakeRequest(recipeId, recipeInstanceId)).to[MessageEntity]
+ request = HttpRequest(method = HttpMethods.POST, uri = withPath(root./("bake")), entity = encoded)
+ response <- Http().singleRequest(request)
+ _ <- unmarshalBakerExceptions(response)
+ } yield ()
+
+ /**
+ * Notifies Baker that an event has happened and waits until the event was accepted but not executed by the process.
+ *
+ * Possible failures:
+ * `NoSuchProcessException` -> When no process exists for the given id
+ * `ProcessDeletedException` -> If the process is already deleted
+ *
+ * @param recipeInstanceId The process identifier
+ * @param event The event object
+ * @param correlationId Id used to ensure the process instance handles unique events
+ */
+ override def fireEventAndResolveWhenReceived(recipeInstanceId: String, event: EventInstance, correlationId: Option[String]): Future[SensoryEventStatus] =
+ for {
+ encoded <- Marshal(BaaSProtocol.FireEventAndResolveWhenReceivedRequest(recipeInstanceId, event, correlationId)).to[MessageEntity]
+ request = HttpRequest(method = HttpMethods.POST, uri = withPath(root./("fireEventAndResolveWhenReceived")), entity = encoded)
+ response <- Http().singleRequest(request)
+ decoded <- unmarshal[BaaSProtocol.FireEventAndResolveWhenReceivedResponse](response).withBakerExceptions
+ } yield decoded.sensoryEventStatus
+
+ /**
+ * Notifies Baker that an event has happened and waits until all the actions which depend on this event are executed.
+ *
+ * Possible failures:
+ * `NoSuchProcessException` -> When no process exists for the given id
+ * `ProcessDeletedException` -> If the process is already deleted
+ *
+ * @param recipeInstanceId The process identifier
+ * @param event The event object
+ * @param correlationId Id used to ensure the process instance handles unique events
+ */
+ override def fireEventAndResolveWhenCompleted(recipeInstanceId: String, event: EventInstance, correlationId: Option[String]): Future[SensoryEventResult] =
+ for {
+ encoded <- Marshal(BaaSProtocol.FireEventAndResolveWhenCompletedRequest(recipeInstanceId, event, correlationId)).to[MessageEntity]
+ request = HttpRequest(method = HttpMethods.POST, uri = withPath(root./("fireEventAndResolveWhenCompleted")), entity = encoded)
+ response <- Http().singleRequest(request)
+ decoded <- unmarshal[BaaSProtocol.FireEventAndResolveWhenCompletedResponse](response).withBakerExceptions
+ } yield decoded.sensoryEventResult
+
+ /**
+ * Notifies Baker that an event has happened and waits until an specific event has executed.
+ *
+ * Possible failures:
+ * `NoSuchProcessException` -> When no process exists for the given id
+ * `ProcessDeletedException` -> If the process is already deleted
+ *
+ * @param recipeInstanceId The process identifier
+ * @param event The event object
+ * @param onEvent The name of the event to wait for
+ * @param correlationId Id used to ensure the process instance handles unique events
+ */
+ override def fireEventAndResolveOnEvent(recipeInstanceId: String, event: EventInstance, onEvent: String, correlationId: Option[String]): Future[SensoryEventResult] =
+ for {
+ encoded <- Marshal(BaaSProtocol.FireEventAndResolveOnEventRequest(recipeInstanceId, event, onEvent, correlationId)).to[MessageEntity]
+ request = HttpRequest(method = HttpMethods.POST, uri = withPath(root./("fireEventAndResolveOnEvent")), entity = encoded)
+ response <- Http().singleRequest(request)
+ decoded <- unmarshal[BaaSProtocol.FireEventAndResolveOnEventResponse](response).withBakerExceptions
+ } yield decoded.sensoryEventResult
+
+ /**
+ * Notifies Baker that an event has happened and provides 2 async handlers, one for when the event was accepted by
+ * the process, and another for when the event was fully executed by the process.
+ *
+ * Possible failures:
+ * `NoSuchProcessException` -> When no process exists for the given id
+ * `ProcessDeletedException` -> If the process is already deleted
+ *
+ * @param recipeInstanceId The process identifier
+ * @param event The event object
+ * @param correlationId Id used to ensure the process instance handles unique events
+ */
+ override def fireEvent(recipeInstanceId: String, event: EventInstance, correlationId: Option[String]): EventResolutions = {
+ for {
+ encoded <- Marshal(BaaSProtocol.FireEventRequest(recipeInstanceId, event, correlationId)).to[MessageEntity]
+ request = HttpRequest(method = HttpMethods.POST, uri = withPath(root./("fireEvent")), entity = encoded)
+ response <- Http().singleRequest(request)
+ //decoded <- unmarshal(response)[BaaSProtocol.???] TODO f.withBakerExceptionsigure out what to do on this situation with the two futures
+ } yield () //decoded.recipeInformation
+ ???
+ }
+
+ /**
+ * Returns an index of all running processes.
+ *
+ * Can potentially return a partial index when baker runs in cluster mode
+ * and not all shards can be reached within the given timeout.
+ *
+ * Does not include deleted processes.
+ *
+ * @return An index of all processes
+ */
+ override def getAllRecipeInstancesMetadata: Future[Set[RecipeInstanceMetadata]] = {
+ val request = HttpRequest(method = HttpMethods.POST, uri = withPath(root./("getAllRecipeInstancesMetadata")))
+ for {
+ response <- Http().singleRequest(request)
+ decoded <- unmarshal[BaaSProtocol.GetAllRecipeInstancesMetadataResponse](response).withBakerExceptions
+ } yield decoded.set
+ }
+
+ /**
+ * Returns the process state.
+ *
+ * @param recipeInstanceId The process identifier
+ * @return The process state.
+ */
+ override def getRecipeInstanceState(recipeInstanceId: String): Future[RecipeInstanceState] =
+ for {
+ encoded <- Marshal(BaaSProtocol.GetRecipeInstanceStateRequest(recipeInstanceId)).to[MessageEntity]
+ request = HttpRequest(method = HttpMethods.POST, uri = withPath(root./("getRecipeInstanceState")), entity = encoded)
+ response <- Http().singleRequest(request)
+ decoded <- unmarshal[BaaSProtocol.GetRecipeInstanceStateResponse](response).withBakerExceptions
+ } yield decoded.recipeInstanceState
+
+ /**
+ * Returns all provided ingredients for a given RecipeInstance id.
+ *
+ * @param recipeInstanceId The process id.
+ * @return The provided ingredients.
+ */
+ override def getIngredients(recipeInstanceId: String): Future[Map[String, Value]] =
+ getRecipeInstanceState(recipeInstanceId).map(_.ingredients)
+
+ /**
+ * Returns all fired events for a given RecipeInstance id.
+ *
+ * @param recipeInstanceId The process id.
+ * @return The events
+ */
+ override def getEvents(recipeInstanceId: String): Future[Seq[EventMoment]] =
+ getRecipeInstanceState(recipeInstanceId).map(_.events)
+
+ /**
+ * Returns all names of fired events for a given RecipeInstance id.
+ *
+ * @param recipeInstanceId The process id.
+ * @return The event names
+ */
+ override def getEventNames(recipeInstanceId: String): Future[Seq[String]] =
+ getRecipeInstanceState(recipeInstanceId).map(_.events.map(_.name))
+
+ /**
+ * Returns the visual state (.dot) for a given process.
+ *
+ * @param recipeInstanceId The process identifier.
+ * @return A visual (.dot) representation of the process state.
+ */
+ override def getVisualState(recipeInstanceId: String, style: RecipeVisualStyle): Future[String] =
+ for {
+ encoded <- Marshal(BaaSProtocol.GetVisualStateRequest(recipeInstanceId)).to[MessageEntity]
+ request = HttpRequest(method = HttpMethods.POST, uri = withPath(root./("getVisualState")), entity = encoded)
+ response <- Http().singleRequest(request)
+ decoded <- unmarshal[BaaSProtocol.GetVisualStateResponse](response).withBakerExceptions
+ } yield decoded.state
+
+ /**
+ * Registers a listener to all runtime events for recipes with the given name run in this baker instance.
+ *
+ * Note that the delivery guarantee is *AT MOST ONCE*. Do not use it for critical functionality
+ */
+ override def registerEventListener(recipeName: String, listenerFunction: (RecipeEventMetadata, EventInstance) => Unit): Future[Unit] =
+ throw new NotImplementedError("registerEventListener is not implemented for client bakers")
+
+ /**
+ * Registers a listener to all runtime events for all recipes that run in this Baker instance.
+ *
+ * Note that the delivery guarantee is *AT MOST ONCE*. Do not use it for critical functionality
+ */
+ override def registerEventListener(listenerFunction: (RecipeEventMetadata, EventInstance) => Unit): Future[Unit] =
+ throw new NotImplementedError("registerEventListener is not implemented for client bakers")
+
+ /**
+ * Registers a listener function that listens to all BakerEvents
+ *
+ * Note that the delivery guarantee is *AT MOST ONCE*. Do not use it for critical functionality
+ *
+ * @param listenerFunction
+ * @return
+ */
+ override def registerBakerEventListener(listenerFunction: BakerEvent => Unit): Future[Unit] =
+ throw new NotImplementedError("registerBakerEventListener is not implemented for client bakers")
+
+ /**
+ * Adds an interaction implementation to baker.
+ *
+ * @param implementation The implementation object
+ */
+ override def addInteractionInstance(implementation: InteractionInstance): Future[Unit] =
+ throw new NotImplementedError("addInteractionInstance is not implemented for client bakers, instances are deployed independently, please view the documentation")
+
+ /**
+ * Adds a sequence of interaction implementation to baker.
+ *
+ * @param implementations The implementation object
+ */
+ override def addInteractionInstances(implementations: Seq[InteractionInstance]): Future[Unit] =
+ throw new NotImplementedError("addInteractionInstances is not implemented for client bakers, instances are deployed independently, please view the documentation")
+
+ /**
+ * Attempts to gracefully shutdown the baker system.
+ */
+ override def gracefulShutdown(): Future[Unit] =
+ system.terminate().map(_ => ())
+
+ /**
+ * Retries a blocked interaction.
+ *
+ * @return
+ */
+ override def retryInteraction(recipeInstanceId: String, interactionName: String): Future[Unit] =
+ for {
+ encoded <- Marshal(BaaSProtocol.RetryInteractionRequest(recipeInstanceId, interactionName)).to[MessageEntity]
+ request = HttpRequest(method = HttpMethods.POST, uri = withPath(root./("retryInteraction")), entity = encoded)
+ response <- Http().singleRequest(request)
+ _ <- unmarshalBakerExceptions(response)
+ } yield ()
+
+ /**
+ * Resolves a blocked interaction by specifying it's output.
+ *
+ * !!! You should provide an event of the original interaction. Event / ingredient renames are done by Baker.
+ *
+ * @return
+ */
+ override def resolveInteraction(recipeInstanceId: String, interactionName: String, event: EventInstance): Future[Unit] =
+ for {
+ encoded <- Marshal(BaaSProtocol.ResolveInteractionRequest(recipeInstanceId, interactionName, event)).to[MessageEntity]
+ request = HttpRequest(method = HttpMethods.POST, uri = withPath(root./("resolveInteraction")), entity = encoded)
+ response <- Http().singleRequest(request)
+ _ <- unmarshalBakerExceptions(response)
+ } yield ()
+
+ /**
+ * Stops the retrying of an interaction.
+ *
+ * @return
+ */
+ override def stopRetryingInteraction(recipeInstanceId: String, interactionName: String): Future[Unit] =
+ for {
+ encoded <- Marshal(BaaSProtocol.StopRetryingInteractionRequest(recipeInstanceId, interactionName)).to[MessageEntity]
+ request = HttpRequest(method = HttpMethods.POST, uri = withPath(root./("stopRetryingInteraction")), entity = encoded)
+ response <- Http().singleRequest(request)
+ _ <- unmarshalBakerExceptions(response)
+ } yield ()
+}
diff --git a/baas-node-event-listener/src/main/scala/com/ing/baker/baas/akka/EventListenerAgent.scala b/baas-node-event-listener/src/main/scala/com/ing/baker/baas/akka/EventListenerAgent.scala
new file mode 100644
index 000000000..6a4080ee2
--- /dev/null
+++ b/baas-node-event-listener/src/main/scala/com/ing/baker/baas/akka/EventListenerAgent.scala
@@ -0,0 +1,36 @@
+package com.ing.baker.baas.akka
+
+import akka.actor.{Actor, ActorRef, Props}
+import akka.cluster.pubsub.{DistributedPubSub, DistributedPubSubMediator}
+import com.ing.baker.baas.protocol.ProtocolDistributedEventPublishing
+import com.ing.baker.runtime.scaladsl.{EventInstance, RecipeEventMetadata}
+
+object EventListenerAgent {
+
+ case object CommitTimeout
+
+ def apply(recipeName: String, listenerFunction: (RecipeEventMetadata, EventInstance) => Unit): Props =
+ Props(new EventListenerAgent(recipeName, listenerFunction))
+}
+
+class EventListenerAgent(recipeName: String, listenerFunction: (RecipeEventMetadata, EventInstance) => Unit) extends Actor {
+
+ val mediator: ActorRef =
+ DistributedPubSub(context.system).mediator
+
+ val eventsTopic: String =
+ ProtocolDistributedEventPublishing.eventsTopic(recipeName)
+
+ def subscribeToEvents(): Unit =
+ mediator ! DistributedPubSubMediator.Subscribe(eventsTopic, self)
+
+ def unsubscribeToEvents(): Unit =
+ mediator ! DistributedPubSubMediator.Unsubscribe(eventsTopic, self)
+
+ subscribeToEvents()
+
+ def receive: Receive = {
+ case ProtocolDistributedEventPublishing.Event(recipeEventMetadata, event) =>
+ listenerFunction(recipeEventMetadata, event)
+ }
+}
diff --git a/baas-node-event-listener/src/main/scala/com/ing/baker/baas/common/BaaSEventListener.scala b/baas-node-event-listener/src/main/scala/com/ing/baker/baas/common/BaaSEventListener.scala
new file mode 100644
index 000000000..a3c5beec6
--- /dev/null
+++ b/baas-node-event-listener/src/main/scala/com/ing/baker/baas/common/BaaSEventListener.scala
@@ -0,0 +1,14 @@
+package com.ing.baker.baas.common
+
+import com.ing.baker.runtime.common.{EventInstance, InteractionInstance, RecipeEventMetadata}
+import com.ing.baker.runtime.common.LanguageDataStructures.LanguageApi
+
+trait BaaSEventListener[F[_]] extends LanguageApi { self =>
+
+ type EventInstanceType <: EventInstance { type Language <: self.Language }
+
+ type RecipeEventMetadataType <: RecipeEventMetadata { type Language <: self.Language }
+
+ def registerEventListener(recipeName: String, listenerFunction: language.BiConsumerFunction[RecipeEventMetadataType, EventInstanceType]): F[Unit]
+
+}
diff --git a/baas-node-event-listener/src/main/scala/com/ing/baker/baas/javadsl/BaaSEventListener.scala b/baas-node-event-listener/src/main/scala/com/ing/baker/baas/javadsl/BaaSEventListener.scala
new file mode 100644
index 000000000..698914388
--- /dev/null
+++ b/baas-node-event-listener/src/main/scala/com/ing/baker/baas/javadsl/BaaSEventListener.scala
@@ -0,0 +1,22 @@
+package com.ing.baker.baas.javadsl
+
+import java.util.concurrent.CompletableFuture
+import java.util.function.BiConsumer
+
+import akka.actor.ActorSystem
+import com.ing.baker.baas.common
+import com.ing.baker.baas.scaladsl
+import com.ing.baker.runtime.common.LanguageDataStructures.JavaApi
+import com.ing.baker.runtime.javadsl.{EventInstance, RecipeEventMetadata}
+
+import scala.compat.java8.FutureConverters
+
+class BaaSEventListener(actorSystem: ActorSystem) extends common.BaaSEventListener[CompletableFuture] with JavaApi {
+
+ override type EventInstanceType = EventInstance
+
+ override type RecipeEventMetadataType = RecipeEventMetadata
+
+ override def registerEventListener(recipeName: String, listenerFunction: BiConsumer[RecipeEventMetadata, EventInstance]): CompletableFuture[Unit] =
+ FutureConverters.toJava(scaladsl.BaaSEventListener(actorSystem).registerEventListener(recipeName, (metadata, event) => listenerFunction.accept(metadata.asJava, event.asJava))).toCompletableFuture
+}
diff --git a/baas-node-event-listener/src/main/scala/com/ing/baker/baas/scaladsl/BaaSEventListener.scala b/baas-node-event-listener/src/main/scala/com/ing/baker/baas/scaladsl/BaaSEventListener.scala
new file mode 100644
index 000000000..8fdcf65e3
--- /dev/null
+++ b/baas-node-event-listener/src/main/scala/com/ing/baker/baas/scaladsl/BaaSEventListener.scala
@@ -0,0 +1,20 @@
+package com.ing.baker.baas.scaladsl
+
+import akka.actor.ActorSystem
+import com.ing.baker.baas.akka.EventListenerAgent
+import com.ing.baker.baas.common
+import com.ing.baker.runtime.common.LanguageDataStructures.ScalaApi
+import com.ing.baker.runtime.scaladsl.{EventInstance, RecipeEventMetadata}
+
+import scala.concurrent.Future
+
+case class BaaSEventListener(actorSystem: ActorSystem) extends common.BaaSEventListener[Future] with ScalaApi {
+
+ override type EventInstanceType = EventInstance
+
+ override type RecipeEventMetadataType = RecipeEventMetadata
+
+ override def registerEventListener(recipeName: String, listenerFunction: (RecipeEventMetadata, EventInstance) => Unit): Future[Unit] =
+ Future.successful { actorSystem.actorOf(EventListenerAgent(recipeName, listenerFunction)) }
+}
+
diff --git a/baas-node-interaction/src/main/scala/com/ing/baker/baas/akka/InteractionAgent.scala b/baas-node-interaction/src/main/scala/com/ing/baker/baas/akka/InteractionAgent.scala
new file mode 100644
index 000000000..41bc1cb05
--- /dev/null
+++ b/baas-node-interaction/src/main/scala/com/ing/baker/baas/akka/InteractionAgent.scala
@@ -0,0 +1,112 @@
+package com.ing.baker.baas.akka
+
+import java.util.UUID
+
+import akka.actor.{Actor, ActorRef, Props}
+import akka.cluster.pubsub.{DistributedPubSub, DistributedPubSubMediator}
+import com.ing.baker.baas.akka.InteractionAgent.{CommitTimeout, log}
+import com.ing.baker.baas.protocol.{ProtocolInteractionExecution, ProtocolPushPullMatching, ProtocolQuestCommit}
+import com.ing.baker.runtime.scaladsl.{EventInstance, InteractionInstance}
+import org.slf4j.LoggerFactory
+
+import scala.concurrent.duration._
+import scala.concurrent.{ExecutionContext, Future}
+import scala.util.{Failure, Success}
+
+object InteractionAgent {
+
+ case object CommitTimeout
+
+ def apply(instance: InteractionInstance): Props =
+ Props(new InteractionAgent(instance))
+
+ /**
+ * Closes over the agent actor references, just like the pipe pattern does, except it sends a more expressive
+ * message in the case of failure.
+ *
+ * TODO: Handle invalid ingredients scenario
+ *
+ * @param agent actor reference
+ * @param result outcome of invoking the interaction instance
+ * @param ec execution context to use
+ */
+ def pipeBackExecutionResponse(agent: ActorRef, mandated: ActorRef)(result: Future[Option[EventInstance]])(implicit ec: ExecutionContext): Unit = {
+ result.onComplete {
+ case Success(value) =>
+ mandated.tell(ProtocolInteractionExecution.InstanceExecutedSuccessfully(value), agent)
+ case Failure(exception) =>
+ mandated.tell(ProtocolInteractionExecution.InstanceExecutionFailed(), agent)
+ }
+ }
+
+ private val log = LoggerFactory.getLogger(classOf[InteractionAgent])
+}
+
+class InteractionAgent(interaction: InteractionInstance) extends Actor {
+
+ import context.dispatcher
+
+ val mediator: ActorRef = DistributedPubSub(context.system).mediator
+
+ val pullTopic: String =
+ ProtocolPushPullMatching.pullTopic(interaction.name)
+
+ val pushTopic: String =
+ ProtocolPushPullMatching.pushTopic(interaction.name)
+
+ def pull(): Unit =
+ mediator ! DistributedPubSubMediator.Publish(pullTopic, ProtocolPushPullMatching.Pull(self))
+
+ def subscribePush(): Unit =
+ mediator ! DistributedPubSubMediator.Subscribe(pushTopic, self)
+
+ def unsubscribePush(): Unit =
+ mediator ! DistributedPubSubMediator.Unsubscribe(pushTopic, self)
+
+ subscribePush()
+ pull()
+
+ private val timeout: FiniteDuration = 10.seconds
+
+ def receive: Receive = {
+ case ProtocolPushPullMatching.Push(mandated, uuid) =>
+ // start Quest commit protocol
+ log.info(s"${interaction.name}:$uuid: Considering quest from $mandated")
+ mandated ! ProtocolQuestCommit.Considering(self)
+ unsubscribePush()
+ context.system.scheduler.scheduleOnce(timeout, self, CommitTimeout)(context.dispatcher, self)
+ context.become(considering(uuid))
+
+ case ProtocolPushPullMatching.AvailableQuest(mandated, uuid) =>
+ // start Quest commit protocol
+ log.info(s"${interaction.name}:$uuid: Considering quest from $mandated")
+ mandated ! ProtocolQuestCommit.Considering(self)
+ unsubscribePush()
+ context.system.scheduler.scheduleOnce(timeout, self, CommitTimeout)(context.dispatcher, self)
+ context.become(considering(uuid))
+ }
+
+ def considering(uuid: UUID): Receive = {
+ case ProtocolQuestCommit.Commit(mandated, executeMessage) =>
+ log.info(s"${interaction.name}:$uuid: Commited to quest from $mandated")
+ // start the execution protocol by already starting the computation and become committed
+ InteractionAgent.pipeBackExecutionResponse(self, mandated)(interaction.run(executeMessage.input))
+ subscribePush()
+ pull()
+ context.become(receive)
+
+ case ProtocolQuestCommit.QuestTaken =>
+ log.info(s"${interaction.name}:$uuid: Quest taken, starting the protocol again")
+ // quest taIken, start all over again
+ subscribePush()
+ pull()
+ context.become(receive)
+
+ case CommitTimeout =>
+ log.info(s"${interaction.name}:$uuid: not received a response after commit timeout")
+ subscribePush()
+ pull()
+ context.become(receive)
+
+ }
+}
diff --git a/baas-node-interaction/src/main/scala/com/ing/baker/baas/common/BaaSInteractionInstance.scala b/baas-node-interaction/src/main/scala/com/ing/baker/baas/common/BaaSInteractionInstance.scala
new file mode 100644
index 000000000..766dc0686
--- /dev/null
+++ b/baas-node-interaction/src/main/scala/com/ing/baker/baas/common/BaaSInteractionInstance.scala
@@ -0,0 +1,12 @@
+package com.ing.baker.baas.common
+
+import com.ing.baker.runtime.common.InteractionInstance
+import com.ing.baker.runtime.common.LanguageDataStructures.LanguageApi
+
+trait BaaSInteractionInstance[F[_]] extends LanguageApi { self =>
+
+ type InteractionInstanceType <: InteractionInstance[F] { type Language <: self.Language }
+
+ def load(implementation: InteractionInstanceType*): Unit
+
+}
diff --git a/baas-node-interaction/src/main/scala/com/ing/baker/baas/javadsl/BaaSInteractionInstance.scala b/baas-node-interaction/src/main/scala/com/ing/baker/baas/javadsl/BaaSInteractionInstance.scala
new file mode 100644
index 000000000..7d865b7cb
--- /dev/null
+++ b/baas-node-interaction/src/main/scala/com/ing/baker/baas/javadsl/BaaSInteractionInstance.scala
@@ -0,0 +1,17 @@
+package com.ing.baker.baas.javadsl
+
+import java.util.concurrent.CompletableFuture
+
+import akka.actor.ActorSystem
+import com.ing.baker.baas.common
+import com.ing.baker.baas.scaladsl
+import com.ing.baker.runtime.javadsl.InteractionInstance
+import com.ing.baker.runtime.common.LanguageDataStructures.JavaApi
+
+class BaaSInteractionInstance(actorSystem: ActorSystem) extends common.BaaSInteractionInstance[CompletableFuture] with JavaApi {
+
+ override type InteractionInstanceType = InteractionInstance
+
+ override def load(implementation: InteractionInstance*): Unit =
+ scaladsl.BaaSInteractionInstance(actorSystem).load(implementation.map(_.asScala): _*)
+}
diff --git a/baas-node-interaction/src/main/scala/com/ing/baker/baas/scaladsl/BaaSInteractionInstance.scala b/baas-node-interaction/src/main/scala/com/ing/baker/baas/scaladsl/BaaSInteractionInstance.scala
new file mode 100644
index 000000000..fa079e407
--- /dev/null
+++ b/baas-node-interaction/src/main/scala/com/ing/baker/baas/scaladsl/BaaSInteractionInstance.scala
@@ -0,0 +1,20 @@
+package com.ing.baker.baas.scaladsl
+
+import akka.actor.ActorSystem
+import com.ing.baker.baas.akka.InteractionAgent
+import com.ing.baker.baas.common
+import com.ing.baker.runtime.common.LanguageDataStructures.ScalaApi
+import com.ing.baker.runtime.scaladsl.InteractionInstance
+
+import scala.concurrent.Future
+
+case class BaaSInteractionInstance(actorSystem: ActorSystem) extends common.BaaSInteractionInstance[Future] with ScalaApi {
+
+ override type InteractionInstanceType = InteractionInstance
+
+ override def load(implementation: InteractionInstance*): Unit =
+ implementation.foreach { implementation =>
+ actorSystem.actorOf(InteractionAgent(implementation))
+ }
+}
+
diff --git a/baas-node-state/src/main/resources/application.conf b/baas-node-state/src/main/resources/application.conf
new file mode 100644
index 000000000..ecd52f396
--- /dev/null
+++ b/baas-node-state/src/main/resources/application.conf
@@ -0,0 +1,98 @@
+include "baker.conf"
+
+service {
+
+ actorSystemName = "BaaS"
+ actorSystemName = ${?ACTOR_SYSTEM_NAME}
+
+ clusterHost = "127.0.0.1"
+ clusterHost = ${?CLUSTER_HOST}
+
+ clusterPort = 2551
+ clusterPort = ${?CLUSTER_PORT}
+
+ seedHost = "127.0.0.1"
+ seedHost = ${?CLUSTER_SEED_HOST}
+
+ seedPort = 2551
+ seedPort = ${?CLUSTER_SEED_PORT}
+
+ httpServerPort = 8080
+ httpServerPort = ${?HTTP_SERVER_PORT}
+
+ memory-dump-path = "/home/demiourgos728/memdump"
+ memory-dump-path = ${?APP_MEMORY_DUMP_PATH}
+}
+
+baker {
+
+ interaction-manager = "remote"
+
+ actor {
+ provider = "cluster-sharded"
+ idle-timeout = 1 minute
+ }
+}
+
+cassandra-journal.contact-points.0 = "127.0.0.1"
+cassandra-journal.contact-points.0 = ${?CASSANDRA_CONTACT_POINTS_0}
+
+cassandra-snapshot-store.contact-points.0 = "127.0.0.1"
+cassandra-snapshot-store.contact-points.0 = ${?CASSANDRA_CONTACT_POINTS_0}
+
+akka.actor.allow-java-serialization = on
+
+akka {
+
+ actor {
+ provider = "cluster"
+ }
+
+ persistence {
+ # See https://doc.akka.io/docs/akka-persistence-cassandra/current/journal.html#configuration
+ journal.plugin = "cassandra-journal"
+ # See https://doc.akka.io/docs/akka-persistence-cassandra/current/snapshots.html#configuration
+ snapshot-store.plugin = "cassandra-snapshot-store"
+ }
+
+ remote {
+ log-remote-lifecycle-events = off
+ netty.tcp {
+ hostname = ${service.clusterHost}
+ port = ${service.clusterPort}
+ }
+ }
+
+ cluster {
+
+ seed-nodes = [
+ "akka.tcp://"${service.actorSystemName}"@"${service.seedHost}":"${service.seedPort}]
+
+ # auto downing is NOT safe for production deployments.
+ # you may want to use it during development, read more about it in the docs.
+ #
+ # auto-down-unreachable-after = 10s
+ }
+
+ management.http.routes {
+ cluster-management = ""
+ }
+}
+
+kamon.instrumentation.akka.filters {
+
+ actors.track {
+ includes = [ ${service.actorSystemName}"/user/*" ]
+ excludes = []
+ # ${service.actorSystemName}"/system/**", ${service.actorSystemName}"/user/worker-helper"
+ #]
+ }
+
+ dispatchers {
+ includes = [ ${service.actorSystemName}"/akka.actor.default-dispatcher" ]
+ }
+
+ routers {
+ includes = [ ${service.actorSystemName}"/user/*" ]
+ }
+}
diff --git a/baas-node-state/src/main/resources/logback.xml b/baas-node-state/src/main/resources/logback.xml
new file mode 100644
index 000000000..417dc94e9
--- /dev/null
+++ b/baas-node-state/src/main/resources/logback.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+ %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
+
+
+
+
+
\ No newline at end of file
diff --git a/baas-node-state/src/main/scala/com/ing/baker/baas/state/BaaSServer.scala b/baas-node-state/src/main/scala/com/ing/baker/baas/state/BaaSServer.scala
new file mode 100644
index 000000000..b7bc99868
--- /dev/null
+++ b/baas-node-state/src/main/scala/com/ing/baker/baas/state/BaaSServer.scala
@@ -0,0 +1,152 @@
+package com.ing.baker.baas.state
+
+import akka.actor.ActorSystem
+import akka.cluster.pubsub.{DistributedPubSub, DistributedPubSubMediator}
+import akka.http.scaladsl.Http
+import akka.http.scaladsl.model.StatusCodes
+import akka.http.scaladsl.server.Directives._
+import akka.http.scaladsl.server.Route
+import akka.stream.Materializer
+import com.ing.baker.baas.protocol.{BaaSProtocol, ProtocolDistributedEventPublishing}
+import com.ing.baker.baas.protocol.BaaSProto._
+import com.ing.baker.baas.protocol.MarshallingUtils._
+import com.ing.baker.runtime.scaladsl.Baker
+import com.ing.baker.runtime.serialization.{Encryption, SerializersProvider}
+
+import scala.concurrent.{ExecutionContext, Future}
+
+object BaaSServer {
+
+ def run(baker: Baker, host: String, port: Int)(implicit system: ActorSystem, mat: Materializer): Future[Http.ServerBinding] = {
+ import system.dispatcher
+ val encryption = Encryption.NoEncryption
+ val server = new BaaSServer()(system, mat, baker, encryption)
+ for {
+ _ <- initializeEventListeners(baker, system)
+ binding <- Http().bindAndHandle(server.route, host, port)
+ } yield binding
+ }
+
+ private[state] def registerEventListenerForRemote(recipeName: String, baker: Baker, system: ActorSystem): Future[Unit] = {
+ println(Console.YELLOW + s"Event listener for: $recipeName" + Console.RESET)
+ baker.registerEventListener(recipeName, (metadata, event) => {
+ val eventsTopic: String =
+ ProtocolDistributedEventPublishing.eventsTopic(recipeName)
+ DistributedPubSub(system).mediator ! DistributedPubSubMediator.Publish(eventsTopic, ProtocolDistributedEventPublishing.Event(metadata, event))
+ })
+ }
+
+ private[state] def initializeEventListeners(baker: Baker, system: ActorSystem)(implicit ec: ExecutionContext): Future[Unit] =
+ for {
+ recipes <- baker.getAllRecipes
+ _ <- Future.traverse(recipes.toList) { case (_, recipe) => registerEventListenerForRemote(recipe.compiledRecipe.name, baker, system) }
+ } yield ()
+}
+
+class BaaSServer(implicit system: ActorSystem, mat: Materializer, baker: Baker, encryption: Encryption) {
+
+ import system.dispatcher
+
+ implicit private val serializersProvider: SerializersProvider =
+ SerializersProvider(system, encryption)
+
+ def route: Route = concat(pathPrefix("api" / "v3")(concat(health, addRecipe, getRecipe, getAllRecipes, bake,
+ fireEventAndResolveWhenReceived, fireEventAndResolveWhenCompleted, fireEventAndResolveOnEvent, fireEvent,
+ getAllRecipeInstancesMetadata, getRecipeInstanceState, getVisualState, retryInteraction, resolveInteraction,
+ stopRetryingInteraction
+ )))
+
+ private def health: Route = pathPrefix("health")(get(complete(StatusCodes.OK)))
+
+ private def addRecipe: Route = post(path("addRecipe") {
+ entity(as[BaaSProtocol.AddRecipeRequest]) { request =>
+ val result = for {
+ recipeId <- baker.addRecipe(request.compiledRecipe)
+ _ <- BaaSServer.registerEventListenerForRemote(request.compiledRecipe.name, baker, system)
+ } yield BaaSProtocol.AddRecipeResponse(recipeId)
+ completeWithBakerFailures(result)
+ }
+ })
+
+ private def getRecipe: Route = post(path("getRecipe") {
+ entity(as[BaaSProtocol.GetRecipeRequest]) { request =>
+ completeWithBakerFailures(baker.getRecipe(request.recipeId).map(BaaSProtocol.GetRecipeResponse))
+ }
+ })
+
+ private def getAllRecipes: Route = post(path("getAllRecipes") {
+ completeWithBakerFailures(baker.getAllRecipes.map(BaaSProtocol.GetAllRecipesResponse))
+ })
+
+ private def bake: Route = post(path("bake") {
+ entity(as[BaaSProtocol.BakeRequest]) { request =>
+ completeWithBakerFailures(baker.bake(request.recipeId, request.recipeInstanceId))
+ }
+ })
+
+ private def fireEventAndResolveWhenReceived: Route = post(path("fireEventAndResolveWhenReceived") {
+ entity(as[BaaSProtocol.FireEventAndResolveWhenReceivedRequest]) { request =>
+ completeWithBakerFailures(baker.fireEventAndResolveWhenReceived(request.recipeInstanceId, request.event, request.correlationId)
+ .map(BaaSProtocol.FireEventAndResolveWhenReceivedResponse))
+ }
+ })
+
+ private def fireEventAndResolveWhenCompleted: Route = post(path("fireEventAndResolveWhenCompleted") {
+ entity(as[BaaSProtocol.FireEventAndResolveWhenCompletedRequest]) { request =>
+ completeWithBakerFailures(baker.fireEventAndResolveWhenCompleted(request.recipeInstanceId, request.event, request.correlationId)
+ .map(BaaSProtocol.FireEventAndResolveWhenCompletedResponse))
+ }
+ })
+
+ private def fireEventAndResolveOnEvent: Route = post(path("fireEventAndResolveOnEvent") {
+ entity(as[BaaSProtocol.FireEventAndResolveOnEventRequest]) { request =>
+ completeWithBakerFailures(baker.fireEventAndResolveOnEvent(request.recipeInstanceId, request.event, request.onEvent, request.correlationId)
+ .map(BaaSProtocol.FireEventAndResolveOnEventResponse))
+ }
+ })
+
+ private def fireEvent: Route = post(path("fireEvent") {
+ entity(as[BaaSProtocol.FireEventRequest]) { request =>
+ complete(baker.fireEvent(request.recipeInstanceId, request.event, request.correlationId).resolveWhenReceived
+ .map(_ => "TODO")) // TODO figure out what to do here with the 2 different futures
+ }
+ })
+
+ private def getAllRecipeInstancesMetadata: Route = post(path("getAllRecipeInstancesMetadata") {
+ completeWithBakerFailures(baker.getAllRecipeInstancesMetadata
+ .map(BaaSProtocol.GetAllRecipeInstancesMetadataResponse))
+ })
+
+ private def getRecipeInstanceState: Route = post(path("getRecipeInstanceState") {
+ entity(as[BaaSProtocol.GetRecipeInstanceStateRequest]) { request =>
+ completeWithBakerFailures(baker.getRecipeInstanceState(request.recipeInstanceId)
+ .map(BaaSProtocol.GetRecipeInstanceStateResponse))
+ }
+ })
+
+ private def getVisualState: Route = post(path("getVisualState") {
+ entity(as[BaaSProtocol.GetVisualStateRequest]) { request =>
+ completeWithBakerFailures(baker.getVisualState(request.recipeInstanceId)
+ .map(BaaSProtocol.GetVisualStateResponse))
+ }
+ })
+
+ private def retryInteraction: Route = post(path("retryInteraction") {
+ entity(as[BaaSProtocol.RetryInteractionRequest]) { request =>
+ completeWithBakerFailures(baker.retryInteraction(request.recipeInstanceId, request.interactionName))
+ }
+ })
+
+ private def resolveInteraction: Route = post(path("resolveInteraction") {
+ entity(as[BaaSProtocol.ResolveInteractionRequest]) { request =>
+ completeWithBakerFailures(baker.resolveInteraction(request.recipeInstanceId, request.interactionName, request.event))
+ }
+ })
+
+ private def stopRetryingInteraction: Route = post(path("stopRetryingInteraction") {
+ entity(as[BaaSProtocol.StopRetryingInteractionRequest]) { request =>
+ completeWithBakerFailures(baker.stopRetryingInteraction(request.recipeInstanceId, request.interactionName))
+ }
+ })
+
+}
diff --git a/baas-node-state/src/main/scala/com/ing/baker/baas/state/Main.scala b/baas-node-state/src/main/scala/com/ing/baker/baas/state/Main.scala
new file mode 100644
index 000000000..7a85b7aca
--- /dev/null
+++ b/baas-node-state/src/main/scala/com/ing/baker/baas/state/Main.scala
@@ -0,0 +1,30 @@
+package com.ing.baker.baas.state
+
+import akka.actor.ActorSystem
+import akka.stream.ActorMaterializer
+import com.ing.baker.runtime.akka.AkkaBaker
+import com.typesafe.config.ConfigFactory
+
+import scala.concurrent.Await
+import scala.concurrent.duration._
+
+object Main extends App {
+ private val timeout: FiniteDuration = 20.seconds
+
+ println(Console.YELLOW + "Starting State Node..." + Console.RESET)
+
+ val config = ConfigFactory.load()
+ val systemName = config.getString("service.actorSystemName")
+ val httpServerPort = config.getInt("service.httpServerPort")
+ val stateNodeSystem = ActorSystem(systemName)
+ val stateNodeBaker = AkkaBaker(config, stateNodeSystem)
+ val materializer = ActorMaterializer()(stateNodeSystem)
+
+ import stateNodeSystem.dispatcher
+
+ Await.result(BaaSServer.run(stateNodeBaker, "0.0.0.0", httpServerPort)(stateNodeSystem, materializer).map { hook =>
+ println(Console.GREEN + "State Node started..." + Console.RESET)
+ println(hook.localAddress)
+ sys.addShutdownHook(Await.result(hook.unbind(), timeout))
+ }, timeout)
+}
diff --git a/baas-protocol-baker/src/main/protobuf/baas.proto b/baas-protocol-baker/src/main/protobuf/baas.proto
new file mode 100644
index 000000000..e7c263194
--- /dev/null
+++ b/baas-protocol-baker/src/main/protobuf/baas.proto
@@ -0,0 +1,112 @@
+syntax = "proto2";
+
+import "scalapb/scalapb.proto";
+import "common.proto";
+
+option java_package = "com.ing.baker.baas.protocol.protobuf";
+option (scalapb.options) = {
+ flat_package: true
+};
+
+message BaaSRemoteFailure {
+ optional BakerException failure = 1;
+}
+
+message AddRecipeRequest {
+ optional CompiledRecipe compiledRecipe = 1;
+}
+
+message AddRecipeResponse {
+ optional string recipeId = 1;
+}
+
+message GetRecipeRequest {
+ optional string recipeId = 1;
+}
+
+message GetRecipeResponse {
+ optional RecipeInformation recipeInformation = 1;
+}
+
+message GetAllRecipesResponse {
+ map mapping = 1;
+}
+
+message BakeRequest {
+ optional string recipeId = 1;
+ optional string recipeInstanceId = 2;
+}
+
+message FireEventAndResolveWhenReceivedRequest {
+ optional string recipeInstanceId = 1;
+ optional RuntimeEvent event = 2;
+ optional string correlationId = 3;
+}
+
+message FireEventAndResolveWhenReceivedResponse {
+ optional SensoryEventStatus sensoryEventStatus = 1;
+}
+
+message FireEventAndResolveWhenCompletedRequest {
+ optional string recipeInstanceId = 1;
+ optional RuntimeEvent event = 2;
+ optional string correlationId = 3;
+}
+
+message FireEventAndResolveWhenCompletedResponse {
+ optional SensoryEventResult sensoryEventResult = 1;
+}
+
+message FireEventAndResolveOnEventRequest {
+ optional string recipeInstanceId = 1;
+ optional RuntimeEvent event = 2;
+ optional string onEvent = 3;
+ optional string correlationId = 4;
+}
+
+message FireEventAndResolveOnEventResponse {
+ optional SensoryEventResult sensoryEventResult = 1;
+}
+
+message FireEventRequest {
+ optional string recipeInstanceId = 1;
+ optional RuntimeEvent event = 2;
+ optional string correlationId = 3;
+}
+
+message GetAllRecipeInstancesMetadataResponse {
+ repeated RecipeInstanceMetadata set = 1;
+}
+
+message GetRecipeInstanceStateRequest {
+ optional string recipeInstanceId = 1;
+}
+
+message GetRecipeInstanceStateResponse {
+ optional ProcessState recipeInstanceState = 1;
+}
+
+message GetVisualStateRequest {
+ optional string recipeInstanceId = 1;
+}
+
+message GetVisualStateResponse {
+ optional string state = 1;
+}
+
+message RetryInteractionRequest {
+ optional string recipeInstanceId = 1;
+ optional string interactionName = 2;
+}
+
+message ResolveInteractionRequest {
+ optional string recipeInstanceId = 1;
+ optional string interactionName = 2;
+ optional RuntimeEvent event = 3;
+}
+
+message StopRetryingInteractionRequest {
+ optional string recipeInstanceId = 1;
+ optional string interactionName = 2;
+}
+
diff --git a/baas-protocol-baker/src/main/scala/com/ing/baker/baas/protocol/BaaSProto.scala b/baas-protocol-baker/src/main/scala/com/ing/baker/baas/protocol/BaaSProto.scala
new file mode 100644
index 000000000..ceabee45b
--- /dev/null
+++ b/baas-protocol-baker/src/main/scala/com/ing/baker/baas/protocol/BaaSProto.scala
@@ -0,0 +1,363 @@
+package com.ing.baker.baas.protocol
+
+import cats.implicits._
+import com.ing.baker.baas.protocol.BaaSProtocol._
+import com.ing.baker.runtime.serialization.{ProtoMap, SerializersProvider}
+import scalapb.GeneratedMessageCompanion
+import com.ing.baker.runtime.serialization.ProtoMap.{ctxFromProto, ctxToProto, versioned}
+import com.ing.baker.runtime.serialization.protomappings.SensoryEventStatusMappingHelper
+
+import scala.util.Try
+
+object BaaSProto {
+
+ implicit val baaSRemoteFailureProto: ProtoMap[BaaSRemoteFailure, protobuf.BaaSRemoteFailure] =
+ new ProtoMap[BaaSRemoteFailure, protobuf.BaaSRemoteFailure] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.BaaSRemoteFailure] =
+ protobuf.BaaSRemoteFailure
+
+ override def toProto(a: BaaSRemoteFailure): protobuf.BaaSRemoteFailure =
+ protobuf.BaaSRemoteFailure(Some(ctxToProto(a.error)))
+
+ override def fromProto(message: protobuf.BaaSRemoteFailure): Try[BaaSRemoteFailure] =
+ versioned(message.failure, "failure")
+ .flatMap(ctxFromProto(_))
+ .map(BaaSRemoteFailure)
+ }
+
+ implicit def addRecipeRequestProto(implicit ev0: SerializersProvider): ProtoMap[AddRecipeRequest, protobuf.AddRecipeRequest] =
+ new ProtoMap[AddRecipeRequest, protobuf.AddRecipeRequest] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.AddRecipeRequest] =
+ protobuf.AddRecipeRequest
+
+ override def toProto(a: AddRecipeRequest): protobuf.AddRecipeRequest =
+ protobuf.AddRecipeRequest(Some(ctxToProto(a.compiledRecipe)))
+
+ override def fromProto(message: protobuf.AddRecipeRequest): Try[AddRecipeRequest] =
+ versioned(message.compiledRecipe, "compiledRecipe")
+ .flatMap(ctxFromProto(_))
+ .map(AddRecipeRequest)
+ }
+
+ implicit def addRecipeResponseProto: ProtoMap[AddRecipeResponse, protobuf.AddRecipeResponse] =
+ new ProtoMap[AddRecipeResponse, protobuf.AddRecipeResponse] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.AddRecipeResponse] =
+ protobuf.AddRecipeResponse
+
+ override def toProto(a: AddRecipeResponse): protobuf.AddRecipeResponse =
+ protobuf.AddRecipeResponse(Some(a.recipeId))
+
+ override def fromProto(message: protobuf.AddRecipeResponse): Try[AddRecipeResponse] =
+ versioned(message.recipeId, "recipeId")
+ .map(AddRecipeResponse)
+ }
+
+ implicit def getRecipeRequestProto: ProtoMap[GetRecipeRequest, protobuf.GetRecipeRequest] =
+ new ProtoMap[GetRecipeRequest, protobuf.GetRecipeRequest] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.GetRecipeRequest] =
+ protobuf.GetRecipeRequest
+
+ override def toProto(a: GetRecipeRequest): protobuf.GetRecipeRequest =
+ protobuf.GetRecipeRequest(Some(a.recipeId))
+
+ override def fromProto(message: protobuf.GetRecipeRequest): Try[GetRecipeRequest] =
+ versioned(message.recipeId, "recipeId")
+ .map(GetRecipeRequest)
+ }
+
+ implicit def getRecipeResponseProto(implicit ev0: SerializersProvider): ProtoMap[GetRecipeResponse, protobuf.GetRecipeResponse] =
+ new ProtoMap[GetRecipeResponse, protobuf.GetRecipeResponse] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.GetRecipeResponse] =
+ protobuf.GetRecipeResponse
+
+ override def toProto(a: GetRecipeResponse): protobuf.GetRecipeResponse =
+ protobuf.GetRecipeResponse(Some(ctxToProto(a.recipeInformation)))
+
+ override def fromProto(message: protobuf.GetRecipeResponse): Try[GetRecipeResponse] =
+ for {
+ recipeInformationProto <- versioned(message.recipeInformation, "recipeInformation")
+ recipeInformation <- ctxFromProto(recipeInformationProto)
+ } yield GetRecipeResponse(recipeInformation)
+ }
+
+ implicit def getAllRecipesResponseProto(implicit ev0: SerializersProvider): ProtoMap[GetAllRecipesResponse, protobuf.GetAllRecipesResponse] =
+ new ProtoMap[GetAllRecipesResponse, protobuf.GetAllRecipesResponse] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.GetAllRecipesResponse] =
+ protobuf.GetAllRecipesResponse
+
+ override def toProto(a: GetAllRecipesResponse): protobuf.GetAllRecipesResponse =
+ protobuf.GetAllRecipesResponse(a.map.mapValues(ctxToProto(_)))
+
+ override def fromProto(message: protobuf.GetAllRecipesResponse): Try[GetAllRecipesResponse] =
+ for {
+ allRecipes <- message.mapping.toList.traverse { case (id, recipeProto) =>
+ ctxFromProto(recipeProto).map(x => (id, x))
+ }
+ } yield GetAllRecipesResponse(allRecipes.toMap)
+ }
+
+ implicit def bakeRequestProto: ProtoMap[BakeRequest, protobuf.BakeRequest] =
+ new ProtoMap[BakeRequest, protobuf.BakeRequest] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.BakeRequest] =
+ protobuf.BakeRequest
+
+ override def toProto(a: BakeRequest): protobuf.BakeRequest =
+ protobuf.BakeRequest(Some(a.recipeId), Some(a.recipeInstanceId))
+
+ override def fromProto(message: protobuf.BakeRequest): Try[BakeRequest] =
+ for {
+ recipeId <- versioned(message.recipeId, "recipeId")
+ recipeInstanceId <- versioned(message.recipeInstanceId, "recipeInstanceId")
+ } yield BakeRequest(recipeId, recipeInstanceId)
+ }
+
+ implicit def fireEventAndResolveWhenReceivedRequestProto: ProtoMap[FireEventAndResolveWhenReceivedRequest, protobuf.FireEventAndResolveWhenReceivedRequest] =
+ new ProtoMap[FireEventAndResolveWhenReceivedRequest, protobuf.FireEventAndResolveWhenReceivedRequest] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.FireEventAndResolveWhenReceivedRequest] =
+ protobuf.FireEventAndResolveWhenReceivedRequest
+
+ override def toProto(a: FireEventAndResolveWhenReceivedRequest): protobuf.FireEventAndResolveWhenReceivedRequest =
+ protobuf.FireEventAndResolveWhenReceivedRequest(Some(a.recipeInstanceId), Some(ctxToProto(a.event)), a.correlationId)
+
+ override def fromProto(message: protobuf.FireEventAndResolveWhenReceivedRequest): Try[FireEventAndResolveWhenReceivedRequest] =
+ for {
+ recipeInstanceId <- versioned(message.recipeInstanceId, "recipeInstanceId")
+ event <- versioned(message.event, "event")
+ decodedEvent <- ctxFromProto(event)
+ } yield FireEventAndResolveWhenReceivedRequest(recipeInstanceId, decodedEvent, message.correlationId)
+ }
+
+ implicit def fireEventAndResolveWhenReceivedResponseProto: ProtoMap[FireEventAndResolveWhenReceivedResponse, protobuf.FireEventAndResolveWhenReceivedResponse] =
+ new ProtoMap[FireEventAndResolveWhenReceivedResponse, protobuf.FireEventAndResolveWhenReceivedResponse] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.FireEventAndResolveWhenReceivedResponse] =
+ protobuf.FireEventAndResolveWhenReceivedResponse
+
+ override def toProto(a: FireEventAndResolveWhenReceivedResponse): protobuf.FireEventAndResolveWhenReceivedResponse =
+ protobuf.FireEventAndResolveWhenReceivedResponse(Some(SensoryEventStatusMappingHelper.toProto(a.sensoryEventStatus)))
+
+ override def fromProto(message: protobuf.FireEventAndResolveWhenReceivedResponse): Try[FireEventAndResolveWhenReceivedResponse] =
+ for {
+ sensoryEventStatus <- versioned(message.sensoryEventStatus, "sensoryEventStatus")
+ decodedSensoryEventStatus <- SensoryEventStatusMappingHelper.fromProto(sensoryEventStatus)
+ } yield FireEventAndResolveWhenReceivedResponse(decodedSensoryEventStatus)
+ }
+
+ implicit def fireEventAndResolveWhenCompletedRequestProto: ProtoMap[FireEventAndResolveWhenCompletedRequest, protobuf.FireEventAndResolveWhenCompletedRequest] =
+ new ProtoMap[FireEventAndResolveWhenCompletedRequest, protobuf.FireEventAndResolveWhenCompletedRequest] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.FireEventAndResolveWhenCompletedRequest] =
+ protobuf.FireEventAndResolveWhenCompletedRequest
+
+ override def toProto(a: FireEventAndResolveWhenCompletedRequest): protobuf.FireEventAndResolveWhenCompletedRequest =
+ protobuf.FireEventAndResolveWhenCompletedRequest(Some(a.recipeInstanceId), Some(ctxToProto(a.event)), a.correlationId)
+
+ override def fromProto(message: protobuf.FireEventAndResolveWhenCompletedRequest): Try[FireEventAndResolveWhenCompletedRequest] =
+ for {
+ recipeInstanceId <- versioned(message.recipeInstanceId, "recipeInstanceId")
+ event <- versioned(message.event, "event")
+ decodedEvent <- ctxFromProto(event)
+ } yield FireEventAndResolveWhenCompletedRequest(recipeInstanceId, decodedEvent, message.correlationId)
+ }
+
+ implicit def fireEventAndResolveWhenCompletedResponseProto: ProtoMap[FireEventAndResolveWhenCompletedResponse, protobuf.FireEventAndResolveWhenCompletedResponse] =
+ new ProtoMap[FireEventAndResolveWhenCompletedResponse, protobuf.FireEventAndResolveWhenCompletedResponse] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.FireEventAndResolveWhenCompletedResponse] =
+ protobuf.FireEventAndResolveWhenCompletedResponse
+
+ override def toProto(a: FireEventAndResolveWhenCompletedResponse): protobuf.FireEventAndResolveWhenCompletedResponse =
+ protobuf.FireEventAndResolveWhenCompletedResponse(Some(ctxToProto(a.sensoryEventResult)))
+
+ override def fromProto(message: protobuf.FireEventAndResolveWhenCompletedResponse): Try[FireEventAndResolveWhenCompletedResponse] =
+ for {
+ sensoryEventResult <- versioned(message.sensoryEventResult, "sensoryEventResult")
+ decodedSensoryEventResult <- ctxFromProto(sensoryEventResult)
+ } yield FireEventAndResolveWhenCompletedResponse(decodedSensoryEventResult)
+ }
+
+ implicit def fireEventAndResolveOnEventRequestProto: ProtoMap[FireEventAndResolveOnEventRequest, protobuf.FireEventAndResolveOnEventRequest] =
+ new ProtoMap[FireEventAndResolveOnEventRequest, protobuf.FireEventAndResolveOnEventRequest] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.FireEventAndResolveOnEventRequest] =
+ protobuf.FireEventAndResolveOnEventRequest
+
+ override def toProto(a: FireEventAndResolveOnEventRequest): protobuf.FireEventAndResolveOnEventRequest =
+ protobuf.FireEventAndResolveOnEventRequest(Some(a.recipeInstanceId), Some(ctxToProto(a.event)), Some(a.onEvent), a.correlationId)
+
+ override def fromProto(message: protobuf.FireEventAndResolveOnEventRequest): Try[FireEventAndResolveOnEventRequest] =
+ for {
+ recipeInstanceId <- versioned(message.recipeInstanceId, "recipeInstanceId")
+ onEvent <- versioned(message.onEvent, "onEvent")
+ event <- versioned(message.event, "event")
+ decodedEvent <- ctxFromProto(event)
+ } yield FireEventAndResolveOnEventRequest(recipeInstanceId, decodedEvent, onEvent, message.correlationId)
+ }
+
+ implicit def fireEventAndResolveOnEventResponseProto: ProtoMap[FireEventAndResolveOnEventResponse, protobuf.FireEventAndResolveOnEventResponse] =
+ new ProtoMap[FireEventAndResolveOnEventResponse, protobuf.FireEventAndResolveOnEventResponse] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.FireEventAndResolveOnEventResponse] =
+ protobuf.FireEventAndResolveOnEventResponse
+
+ override def toProto(a: FireEventAndResolveOnEventResponse): protobuf.FireEventAndResolveOnEventResponse =
+ protobuf.FireEventAndResolveOnEventResponse(Some(ctxToProto(a.sensoryEventResult)))
+
+ override def fromProto(message: protobuf.FireEventAndResolveOnEventResponse): Try[FireEventAndResolveOnEventResponse] =
+ for {
+ sensoryEventResult <- versioned(message.sensoryEventResult, "sensoryEventResult")
+ decodedSensoryEventResult <- ctxFromProto(sensoryEventResult)
+ } yield FireEventAndResolveOnEventResponse(decodedSensoryEventResult)
+ }
+
+ implicit def fireEventRequestProto: ProtoMap[FireEventRequest, protobuf.FireEventRequest] =
+ new ProtoMap[FireEventRequest, protobuf.FireEventRequest] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.FireEventRequest] =
+ protobuf.FireEventRequest
+
+ override def toProto(a: FireEventRequest): protobuf.FireEventRequest =
+ protobuf.FireEventRequest(Some(a.recipeInstanceId), Some(ctxToProto(a.event)), a.correlationId)
+
+ override def fromProto(message: protobuf.FireEventRequest): Try[FireEventRequest] =
+ for {
+ recipeInstanceId <- versioned(message.recipeInstanceId, "recipeInstanceId")
+ event <- versioned(message.event, "event")
+ decodedEvent <- ctxFromProto(event)
+ } yield FireEventRequest(recipeInstanceId, decodedEvent, message.correlationId)
+ }
+
+ implicit def getAllRecipeInstancesMetadataResponseProto: ProtoMap[GetAllRecipeInstancesMetadataResponse, protobuf.GetAllRecipeInstancesMetadataResponse] =
+ new ProtoMap[GetAllRecipeInstancesMetadataResponse, protobuf.GetAllRecipeInstancesMetadataResponse] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.GetAllRecipeInstancesMetadataResponse] =
+ protobuf.GetAllRecipeInstancesMetadataResponse
+
+ override def toProto(a: GetAllRecipeInstancesMetadataResponse): protobuf.GetAllRecipeInstancesMetadataResponse =
+ protobuf.GetAllRecipeInstancesMetadataResponse(a.set.toSeq.map(ctxToProto(_)))
+
+ override def fromProto(message: protobuf.GetAllRecipeInstancesMetadataResponse): Try[GetAllRecipeInstancesMetadataResponse] =
+ for {
+ set <- message.set.toList.traverse(ctxFromProto(_))
+ } yield GetAllRecipeInstancesMetadataResponse(set.toSet)
+ }
+
+ implicit def getRecipeInstanceStateRequestProto: ProtoMap[GetRecipeInstanceStateRequest, protobuf.GetRecipeInstanceStateRequest] =
+ new ProtoMap[GetRecipeInstanceStateRequest, protobuf.GetRecipeInstanceStateRequest] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.GetRecipeInstanceStateRequest] =
+ protobuf.GetRecipeInstanceStateRequest
+
+ override def toProto(a: GetRecipeInstanceStateRequest): protobuf.GetRecipeInstanceStateRequest =
+ protobuf.GetRecipeInstanceStateRequest(Some(a.recipeInstanceId))
+
+ override def fromProto(message: protobuf.GetRecipeInstanceStateRequest): Try[GetRecipeInstanceStateRequest] =
+ for {
+ recipeInstanceId <- versioned(message.recipeInstanceId, "recipeInstanceId")
+ } yield GetRecipeInstanceStateRequest(recipeInstanceId)
+ }
+
+ implicit def getRecipeInstanceStateResponseProto: ProtoMap[GetRecipeInstanceStateResponse, protobuf.GetRecipeInstanceStateResponse] =
+ new ProtoMap[GetRecipeInstanceStateResponse, protobuf.GetRecipeInstanceStateResponse] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.GetRecipeInstanceStateResponse] =
+ protobuf.GetRecipeInstanceStateResponse
+
+ override def toProto(a: GetRecipeInstanceStateResponse): protobuf.GetRecipeInstanceStateResponse =
+ protobuf.GetRecipeInstanceStateResponse(Some(ctxToProto(a.recipeInstanceState)))
+
+ override def fromProto(message: protobuf.GetRecipeInstanceStateResponse): Try[GetRecipeInstanceStateResponse] =
+ for {
+ recipeInstanceState <- versioned(message.recipeInstanceState, "recipeInstanceState")
+ decodedSensoryEventResult <- ctxFromProto(recipeInstanceState)
+ } yield GetRecipeInstanceStateResponse(decodedSensoryEventResult)
+ }
+
+ implicit def getVisualStateRequestProto: ProtoMap[GetVisualStateRequest, protobuf.GetVisualStateRequest] =
+ new ProtoMap[GetVisualStateRequest, protobuf.GetVisualStateRequest] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.GetVisualStateRequest] =
+ protobuf.GetVisualStateRequest
+
+ override def toProto(a: GetVisualStateRequest): protobuf.GetVisualStateRequest =
+ protobuf.GetVisualStateRequest(Some(a.recipeInstanceId))
+
+ override def fromProto(message: protobuf.GetVisualStateRequest): Try[GetVisualStateRequest] =
+ for {
+ recipeInstanceId <- versioned(message.recipeInstanceId, "recipeInstanceId")
+ } yield GetVisualStateRequest(recipeInstanceId)
+ }
+
+ implicit def getVisualStateResponseProto: ProtoMap[GetVisualStateResponse, protobuf.GetVisualStateResponse] =
+ new ProtoMap[GetVisualStateResponse, protobuf.GetVisualStateResponse] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.GetVisualStateResponse] =
+ protobuf.GetVisualStateResponse
+
+ override def toProto(a: GetVisualStateResponse): protobuf.GetVisualStateResponse =
+ protobuf.GetVisualStateResponse(Some(a.state))
+
+ override def fromProto(message: protobuf.GetVisualStateResponse): Try[GetVisualStateResponse] =
+ for {
+ state <- versioned(message.state, "state")
+ } yield GetVisualStateResponse(state)
+ }
+
+ implicit def retryInteractionRequestProto: ProtoMap[RetryInteractionRequest, protobuf.RetryInteractionRequest] =
+ new ProtoMap[RetryInteractionRequest, protobuf.RetryInteractionRequest] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.RetryInteractionRequest] =
+ protobuf.RetryInteractionRequest
+
+ override def toProto(a: RetryInteractionRequest): protobuf.RetryInteractionRequest =
+ protobuf.RetryInteractionRequest(Some(a.recipeInstanceId), Some(a.interactionName))
+
+ override def fromProto(message: protobuf.RetryInteractionRequest): Try[RetryInteractionRequest] =
+ for {
+ recipeInstanceId <- versioned(message.recipeInstanceId, "recipeInstanceId")
+ interactionName <- versioned(message.interactionName, "interactionName")
+ } yield RetryInteractionRequest(recipeInstanceId, interactionName)
+ }
+
+ implicit def resolveInteractionRequestProto: ProtoMap[ResolveInteractionRequest, protobuf.ResolveInteractionRequest] =
+ new ProtoMap[ResolveInteractionRequest, protobuf.ResolveInteractionRequest] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.ResolveInteractionRequest] =
+ protobuf.ResolveInteractionRequest
+
+ override def toProto(a: ResolveInteractionRequest): protobuf.ResolveInteractionRequest =
+ protobuf.ResolveInteractionRequest(Some(a.recipeInstanceId), Some(a.interactionName), Some(ctxToProto(a.event)))
+
+ override def fromProto(message: protobuf.ResolveInteractionRequest): Try[ResolveInteractionRequest] =
+ for {
+ recipeInstanceId <- versioned(message.recipeInstanceId, "recipeInstanceId")
+ interactionName <- versioned(message.interactionName, "interactionName")
+ event <- versioned(message.event, "event")
+ decodedEvent <- ctxFromProto(event)
+ } yield ResolveInteractionRequest(recipeInstanceId, interactionName, decodedEvent)
+ }
+
+ implicit def stopRetryingInteractionRequestProto: ProtoMap[StopRetryingInteractionRequest, protobuf.StopRetryingInteractionRequest] =
+ new ProtoMap[StopRetryingInteractionRequest, protobuf.StopRetryingInteractionRequest] {
+
+ override def companion: GeneratedMessageCompanion[protobuf.StopRetryingInteractionRequest] =
+ protobuf.StopRetryingInteractionRequest
+
+ override def toProto(a: StopRetryingInteractionRequest): protobuf.StopRetryingInteractionRequest =
+ protobuf.StopRetryingInteractionRequest(Some(a.recipeInstanceId), Some(a.interactionName))
+
+ override def fromProto(message: protobuf.StopRetryingInteractionRequest): Try[StopRetryingInteractionRequest] =
+ for {
+ recipeInstanceId <- versioned(message.recipeInstanceId, "recipeInstanceId")
+ interactionName <- versioned(message.interactionName, "interactionName")
+ } yield StopRetryingInteractionRequest(recipeInstanceId, interactionName)
+ }
+}
diff --git a/baas-protocol-baker/src/main/scala/com/ing/baker/baas/protocol/BaaSProtocol.scala b/baas-protocol-baker/src/main/scala/com/ing/baker/baas/protocol/BaaSProtocol.scala
new file mode 100644
index 000000000..296913f59
--- /dev/null
+++ b/baas-protocol-baker/src/main/scala/com/ing/baker/baas/protocol/BaaSProtocol.scala
@@ -0,0 +1,54 @@
+package com.ing.baker.baas.protocol
+
+import com.ing.baker.il.CompiledRecipe
+import com.ing.baker.runtime.common.{BakerException, SensoryEventStatus}
+import com.ing.baker.runtime.scaladsl._
+
+object BaaSProtocol {
+
+ case class BaaSRemoteFailure(error: BakerException)
+
+ case class AddRecipeRequest(compiledRecipe: CompiledRecipe)
+
+ case class AddRecipeResponse(recipeId: String)
+
+ case class GetRecipeRequest(recipeId: String)
+
+ case class GetRecipeResponse(recipeInformation: RecipeInformation)
+
+ case class GetAllRecipesResponse(map: Map[String, RecipeInformation])
+
+ case class BakeRequest(recipeId: String, recipeInstanceId: String)
+
+ case class FireEventAndResolveWhenReceivedRequest(recipeInstanceId: String, event: EventInstance, correlationId: Option[String])
+
+ case class FireEventAndResolveWhenReceivedResponse(sensoryEventStatus: SensoryEventStatus)
+
+ case class FireEventAndResolveWhenCompletedRequest(recipeInstanceId: String, event: EventInstance, correlationId: Option[String])
+
+ case class FireEventAndResolveWhenCompletedResponse(sensoryEventResult: SensoryEventResult)
+
+ case class FireEventAndResolveOnEventRequest(recipeInstanceId: String, event: EventInstance, onEvent: String, correlationId: Option[String])
+
+ case class FireEventAndResolveOnEventResponse(sensoryEventResult: SensoryEventResult)
+
+ case class FireEventRequest(recipeInstanceId: String, event: EventInstance, correlationId: Option[String])
+
+ // case class FireEventResponse() TODO figure out how to deal with this one
+
+ case class GetAllRecipeInstancesMetadataResponse(set: Set[RecipeInstanceMetadata])
+
+ case class GetRecipeInstanceStateRequest(recipeInstanceId: String)
+
+ case class GetRecipeInstanceStateResponse(recipeInstanceState: RecipeInstanceState)
+
+ case class GetVisualStateRequest(recipeInstanceId: String)
+
+ case class GetVisualStateResponse(state: String)
+
+ case class RetryInteractionRequest(recipeInstanceId: String, interactionName: String)
+
+ case class ResolveInteractionRequest(recipeInstanceId: String, interactionName: String, event: EventInstance)
+
+ case class StopRetryingInteractionRequest(recipeInstanceId: String, interactionName: String)
+}
diff --git a/baas-protocol-baker/src/main/scala/com/ing/baker/baas/protocol/MarshallingUtils.scala b/baas-protocol-baker/src/main/scala/com/ing/baker/baas/protocol/MarshallingUtils.scala
new file mode 100644
index 000000000..79dd21603
--- /dev/null
+++ b/baas-protocol-baker/src/main/scala/com/ing/baker/baas/protocol/MarshallingUtils.scala
@@ -0,0 +1,70 @@
+package com.ing.baker.baas.protocol
+
+import akka.http.scaladsl.marshalling.{Marshaller, ToEntityMarshaller}
+import akka.http.scaladsl.model.{ContentTypes, HttpResponse, MediaTypes, StatusCodes}
+import akka.http.scaladsl.server.Directives.{complete, onSuccess}
+import akka.http.scaladsl.server.Route
+import akka.http.scaladsl.unmarshalling.{FromEntityUnmarshaller, Unmarshal, Unmarshaller}
+import akka.stream.Materializer
+import com.ing.baker.runtime.common.BakerException
+import com.ing.baker.runtime.serialization.ProtoMap
+import BaaSProto._
+
+import scala.concurrent.{ExecutionContext, Future}
+
+object MarshallingUtils {
+
+ type ProtoMessage[A] = scalapb.GeneratedMessage with scalapb.Message[A]
+
+ def completeWithBakerFailures[A, P <: ProtoMessage[P]](f: Future[A])(implicit ec: ExecutionContext, m1: ProtoMap[A, P]): Route =
+ complete(f.map(Right(_)).recover { case e: BakerException => Left(BaaSProtocol.BaaSRemoteFailure(e)) })
+
+ def completeWithBakerFailures(f: Future[Unit])(implicit ec: ExecutionContext): Route =
+ onSuccess(f.map(_ => None).recover { case e: BakerException => Some(e) }) {
+ case Some(e) => complete(BaaSProtocol.BaaSRemoteFailure(e))
+ case None => complete(StatusCodes.OK)
+ }
+
+ case class UnmarshalWithBakerExceptions[A](response: HttpResponse) {
+
+ def withBakerExceptions[P <: ProtoMessage[P]](implicit ec: ExecutionContext, mat: Materializer, m1: ProtoMap[A, P]): Future[A] = {
+ for {
+ decoded <- Unmarshal(response).to[Either[BaaSProtocol.BaaSRemoteFailure, A]]
+ response <- decoded match {
+ case Left(e) => Future.failed(e.error)
+ case Right(a) => Future.successful(a)
+ }
+ } yield response
+ }
+ }
+
+ def unmarshal[A](response: HttpResponse): UnmarshalWithBakerExceptions[A] =
+ UnmarshalWithBakerExceptions[A](response)
+
+ def unmarshalBakerExceptions(response: HttpResponse)(implicit ec: ExecutionContext, mat: Materializer): Future[Unit] =
+ response.entity.httpEntity.contentType match {
+ case ContentTypes.`application/octet-stream` =>
+ Unmarshal(response)
+ .to[BaaSProtocol.BaaSRemoteFailure]
+ .flatMap(e => Future.failed(e.error))
+ case _ =>
+ Future.successful(())
+ }
+
+ implicit def protoMarshaller[A, P <: ProtoMessage[P]](implicit mapping: ProtoMap[A, P]): ToEntityMarshaller[A] =
+ Marshaller.ByteArrayMarshaller.wrap(MediaTypes.`application/octet-stream`)(mapping.toByteArray)
+
+ implicit def protoUnmarshaller[A, P <: ProtoMessage[P]](implicit mapping: ProtoMap[A, P]): FromEntityUnmarshaller[A] =
+ Unmarshaller.byteArrayUnmarshaller.map(mapping.fromByteArray(_).get)
+
+ implicit def protoEitherMarshaller[A, P0 <: ProtoMessage[P0], B, P1 <: ProtoMessage[P1]](implicit m1: ProtoMap[A, P0], m2: ProtoMap[B, P1]): ToEntityMarshaller[Either[A, B]] =
+ Marshaller.ByteArrayMarshaller.wrap(MediaTypes.`application/octet-stream`) {
+ case Left(a) => m1.toByteArray(a)
+ case Right(b) => m2.toByteArray(b)
+ }
+
+ implicit def protoEitherUnmarshaller[A, P0 <: ProtoMessage[P0], B, P1 <: ProtoMessage[P1]](implicit m1: ProtoMap[A, P0], m2: ProtoMap[B, P1]): FromEntityUnmarshaller[Either[A, B]] =
+ Unmarshaller.byteArrayUnmarshaller.map { byteArray =>
+ m1.fromByteArray(byteArray).map(Left(_)).orElse(m2.fromByteArray(byteArray).map(Right(_))).get
+ }
+}
diff --git a/baas-protocol-interaction-scheduling/src/main/protobuf/interaction_schedulling.proto b/baas-protocol-interaction-scheduling/src/main/protobuf/interaction_schedulling.proto
new file mode 100644
index 000000000..fe7a0497f
--- /dev/null
+++ b/baas-protocol-interaction-scheduling/src/main/protobuf/interaction_schedulling.proto
@@ -0,0 +1,61 @@
+syntax = "proto2";
+
+import "scalapb/scalapb.proto";
+import "common.proto";
+
+option java_package = "com.ing.baker.baas.protocol.protobuf";
+option (scalapb.options) = {
+ flat_package: true
+};
+
+message ExecuteInstance {
+ repeated Ingredient input = 1;
+}
+
+message InstanceExecutedSuccessfully {
+ optional RuntimeEvent result = 1;
+}
+
+message InstanceExecutionFailed {
+
+}
+
+message InstanceExecutionTimedOut {
+
+}
+
+message NoInstanceFound {
+
+}
+
+message InvalidExecution {
+
+}
+
+message Push {
+ optional ActorRefId mandated = 1;
+ optional string uuid = 2;
+}
+
+message Pull {
+ optional ActorRefId agent = 1;
+}
+
+message AvailableQuest {
+ optional ActorRefId mandated = 1;
+ optional string uuid = 2;
+}
+
+message Considering {
+ optional ActorRefId agent = 1;
+}
+
+message Commit {
+ optional ActorRefId mandated = 1;
+ optional ExecuteInstance execute = 2;
+}
+
+message QuestTaken {
+
+}
+
diff --git a/baas-protocol-interaction-scheduling/src/main/resources/reference.conf b/baas-protocol-interaction-scheduling/src/main/resources/reference.conf
new file mode 100644
index 000000000..9c3844d9f
--- /dev/null
+++ b/baas-protocol-interaction-scheduling/src/main/resources/reference.conf
@@ -0,0 +1,15 @@
+
+akka {
+ actor {
+
+ serializers {
+ interaction-scheduling-protobuf = "com.ing.baker.baas.akka.InteractionSchedulingProtocolsSerializer"
+ }
+
+ serialization-bindings {
+ "com.ing.baker.baas.protocol.ProtocolInteractionExecution" = interaction-scheduling-protobuf
+ "com.ing.baker.baas.protocol.ProtocolPushPullMatching" = interaction-scheduling-protobuf
+ "com.ing.baker.baas.protocol.ProtocolQuestCommit" = interaction-scheduling-protobuf
+ }
+ }
+}
diff --git a/baas-protocol-interaction-scheduling/src/main/scala/com/ing/baker/baas/akka/InteractionSchedulingProtocolsSerializer.scala b/baas-protocol-interaction-scheduling/src/main/scala/com/ing/baker/baas/akka/InteractionSchedulingProtocolsSerializer.scala
new file mode 100644
index 000000000..43aeb9375
--- /dev/null
+++ b/baas-protocol-interaction-scheduling/src/main/scala/com/ing/baker/baas/akka/InteractionSchedulingProtocolsSerializer.scala
@@ -0,0 +1,43 @@
+package com.ing.baker.baas.akka
+
+import akka.actor.ExtendedActorSystem
+import com.ing.baker.runtime.serialization.{SerializersProvider, TypedProtobufSerializer}
+import com.ing.baker.runtime.serialization.TypedProtobufSerializer.{BinarySerializable, forType}
+import com.ing.baker.baas.protocol.InteractionSchedulingProto._
+
+object InteractionSchedulingProtocolsSerializer {
+
+ val identifier: Int = 102
+
+ def entries(ev0: SerializersProvider): List[BinarySerializable] = {
+ implicit val ev = ev0
+ List(
+ forType[com.ing.baker.baas.protocol.ProtocolInteractionExecution.ExecuteInstance]
+ .register("com.ing.baker.baas.protocol.ProtocolInteractionExecution.ExecuteInstance"),
+ forType[com.ing.baker.baas.protocol.ProtocolInteractionExecution.InstanceExecutedSuccessfully]
+ .register("com.ing.baker.baas.protocol.ProtocolInteractionExecution.InstanceExecutedSuccessfully"),
+ forType[com.ing.baker.baas.protocol.ProtocolInteractionExecution.InstanceExecutionFailed]
+ .register("com.ing.baker.baas.protocol.ProtocolInteractionExecution.InstanceExecutionFailed"),
+ forType[com.ing.baker.baas.protocol.ProtocolInteractionExecution.InstanceExecutionTimedOut]
+ .register("com.ing.baker.baas.protocol.ProtocolInteractionExecution.InstanceExecutionTimedOut"),
+ forType[com.ing.baker.baas.protocol.ProtocolInteractionExecution.NoInstanceFound.type]
+ .register("com.ing.baker.baas.protocol.ProtocolInteractionExecution.NoInstanceFound"),
+ forType[com.ing.baker.baas.protocol.ProtocolInteractionExecution.InvalidExecution]
+ .register("com.ing.baker.baas.protocol.ProtocolInteractionExecution.InvalidExecution"),
+ forType[com.ing.baker.baas.protocol.ProtocolPushPullMatching.Push]
+ .register("com.ing.baker.baas.protocol.ProtocolPushPullMatching.Push"),
+ forType[com.ing.baker.baas.protocol.ProtocolPushPullMatching.Pull]
+ .register("com.ing.baker.baas.protocol.ProtocolPushPullMatching.Pull"),
+ forType[com.ing.baker.baas.protocol.ProtocolPushPullMatching.AvailableQuest]
+ .register("com.ing.baker.baas.protocol.ProtocolPushPullMatching.AvailableQuest"),
+ forType[com.ing.baker.baas.protocol.ProtocolQuestCommit.Considering]
+ .register("com.ing.baker.baas.protocol.ProtocolQuestCommit.Considering"),
+ forType[com.ing.baker.baas.protocol.ProtocolQuestCommit.Commit]
+ .register("com.ing.baker.baas.protocol.ProtocolQuestCommit.Commit"),
+ forType[com.ing.baker.baas.protocol.ProtocolQuestCommit.QuestTaken.type]
+ .register("com.ing.baker.baas.protocol.ProtocolQuestCommit.QuestTaken")
+ )
+ }
+}
+
+class InteractionSchedulingProtocolsSerializer(system: ExtendedActorSystem) extends TypedProtobufSerializer(system, InteractionSchedulingProtocolsSerializer.identifier ,InteractionSchedulingProtocolsSerializer.entries)
diff --git a/baas-protocol-interaction-scheduling/src/main/scala/com/ing/baker/baas/protocol/InteractionSchedulingProto.scala b/baas-protocol-interaction-scheduling/src/main/scala/com/ing/baker/baas/protocol/InteractionSchedulingProto.scala
new file mode 100644
index 000000000..cf3dd67ca
--- /dev/null
+++ b/baas-protocol-interaction-scheduling/src/main/scala/com/ing/baker/baas/protocol/InteractionSchedulingProto.scala
@@ -0,0 +1,184 @@
+package com.ing.baker.baas.protocol
+
+import java.util.UUID
+
+import cats.implicits._
+import com.ing.baker.baas.protocol.ProtocolInteractionExecution._
+import com.ing.baker.baas.protocol.ProtocolPushPullMatching._
+import com.ing.baker.baas.protocol.ProtocolQuestCommit._
+import com.ing.baker.runtime.serialization.{ProtoMap, SerializersProvider}
+import com.ing.baker.runtime.serialization.ProtoMap.{ctxFromProto, ctxToProto, versioned}
+
+import scala.util.{Success, Try}
+
+object InteractionSchedulingProto {
+
+ implicit def executeInstanceProto: ProtoMap[ExecuteInstance, protobuf.ExecuteInstance] =
+ new ProtoMap[ExecuteInstance, protobuf.ExecuteInstance] {
+
+ val companion = protobuf.ExecuteInstance
+
+ def toProto(a: ExecuteInstance): protobuf.ExecuteInstance =
+ protobuf.ExecuteInstance(a.input.map(ctxToProto(_)))
+
+ def fromProto(message: protobuf.ExecuteInstance): Try[ExecuteInstance] =
+ for {
+ result <- message.input.toList.traverse(ctxFromProto(_))
+ } yield ExecuteInstance(result)
+ }
+
+ implicit def instanceExcutedSuccessfullyProto: ProtoMap[InstanceExecutedSuccessfully, protobuf.InstanceExecutedSuccessfully] =
+ new ProtoMap[InstanceExecutedSuccessfully, protobuf.InstanceExecutedSuccessfully] {
+
+ val companion = protobuf.InstanceExecutedSuccessfully
+
+ def toProto(a: InstanceExecutedSuccessfully): protobuf.InstanceExecutedSuccessfully =
+ protobuf.InstanceExecutedSuccessfully(a.result.map(ctxToProto(_)))
+
+ def fromProto(message: protobuf.InstanceExecutedSuccessfully): Try[InstanceExecutedSuccessfully] =
+ for {
+ result <- message.result.traverse(ctxFromProto(_))
+ } yield InstanceExecutedSuccessfully(result)
+ }
+
+ implicit def instanceExecutionFailedProto: ProtoMap[InstanceExecutionFailed, protobuf.InstanceExecutionFailed] =
+ new ProtoMap[InstanceExecutionFailed, protobuf.InstanceExecutionFailed] {
+
+ val companion = protobuf.InstanceExecutionFailed
+
+ def toProto(a: InstanceExecutionFailed): protobuf.InstanceExecutionFailed =
+ protobuf.InstanceExecutionFailed()
+
+ def fromProto(message: protobuf.InstanceExecutionFailed): Try[InstanceExecutionFailed] =
+ Success(InstanceExecutionFailed())
+ }
+
+ implicit def instanceExecutionTimedOutProto: ProtoMap[InstanceExecutionTimedOut, protobuf.InstanceExecutionTimedOut] =
+ new ProtoMap[InstanceExecutionTimedOut, protobuf.InstanceExecutionTimedOut] {
+
+ val companion = protobuf.InstanceExecutionTimedOut
+
+ def toProto(a: InstanceExecutionTimedOut): protobuf.InstanceExecutionTimedOut =
+ protobuf.InstanceExecutionTimedOut()
+
+ def fromProto(message: protobuf.InstanceExecutionTimedOut): Try[InstanceExecutionTimedOut] =
+ Success(InstanceExecutionTimedOut())
+ }
+
+ implicit def noInstanceFoundProto: ProtoMap[NoInstanceFound.type, protobuf.NoInstanceFound] =
+ new ProtoMap[NoInstanceFound.type, protobuf.NoInstanceFound] {
+
+ val companion = protobuf.NoInstanceFound
+
+ def toProto(a: NoInstanceFound.type): protobuf.NoInstanceFound =
+ protobuf.NoInstanceFound()
+
+ def fromProto(message: protobuf.NoInstanceFound): Try[NoInstanceFound.type] =
+ Success(NoInstanceFound)
+ }
+
+ implicit def invalidExecutionProto: ProtoMap[InvalidExecution, protobuf.InvalidExecution] =
+ new ProtoMap[InvalidExecution, protobuf.InvalidExecution] {
+
+ val companion = protobuf.InvalidExecution
+
+ def toProto(a: InvalidExecution): protobuf.InvalidExecution =
+ protobuf.InvalidExecution()
+
+ def fromProto(message: protobuf.InvalidExecution): Try[InvalidExecution] =
+ Success(InvalidExecution())
+ }
+
+ implicit def pushProto(implicit ev0: SerializersProvider): ProtoMap[Push, protobuf.Push] =
+ new ProtoMap[Push, protobuf.Push] {
+
+ val companion = protobuf.Push
+
+ def toProto(a: Push): protobuf.Push =
+ protobuf.Push(Some(ctxToProto(a.mandated)), Some(a.uuid.toString))
+
+ def fromProto(message: protobuf.Push): Try[Push] =
+ for {
+ mandatedId <- versioned(message.mandated, "mandated")
+ mandated <- ctxFromProto(mandatedId)
+ uuidRaw <- versioned(message.uuid, "uuid")
+ uuid <- Try(UUID.fromString(uuidRaw))
+ } yield Push(mandated, uuid)
+ }
+
+ implicit def pullProto(implicit ev0: SerializersProvider): ProtoMap[Pull, protobuf.Pull] =
+ new ProtoMap[Pull, protobuf.Pull] {
+
+ val companion = protobuf.Pull
+
+ def toProto(a: Pull): protobuf.Pull =
+ protobuf.Pull(Some(ctxToProto(a.agent)))
+
+ def fromProto(message: protobuf.Pull): Try[Pull] =
+ for {
+ agentId <- versioned(message.agent, "agent")
+ agent <- ctxFromProto(agentId)
+ } yield Pull(agent)
+ }
+
+ implicit def availableQuestProto(implicit ev0: SerializersProvider): ProtoMap[AvailableQuest, protobuf.AvailableQuest] =
+ new ProtoMap[AvailableQuest, protobuf.AvailableQuest] {
+
+ val companion = protobuf.AvailableQuest
+
+ def toProto(a: AvailableQuest): protobuf.AvailableQuest =
+ protobuf.AvailableQuest(Some(ctxToProto(a.mandated)), Some(a.uuid.toString))
+
+ def fromProto(message: protobuf.AvailableQuest): Try[AvailableQuest] =
+ for {
+ mandatedId <- versioned(message.mandated, "mandated")
+ mandated <- ctxFromProto(mandatedId)
+ uuidRaw <- versioned(message.uuid, "uuid")
+ uuid <- Try(UUID.fromString(uuidRaw))
+ } yield AvailableQuest(mandated, uuid)
+ }
+
+ implicit def consideringProto(implicit ev0: SerializersProvider): ProtoMap[Considering, protobuf.Considering] =
+ new ProtoMap[Considering, protobuf.Considering] {
+
+ val companion = protobuf.Considering
+
+ def toProto(a: Considering): protobuf.Considering =
+ protobuf.Considering(Some(ctxToProto(a.agent)))
+
+ def fromProto(message: protobuf.Considering): Try[Considering] =
+ for {
+ agentId <- versioned(message.agent, "agent")
+ agent <- ctxFromProto(agentId)
+ } yield Considering(agent)
+ }
+
+ implicit def commitProto(implicit ev0: SerializersProvider): ProtoMap[Commit, protobuf.Commit] =
+ new ProtoMap[Commit, protobuf.Commit] {
+
+ val companion = protobuf.Commit
+
+ def toProto(a: Commit): protobuf.Commit =
+ protobuf.Commit(Some(ctxToProto(a.mandated)), Some(ctxToProto(a.execute)))
+
+ def fromProto(message: protobuf.Commit): Try[Commit] =
+ for {
+ mandatedId <- versioned(message.mandated, "mandated")
+ mandated <- ctxFromProto(mandatedId)
+ executeProto <- versioned(message.execute, "execute")
+ execute <- ctxFromProto(executeProto)
+ } yield Commit(mandated, execute)
+ }
+
+ implicit def questTakenProto: ProtoMap[QuestTaken.type, protobuf.QuestTaken] =
+ new ProtoMap[QuestTaken.type, protobuf.QuestTaken] {
+
+ val companion = protobuf.QuestTaken
+
+ def toProto(a: QuestTaken.type): protobuf.QuestTaken =
+ protobuf.QuestTaken()
+
+ def fromProto(message: protobuf.QuestTaken): Try[QuestTaken.type] =
+ Success(QuestTaken)
+ }
+}
diff --git a/baas-protocol-interaction-scheduling/src/main/scala/com/ing/baker/baas/protocol/ProtocolInteractionExecution.scala b/baas-protocol-interaction-scheduling/src/main/scala/com/ing/baker/baas/protocol/ProtocolInteractionExecution.scala
new file mode 100644
index 000000000..e6e7d0968
--- /dev/null
+++ b/baas-protocol-interaction-scheduling/src/main/scala/com/ing/baker/baas/protocol/ProtocolInteractionExecution.scala
@@ -0,0 +1,45 @@
+package com.ing.baker.baas.protocol
+
+import com.ing.baker.runtime.scaladsl.{EventInstance, IngredientInstance}
+
+/**
+ * Protocol executed after a match between a QuestMandate and InteractionAgent has been made and after both
+ * have committed.
+ *
+ * A simple request from the manager to the agent for execution with specific ingredients is done using the
+ * ExecuteInstance message, the outcome comes in the form of either the response messages InstanceExecutedSuccessfully,
+ * InstanceExecutionFailed or InvalidExecution
+ *
+ */
+sealed trait ProtocolInteractionExecution
+
+object ProtocolInteractionExecution {
+
+ case class ExecuteInstance(input: Seq[IngredientInstance]) extends ProtocolInteractionExecution
+
+ /**
+ * Instance executed successfully
+ * @param result the EventInstance that is created, empty if interaction does not return an Event
+ */
+ case class InstanceExecutedSuccessfully(result: Option[EventInstance]) extends ProtocolInteractionExecution
+
+ /**
+ * Technical failure of the interaction
+ */
+ case class InstanceExecutionFailed() extends ProtocolInteractionExecution
+
+ /**
+ * Technical failure of the interaction
+ */
+ case class InstanceExecutionTimedOut() extends ProtocolInteractionExecution
+
+ /**
+ * Technical failure of the interaction
+ */
+ case object NoInstanceFound extends ProtocolInteractionExecution
+
+ /**
+ * Invalid request, bad ingredients given
+ */
+ case class InvalidExecution() extends ProtocolInteractionExecution
+}
diff --git a/baas-protocol-interaction-scheduling/src/main/scala/com/ing/baker/baas/protocol/ProtocolPushPullMatching.scala b/baas-protocol-interaction-scheduling/src/main/scala/com/ing/baker/baas/protocol/ProtocolPushPullMatching.scala
new file mode 100644
index 000000000..dbf8c2e74
--- /dev/null
+++ b/baas-protocol-interaction-scheduling/src/main/scala/com/ing/baker/baas/protocol/ProtocolPushPullMatching.scala
@@ -0,0 +1,26 @@
+package com.ing.baker.baas.protocol
+
+import java.util.UUID
+
+import akka.actor.ActorRef
+
+/**
+ * Protocol done to find a possible matching between a QuestMandated and an available InteractionAgent
+ */
+sealed trait ProtocolPushPullMatching
+
+object ProtocolPushPullMatching {
+
+ def pushTopic(interactionName: String): String =
+ s"Push|:||:|$interactionName|:|"
+
+ def pullTopic(interactionName: String): String =
+ s"Pull|:||:|$interactionName|:|"
+
+ case class Push(mandated: ActorRef, uuid: UUID) extends ProtocolPushPullMatching
+
+ case class Pull(agent: ActorRef) extends ProtocolPushPullMatching
+
+ case class AvailableQuest(mandated: ActorRef, uuid: UUID) extends ProtocolPushPullMatching
+
+}
diff --git a/baas-protocol-interaction-scheduling/src/main/scala/com/ing/baker/baas/protocol/ProtocolQuestCommit.scala b/baas-protocol-interaction-scheduling/src/main/scala/com/ing/baker/baas/protocol/ProtocolQuestCommit.scala
new file mode 100644
index 000000000..05e621f7a
--- /dev/null
+++ b/baas-protocol-interaction-scheduling/src/main/scala/com/ing/baker/baas/protocol/ProtocolQuestCommit.scala
@@ -0,0 +1,18 @@
+package com.ing.baker.baas.protocol
+
+import akka.actor.ActorRef
+
+/**
+ * A Protocol executed after finding a candidate match between a QuestMandated and an InteractionAgent, it makes sure
+ * that 1 QuestMandated commits with 1 InteractionAgent only and vice versa, without leaving orphan agents.
+ */
+sealed trait ProtocolQuestCommit
+
+object ProtocolQuestCommit {
+
+ case class Considering(agent: ActorRef) extends ProtocolQuestCommit
+
+ case class Commit(mandated: ActorRef, execute: ProtocolInteractionExecution.ExecuteInstance) extends ProtocolQuestCommit
+
+ case object QuestTaken extends ProtocolQuestCommit
+}
diff --git a/baas-protocol-recipe-event-publishing/src/main/protobuf/recipe_event_publishing.proto b/baas-protocol-recipe-event-publishing/src/main/protobuf/recipe_event_publishing.proto
new file mode 100644
index 000000000..2119eab3a
--- /dev/null
+++ b/baas-protocol-recipe-event-publishing/src/main/protobuf/recipe_event_publishing.proto
@@ -0,0 +1,14 @@
+syntax = "proto2";
+
+import "scalapb/scalapb.proto";
+import "common.proto";
+
+option java_package = "com.ing.baker.baas.protocol.protobuf";
+option (scalapb.options) = {
+ flat_package: true
+};
+
+message Event {
+ optional RecipeEventMetadata recipeEventMetadata = 1;
+ optional RuntimeEvent event = 2;
+}
diff --git a/baas-protocol-recipe-event-publishing/src/main/resources/reference.conf b/baas-protocol-recipe-event-publishing/src/main/resources/reference.conf
new file mode 100644
index 000000000..b82403e45
--- /dev/null
+++ b/baas-protocol-recipe-event-publishing/src/main/resources/reference.conf
@@ -0,0 +1,13 @@
+
+akka {
+ actor {
+
+ serializers {
+ event-publishing-protobuf = "com.ing.baker.baas.akka.DistributedEventPublishingProtocolSerializer"
+ }
+
+ serialization-bindings {
+ "com.ing.baker.baas.protocol.ProtocolDistributedEventPublishing" = event-publishing-protobuf
+ }
+ }
+}
diff --git a/baas-protocol-recipe-event-publishing/src/main/scala/com/ing/baker/baas/akka/DistributedEventPublishingProtocolSerializer.scala b/baas-protocol-recipe-event-publishing/src/main/scala/com/ing/baker/baas/akka/DistributedEventPublishingProtocolSerializer.scala
new file mode 100644
index 000000000..a8b87d4ac
--- /dev/null
+++ b/baas-protocol-recipe-event-publishing/src/main/scala/com/ing/baker/baas/akka/DistributedEventPublishingProtocolSerializer.scala
@@ -0,0 +1,26 @@
+package com.ing.baker.baas.akka
+
+import akka.actor.ExtendedActorSystem
+import com.ing.baker.baas.protocol.DistributedEventPublishingProto._
+import com.ing.baker.baas.protocol.ProtocolDistributedEventPublishing
+import com.ing.baker.runtime.serialization.TypedProtobufSerializer.{BinarySerializable, forType}
+import com.ing.baker.runtime.serialization.{SerializersProvider, TypedProtobufSerializer}
+
+object DistributedEventPublishingProtocolSerializer {
+
+ val identifier: Int = 103
+
+ def entries(ev0: SerializersProvider): List[BinarySerializable] = {
+ implicit val ev = ev0
+ List(
+ forType[ProtocolDistributedEventPublishing.Event]
+ .register("ProtocolDistributedEventPublishing.Event")
+ )
+ }
+}
+
+class DistributedEventPublishingProtocolSerializer(system: ExtendedActorSystem) extends TypedProtobufSerializer(
+ system,
+ DistributedEventPublishingProtocolSerializer.identifier,
+ DistributedEventPublishingProtocolSerializer.entries
+)
diff --git a/baas-protocol-recipe-event-publishing/src/main/scala/com/ing/baker/baas/protocol/DistributedEventPublishingProto.scala b/baas-protocol-recipe-event-publishing/src/main/scala/com/ing/baker/baas/protocol/DistributedEventPublishingProto.scala
new file mode 100644
index 000000000..d0fe1af9b
--- /dev/null
+++ b/baas-protocol-recipe-event-publishing/src/main/scala/com/ing/baker/baas/protocol/DistributedEventPublishingProto.scala
@@ -0,0 +1,28 @@
+package com.ing.baker.baas.protocol
+
+import com.ing.baker.baas.protocol.ProtocolDistributedEventPublishing.Event
+import com.ing.baker.runtime.serialization.ProtoMap
+import com.ing.baker.runtime.serialization.ProtoMap.{ctxFromProto, ctxToProto, versioned}
+
+import scala.util.Try
+
+object DistributedEventPublishingProto {
+
+ implicit def eventProto: ProtoMap[Event, protobuf.Event] =
+ new ProtoMap[Event, protobuf.Event] {
+
+ val companion = protobuf.Event
+
+ def toProto(a: Event): protobuf.Event =
+ protobuf.Event(Some(ctxToProto(a.recipeEventMetadata)), Some(ctxToProto(a.event)))
+
+ def fromProto(message: protobuf.Event): Try[Event] =
+ for {
+ recipeEventMetadataProto <- versioned(message.recipeEventMetadata, "recipeEventMetadata")
+ recipeEventMetadata <- ctxFromProto(recipeEventMetadataProto)
+ eventProto <- versioned(message.event, "event")
+ event <- ctxFromProto(eventProto)
+ } yield Event(recipeEventMetadata, event)
+ }
+
+}
diff --git a/baas-protocol-recipe-event-publishing/src/main/scala/com/ing/baker/baas/protocol/ProtocolDistributedEventPublishing.scala b/baas-protocol-recipe-event-publishing/src/main/scala/com/ing/baker/baas/protocol/ProtocolDistributedEventPublishing.scala
new file mode 100644
index 000000000..29d19b2ba
--- /dev/null
+++ b/baas-protocol-recipe-event-publishing/src/main/scala/com/ing/baker/baas/protocol/ProtocolDistributedEventPublishing.scala
@@ -0,0 +1,13 @@
+package com.ing.baker.baas.protocol
+
+import com.ing.baker.runtime.scaladsl.{EventInstance, RecipeEventMetadata}
+
+sealed trait ProtocolDistributedEventPublishing
+
+object ProtocolDistributedEventPublishing {
+
+ def eventsTopic(recipeName: String): String =
+ s"recipe-event-publishing:$recipeName:event"
+
+ case class Event(recipeEventMetadata: RecipeEventMetadata, event: EventInstance) extends ProtocolDistributedEventPublishing
+}
diff --git a/baas-tests/src/test/resources/application.conf b/baas-tests/src/test/resources/application.conf
new file mode 100644
index 000000000..14b0925f8
--- /dev/null
+++ b/baas-tests/src/test/resources/application.conf
@@ -0,0 +1,93 @@
+baker {
+
+ config-file-included = true
+
+ actor {
+ # the id of the journal to read events from
+ read-journal-plugin = "inmemory-read-journal"
+
+ # either "local" or "cluster-sharded"
+ provider = "cluster-sharded"
+
+ # the recommended nr is number-of-cluster-nodes * 10
+ cluster.nr-of-shards = 10
+
+ # the time that inactive actors (processes) stay in memory
+ idle-timeout = 5 minutes
+
+ # The interval that a check is done of processes should be deleted
+ retention-check-interval = 1 minutes
+ }
+
+ # the default timeout for Baker.bake(..) process creation calls
+ bake-timeout = 10 seconds
+
+ # the timeout for refreshing the local recipe cache
+ process-index-update-cache-timeout = 5 seconds
+
+ # the default timeout for Baker.processEvent(..)
+ process-event-timeout = 10 seconds
+
+ # the default timeout for inquires on Baker, this means getIngredients(..) & getEvents(..)
+ process-inquire-timeout = 10 seconds
+
+ # when baker starts up, it attempts to 'initialize' the journal connection, this may take some time
+ journal-initialize-timeout = 30 seconds
+
+ # the default timeout for adding a recipe to Baker
+ add-recipe-timeout = 10 seconds
+
+ # the time to wait for a gracefull shutdown
+ shutdown-timeout = 30 seconds
+
+ # The ingredients that are filtered out when getting the process instance.
+ # This should be used if there are big ingredients to improve performance and memory usage.
+ # The ingredients will be in the ingredients map but there value will be an empty String.
+ filtered-ingredient-values = []
+
+ # encryption settings
+ encryption {
+
+ # whether to encrypt data stored in the journal, off or on
+ enabled = off
+
+ # if enabled = on, a secret should be set
+ # secret = ???
+ }
+
+ # use "local" unless you are configuring a BaaS environment, then you will need "remote"
+ interaction-manager = "remote"
+}
+
+akka {
+
+ cluster {
+ jmx.multi-mbeans-in-same-jvm = on
+ sharding.state-store-mode = persistence
+ }
+
+ persistence {
+ journal.plugin = "inmemory-journal"
+ snapshot-store.plugin = "inmemory-snapshot-store"
+ }
+
+ actor {
+ provider = "cluster"
+ idle-timeout = 1 minute
+ allow-java-serialization = off
+
+ serializers {
+ baker-typed-protobuf = "com.ing.baker.runtime.akka.actor.serialization.BakerTypedProtobufSerializer"
+ }
+
+ serialization-bindings {
+ "com.ing.baker.runtime.serialization.BakerSerializable" = baker-typed-protobuf
+ "com.ing.baker.types.Value" = baker-typed-protobuf
+ "com.ing.baker.types.Type" = baker-typed-protobuf
+ "com.ing.baker.il.CompiledRecipe" = baker-typed-protobuf
+ "com.ing.baker.runtime.scaladsl.EventInstance" = baker-typed-protobuf
+ "com.ing.baker.runtime.scaladsl.RecipeInstanceState" = baker-typed-protobuf
+ "com.ing.baker.runtime.scaladsl.RecipeEventMetadata" = baker-typed-protobuf
+ }
+ }
+}
diff --git a/baas-tests/src/test/scala/com/ing/baker/baas/recipe/CheckoutFlowRecipe.scala b/baas-tests/src/test/scala/com/ing/baker/baas/recipe/CheckoutFlowRecipe.scala
new file mode 100644
index 000000000..bbc41cc27
--- /dev/null
+++ b/baas-tests/src/test/scala/com/ing/baker/baas/recipe/CheckoutFlowRecipe.scala
@@ -0,0 +1,130 @@
+package com.ing.baker.baas.recipe
+
+import com.ing.baker.baas.recipe.CheckoutFlowEvents._
+import com.ing.baker.baas.recipe.CheckoutFlowIngredients._
+import com.ing.baker.baas.recipe.CheckoutFlowInteractions._
+import com.ing.baker.recipe.common.InteractionFailureStrategy.RetryWithIncrementalBackoff.UntilDeadline
+import com.ing.baker.recipe.common.InteractionFailureStrategy.{BlockInteraction, RetryWithIncrementalBackoff}
+import com.ing.baker.recipe.scaladsl.{Event, Ingredient, Interaction, Recipe}
+
+import scala.concurrent.Future
+import scala.concurrent.duration._
+
+object CheckoutFlowIngredients {
+
+ case class OrderId(orderId: String)
+
+ case class Item(itemId: String)
+
+ case class ReservedItems(items: List[Item], data: Array[Byte])
+
+ case class ShippingAddress(address: String)
+
+ case class PaymentInformation(info: String)
+
+ case class ShippingOrder(items: List[Item], data: Array[Byte], address: ShippingAddress)
+
+}
+
+object CheckoutFlowEvents {
+
+ case class OrderPlaced(orderId: OrderId, items: List[Item])
+
+ case class PaymentInformationReceived(paymentInformation: PaymentInformation)
+
+ case class ShippingAddressReceived(shippingAddress: ShippingAddress)
+
+ sealed trait ReserveItemsOutput
+
+ case class OrderHadUnavailableItems(unavailableItems: List[Item]) extends ReserveItemsOutput
+
+ case class ItemsReserved(reservedItems: ReservedItems) extends ReserveItemsOutput
+
+ sealed trait MakePaymentOutput
+
+ case class PaymentSuccessful(shippingOrder: ShippingOrder) extends MakePaymentOutput
+
+ case class PaymentFailed() extends MakePaymentOutput
+
+ case class ShippingConfirmed()
+
+}
+
+object CheckoutFlowInteractions {
+
+ trait ReserveItems {
+
+ def apply(orderId: OrderId, items: List[Item]): Future[ReserveItemsOutput]
+ }
+
+ def ReserveItemsInteraction: Interaction = Interaction(
+ name = "ReserveItems",
+ inputIngredients = Seq(
+ Ingredient[OrderId]("orderId"),
+ Ingredient[List[Item]]("items")
+ ),
+ output = Seq(
+ Event[OrderHadUnavailableItems],
+ Event[ItemsReserved]
+ )
+ )
+
+ trait MakePayment {
+
+ def apply(items: ReservedItems, address: ShippingAddress, payment: PaymentInformation): Future[MakePaymentOutput]
+ }
+
+ def MakePaymentInteraction: Interaction = Interaction(
+ name = "MakePayment",
+ inputIngredients = Seq(
+ Ingredient[ReservedItems]("reservedItems"),
+ Ingredient[ShippingAddress]("shippingAddress"),
+ Ingredient[PaymentInformation]("paymentInformation")
+ ),
+ output = Seq(
+ Event[PaymentSuccessful],
+ Event[PaymentFailed]
+ )
+ )
+
+ trait ShipItems {
+
+ def apply(order: ShippingOrder): Future[ShippingConfirmed]
+ }
+
+ def ShipItemsInteraction: Interaction = Interaction(
+ name = "ShipItems",
+ inputIngredients = Seq(
+ Ingredient[ShippingOrder]("shippingOrder")
+ ),
+ output = Seq(
+ Event[ShippingConfirmed]
+ )
+ )
+}
+
+object CheckoutFlowRecipe {
+
+ private def recipeBase = Recipe("Webshop")
+ .withSensoryEvents(
+ Event[OrderPlaced],
+ Event[PaymentInformationReceived],
+ Event[ShippingAddressReceived])
+ .withInteractions(
+ ReserveItemsInteraction,
+ MakePaymentInteraction,
+ ShipItemsInteraction)
+
+ def recipe: Recipe =
+ recipeBase.withDefaultFailureStrategy(
+ RetryWithIncrementalBackoff
+ .builder()
+ .withInitialDelay(100.milliseconds)
+ .withUntil(Some(UntilDeadline(24.hours)))
+ .withMaxTimeBetweenRetries(Some(10.minutes))
+ .build())
+
+ def recipeWithBlockingStrategy: Recipe =
+ recipeBase.withDefaultFailureStrategy(
+ BlockInteraction())
+}
diff --git a/baas-tests/src/test/scala/com/ing/baker/baas/recipe/MakePaymentInstance.scala b/baas-tests/src/test/scala/com/ing/baker/baas/recipe/MakePaymentInstance.scala
new file mode 100644
index 000000000..470b1fa8b
--- /dev/null
+++ b/baas-tests/src/test/scala/com/ing/baker/baas/recipe/MakePaymentInstance.scala
@@ -0,0 +1,18 @@
+package com.ing.baker.baas.recipe
+
+import cats.effect.{IO, Timer}
+import com.ing.baker.baas.recipe.CheckoutFlowEvents.MakePaymentOutput
+import com.ing.baker.baas.recipe.CheckoutFlowIngredients.{PaymentInformation, ReservedItems, ShippingAddress, ShippingOrder}
+import com.ing.baker.baas.recipe.CheckoutFlowInteractions.MakePayment
+
+import scala.concurrent.Future
+import scala.concurrent.duration._
+
+class MakePaymentInstance(implicit timer: Timer[IO]) extends MakePayment {
+
+ override def apply(items: ReservedItems, address: ShippingAddress, payment: PaymentInformation): Future[MakePaymentOutput] = {
+ IO.sleep(5.second)
+ .map(_ => CheckoutFlowEvents.PaymentSuccessful(ShippingOrder(items.items, items.data, address)))
+ .unsafeToFuture()
+ }
+}
diff --git a/baas-tests/src/test/scala/com/ing/baker/baas/recipe/ReserveItemsInstance.scala b/baas-tests/src/test/scala/com/ing/baker/baas/recipe/ReserveItemsInstance.scala
new file mode 100644
index 000000000..7d1b0f715
--- /dev/null
+++ b/baas-tests/src/test/scala/com/ing/baker/baas/recipe/ReserveItemsInstance.scala
@@ -0,0 +1,34 @@
+package com.ing.baker.baas.recipe
+
+import cats.effect.{IO, Timer}
+import cats.implicits._
+import com.ing.baker.baas.recipe.CheckoutFlowEvents.ReserveItemsOutput
+import com.ing.baker.baas.recipe.CheckoutFlowIngredients.{Item, OrderId, ReservedItems}
+import com.ing.baker.baas.recipe.CheckoutFlowInteractions.ReserveItems
+
+import scala.concurrent.Future
+import scala.concurrent.duration._
+
+class ReserveItemsInstance(implicit timer: Timer[IO]) extends ReserveItems {
+
+ override def apply(orderId: OrderId, items: List[Item]): Future[ReserveItemsOutput] = {
+ IO.sleep(1.second)
+ .as(CheckoutFlowEvents.ItemsReserved(ReservedItems(items, Array.fill(1000)(Byte.MaxValue))))
+ .unsafeToFuture()
+ }
+}
+
+class FailingOnceReserveItemsInstance extends ReserveItems {
+
+ var times = 1;
+
+ override def apply(orderId: OrderId, items: List[Item]): Future[ReserveItemsOutput] =
+ if (times == 1) { times = times + 1; Future.failed(new RuntimeException("oups")) }
+ else Future.successful(CheckoutFlowEvents.ItemsReserved(ReservedItems(items, Array.fill(1000)(Byte.MaxValue))))
+}
+
+class FailingReserveItemsInstance extends ReserveItems {
+
+ override def apply(orderId: OrderId, items: List[Item]): Future[ReserveItemsOutput] =
+ Future.failed(new RuntimeException("oups"))
+}
diff --git a/baas-tests/src/test/scala/com/ing/baker/baas/recipe/ShipItemsInstance.scala b/baas-tests/src/test/scala/com/ing/baker/baas/recipe/ShipItemsInstance.scala
new file mode 100644
index 000000000..723eeaaf9
--- /dev/null
+++ b/baas-tests/src/test/scala/com/ing/baker/baas/recipe/ShipItemsInstance.scala
@@ -0,0 +1,20 @@
+package com.ing.baker.baas.recipe
+
+import cats.effect.{IO, Timer}
+import cats.implicits._
+import com.ing.baker.baas.recipe.CheckoutFlowEvents.ShippingConfirmed
+import com.ing.baker.baas.recipe.CheckoutFlowIngredients.ShippingOrder
+import com.ing.baker.baas.recipe.CheckoutFlowInteractions.ShipItems
+
+import scala.concurrent.Future
+import scala.concurrent.duration._
+
+class ShipItemsInstance(implicit timer: Timer[IO]) extends ShipItems {
+
+ override def apply(order: ShippingOrder): Future[ShippingConfirmed] = {
+ IO.sleep(500.millis)
+ .as(ShippingConfirmed())
+ .unsafeToFuture()
+ }
+}
+
diff --git a/baas-tests/src/test/scala/com/ing/baker/baas/spec/BaaSIntegrationSpec.scala b/baas-tests/src/test/scala/com/ing/baker/baas/spec/BaaSIntegrationSpec.scala
new file mode 100644
index 000000000..77600547b
--- /dev/null
+++ b/baas-tests/src/test/scala/com/ing/baker/baas/spec/BaaSIntegrationSpec.scala
@@ -0,0 +1,448 @@
+package com.ing.baker.baas.spec
+
+import java.util.UUID
+
+import akka.actor.ActorSystem
+import akka.http.scaladsl.Http
+import akka.stream.{ActorMaterializer, Materializer}
+import cats.data.StateT
+import cats.effect.{IO, Timer}
+import cats.implicits._
+import com.ing.baker.baas.recipe.CheckoutFlowEvents.ItemsReserved
+import com.ing.baker.baas.recipe.CheckoutFlowIngredients.{Item, OrderId, ReservedItems, ShippingAddress}
+import com.ing.baker.baas.recipe._
+import com.ing.baker.baas.scaladsl.{BaaSEventListener, BaaSInteractionInstance, BakerClient}
+import com.ing.baker.baas.spec.BaaSIntegrationSpec._
+import com.ing.baker.baas.state.BaaSServer
+import com.ing.baker.compiler.RecipeCompiler
+import com.ing.baker.il.CompiledRecipe
+import com.ing.baker.runtime.akka.AkkaBaker
+import com.ing.baker.runtime.common.LanguageDataStructures.LanguageApi
+import com.ing.baker.runtime.common.{BakerException, SensoryEventStatus}
+import com.ing.baker.runtime.scaladsl.{EventInstance, InteractionInstance, Baker => ScalaBaker}
+import com.ing.baker.runtime.serialization.Encryption
+import com.typesafe.config.{Config, ConfigFactory}
+import org.jboss.netty.channel.ChannelException
+import org.scalatest._
+
+import scala.collection.mutable
+import scala.concurrent.{ExecutionContext, Future}
+
+class BaaSIntegrationSpec
+ extends AsyncFunSpec
+ with Matchers
+ with BeforeAndAfterAll
+ with BeforeAndAfterEach {
+
+ val test: IntegrationTest = BaaSIntegrationSpec.testWith
+
+ implicit val timer: Timer[IO] = IO.timer(executionContext)
+
+ describe("Baker Client-Server") {
+ it("Baker.addRecipe") {
+ test { (client, stateNode, interactionNode, _) =>
+ for {
+ compiledRecipe <- setupHappyPath(interactionNode)
+ recipeId <- client.addRecipe(compiledRecipe)
+ recipeInformation <- stateNode.getRecipe(recipeId)
+ } yield recipeInformation.compiledRecipe shouldBe compiledRecipe
+ }
+ }
+
+ it("Baker.getRecipe") {
+ test { (client, _, interactionNode, _) =>
+ for {
+ compiledRecipe <- setupHappyPath(interactionNode)
+ recipeId <- client.addRecipe(compiledRecipe)
+ recipeInformation <- client.getRecipe(recipeId)
+ } yield recipeInformation.compiledRecipe shouldBe compiledRecipe
+ }
+ }
+
+ it("Baker.getRecipe (fail with NoSuchRecipeException)") {
+ test { (client, _, _, _) =>
+ for {
+ e <- client
+ .getRecipe("non-existent")
+ .map(_ => None)
+ .recover { case e: BakerException => Some(e) }
+ } yield e shouldBe Some(BakerException.NoSuchRecipeException("non-existent"))
+ }
+ }
+
+ it("Baker.getAllRecipes") {
+ test { (client, stateNode, interactionNode, _) =>
+ for {
+ compiledRecipe <- setupHappyPath(interactionNode)
+ recipeId <- client.addRecipe(compiledRecipe)
+ recipes <- client.getAllRecipes
+ } yield recipes.get(recipeId).map(_.compiledRecipe) shouldBe Some(compiledRecipe)
+ }
+ }
+
+ it("Baker.bake") {
+ test { (client, stateNode, interactionNode, eventListenerNode) =>
+ val recipeInstanceId: String = UUID.randomUUID().toString
+ for {
+ compiledRecipe <- setupHappyPath(interactionNode)
+ events <- setupEventListener(compiledRecipe, eventListenerNode)
+ recipeId <- client.addRecipe(compiledRecipe)
+ _ <- client.bake(recipeId, recipeInstanceId)
+ state <- stateNode.getRecipeInstanceState(recipeInstanceId)
+ } yield {
+ events.toList shouldBe List.empty
+ state.recipeInstanceId shouldBe recipeInstanceId
+ }
+ }
+ }
+
+ it("Baker.bake (fail with ProcessAlreadyExistsException)") {
+ test { (client, stateNode, interactionNode, _) =>
+ val recipeInstanceId: String = UUID.randomUUID().toString
+ for {
+ compiledRecipe <- setupHappyPath(interactionNode)
+ recipeId <- client.addRecipe(compiledRecipe)
+ _ <- client.bake(recipeId, recipeInstanceId)
+ e <- client
+ .bake(recipeId, recipeInstanceId)
+ .map(_ => None)
+ .recover { case e: BakerException => Some(e) }
+ state <- stateNode.getRecipeInstanceState(recipeInstanceId)
+ } yield {
+ e shouldBe Some(BakerException.ProcessAlreadyExistsException(recipeInstanceId))
+ state.recipeInstanceId shouldBe recipeInstanceId
+ }
+ }
+ }
+
+ it("Baker.bake (fail with NoSuchRecipeException)") {
+ test { (client, _, _, _) =>
+ val recipeInstanceId: String = UUID.randomUUID().toString
+ for {
+ e <- client
+ .bake("non-existent", recipeInstanceId)
+ .map(_ => None)
+ .recover { case e: BakerException => Some(e) }
+ } yield e shouldBe Some(BakerException.NoSuchRecipeException("non-existent"))
+ }
+ }
+
+ it("Baker.getRecipeInstanceState (fails with NoSuchProcessException)") {
+ test { (_, stateNode, _, _) =>
+ for {
+ e <- stateNode
+ .getRecipeInstanceState("non-existent")
+ .map(_ => None)
+ .recover { case e: BakerException => Some(e) }
+ } yield e shouldBe Some(BakerException.NoSuchProcessException("non-existent"))
+ }
+ }
+
+ it("Baker.fireEventAndResolveWhenReceived") {
+ test { (client, _, interactionNode, _) =>
+ val recipeInstanceId: String = UUID.randomUUID().toString
+ val event = EventInstance.unsafeFrom(
+ CheckoutFlowEvents.ShippingAddressReceived(ShippingAddress("address")))
+ for {
+ compiledRecipe <- setupHappyPath(interactionNode)
+ recipeId <- client.addRecipe(compiledRecipe)
+ _ <- client.bake(recipeId, recipeInstanceId)
+ status <- client.fireEventAndResolveWhenReceived(recipeInstanceId, event)
+ } yield status shouldBe SensoryEventStatus.Received
+ }
+ }
+
+ it("Baker.fireEventAndResolveWhenCompleted") {
+ test { (client, stateNode, interactionNode, eventListenerNode) =>
+ val recipeInstanceId: String = UUID.randomUUID().toString
+ val event = EventInstance.unsafeFrom(
+ CheckoutFlowEvents.ShippingAddressReceived(ShippingAddress("address")))
+ for {
+ compiledRecipe <- setupHappyPath(interactionNode)
+ events <- setupEventListener(compiledRecipe, eventListenerNode)
+ recipeId <- client.addRecipe(compiledRecipe)
+ _ <- client.bake(recipeId, recipeInstanceId)
+ result <- client.fireEventAndResolveWhenCompleted(recipeInstanceId, event)
+ serverState <- stateNode.getRecipeInstanceState(recipeInstanceId)
+ } yield {
+ result.eventNames should contain("ShippingAddressReceived")
+ serverState.events.map(_.name) should contain("ShippingAddressReceived")
+ events.toList.map(_.name) should contain("ShippingAddressReceived")
+ }
+ }
+ }
+
+ it("Baker.fireEventAndResolveWhenCompleted (fails with IllegalEventException)") {
+ test { (client, stateNode, interactionNode, _) =>
+ val recipeInstanceId: String = UUID.randomUUID().toString
+ val event = EventInstance("non-existent", Map.empty)
+ for {
+ compiledRecipe <- setupHappyPath(interactionNode)
+ recipeId <- client.addRecipe(compiledRecipe)
+ _ <- client.bake(recipeId, recipeInstanceId)
+ result <- client
+ .fireEventAndResolveWhenCompleted(recipeInstanceId, event)
+ .map(_ => None)
+ .recover { case e: BakerException => Some(e) }
+ serverState <- stateNode.getRecipeInstanceState(recipeInstanceId)
+ } yield {
+ result shouldBe Some(BakerException.IllegalEventException("No event with name 'non-existent' found in recipe 'Webshop'"))
+ serverState.events.map(_.name) should not contain("ShippingAddressReceived")
+ }
+ }
+ }
+
+ it("Baker.fireEventAndResolveOnEvent") {
+ test { (client, stateNode, interactionNode, eventListenerNode) =>
+ val recipeInstanceId: String = UUID.randomUUID().toString
+ val event = EventInstance.unsafeFrom(
+ CheckoutFlowEvents.ShippingAddressReceived(ShippingAddress("address")))
+ for {
+ compiledRecipe <- setupHappyPath(interactionNode)
+ events <- setupEventListener(compiledRecipe, eventListenerNode)
+ recipeId <- client.addRecipe(compiledRecipe)
+ _ <- client.bake(recipeId, recipeInstanceId)
+ result <- client.fireEventAndResolveOnEvent(recipeInstanceId, event, "ShippingAddressReceived")
+ serverState <- stateNode.getRecipeInstanceState(recipeInstanceId)
+ } yield {
+ result.eventNames should contain("ShippingAddressReceived")
+ serverState.events.map(_.name) should contain("ShippingAddressReceived")
+ events.toList.map(_.name) should contain("ShippingAddressReceived")
+ }
+ }
+ }
+
+ it("Baker.getAllRecipeInstancesMetadata") {
+ test { (client, stateNode, interactionNode, _) =>
+ val recipeInstanceId: String = UUID.randomUUID().toString
+ for {
+ compiledRecipe <- setupHappyPath(interactionNode)
+ recipeId <- client.addRecipe(compiledRecipe)
+ _ <- client.bake(recipeId, recipeInstanceId)
+ clientMetadata <- client.getAllRecipeInstancesMetadata
+ serverMetadata <- stateNode.getAllRecipeInstancesMetadata
+ } yield clientMetadata shouldBe serverMetadata
+ }
+ }
+
+ it("Baker.getVisualState") {
+ test { (client, stateNode, interactionNode, _) =>
+ val recipeInstanceId: String = UUID.randomUUID().toString
+ for {
+ compiledRecipe <- setupHappyPath(interactionNode)
+ recipeId <- client.addRecipe(compiledRecipe)
+ _ <- client.bake(recipeId, recipeInstanceId)
+ clientState <- client.getVisualState(recipeInstanceId)
+ serverState <- stateNode.getVisualState(recipeInstanceId)
+ } yield clientState shouldBe serverState
+ }
+ }
+
+ it("Baker.retryInteraction") {
+ test { (client, _, interactionNode, eventListenerNode) =>
+ val recipeInstanceId: String = UUID.randomUUID().toString
+ val event = EventInstance.unsafeFrom(
+ CheckoutFlowEvents.OrderPlaced(orderId = OrderId("order1"), List.empty))
+ for {
+ compiledRecipe <- setupFailingOnceReserveItems(interactionNode)
+ events <- setupEventListener(compiledRecipe, eventListenerNode)
+ recipeId <- client.addRecipe(compiledRecipe)
+ _ <- client.bake(recipeId, recipeInstanceId)
+ _ <- client.fireEventAndResolveWhenCompleted(recipeInstanceId, event)
+ state1 <- client.getRecipeInstanceState(recipeInstanceId).map(_.events.map(_.name))
+ _ <- client.retryInteraction(recipeInstanceId, "ReserveItems")
+ state2 <- client.getRecipeInstanceState(recipeInstanceId).map(_.events.map(_.name))
+ } yield {
+ state1 should contain("OrderPlaced")
+ state1 should not contain("ItemsReserved")
+ state2 should contain("OrderPlaced")
+ state2 should contain("ItemsReserved")
+ events.toList.map(_.name) should contain("OrderPlaced")
+ events.toList.map(_.name) should contain("ItemsReserved")
+ }
+ }
+ }
+
+ it("Baker.resolveInteraction") {
+ test { (client, _, interactionNode, eventListenerNode) =>
+ val recipeInstanceId: String = UUID.randomUUID().toString
+ val event = EventInstance.unsafeFrom(
+ CheckoutFlowEvents.OrderPlaced(orderId = OrderId("order1"), List.empty))
+ val resolutionEvent = EventInstance.unsafeFrom(
+ ItemsReserved(reservedItems = ReservedItems(items = List(Item("item1")), data = Array.empty))
+ )
+ for {
+ compiledRecipe <- setupFailingOnceReserveItems(interactionNode)
+ events <- setupEventListener(compiledRecipe, eventListenerNode)
+ recipeId <- client.addRecipe(compiledRecipe)
+ _ <- client.bake(recipeId, recipeInstanceId)
+ _ <- client.fireEventAndResolveWhenCompleted(recipeInstanceId, event)
+ state1 <- client.getRecipeInstanceState(recipeInstanceId).map(_.events.map(_.name))
+ _ <- client.resolveInteraction(recipeInstanceId, "ReserveItems", resolutionEvent)
+ state2data <- client.getRecipeInstanceState(recipeInstanceId)
+ state2 = state2data.events.map(_.name)
+ eventState = state2data.ingredients.get("reservedItems").map(_.as[ReservedItems].items.head.itemId)
+ } yield {
+ state1 should contain("OrderPlaced")
+ state1 should not contain("ItemsReserved")
+ state2 should contain("OrderPlaced")
+ state2 should contain("ItemsReserved")
+ eventState shouldBe Some("item1")
+ events.toList.map(_.name) should contain("OrderPlaced")
+ events.toList.map(_.name) should not contain("ItemsReserved") // Manually resolving an interaction does not fire the event to the listeners?
+ }
+ }
+ }
+
+ it("Baker.stopRetryingInteraction") {
+ test { (client, _, interactionNode, eventListenerNode) =>
+ val recipeInstanceId: String = UUID.randomUUID().toString
+ val event = EventInstance.unsafeFrom(
+ CheckoutFlowEvents.OrderPlaced(orderId = OrderId("order1"), List.empty))
+ for {
+ compiledRecipe <- setupFailingWithRetryReserveItems(interactionNode)
+ events <- setupEventListener(compiledRecipe, eventListenerNode)
+ recipeId <- client.addRecipe(compiledRecipe)
+ _ <- client.bake(recipeId, recipeInstanceId)
+ _ <- client.fireEventAndResolveWhenReceived(recipeInstanceId, event)
+ state1 <- client.getRecipeInstanceState(recipeInstanceId).map(_.events.map(_.name))
+ _ <- client.stopRetryingInteraction(recipeInstanceId, "ReserveItems")
+ state2data <- client.getRecipeInstanceState(recipeInstanceId)
+ state2 = state2data.events.map(_.name)
+ } yield {
+ state1 should contain("OrderPlaced")
+ state1 should not contain("ItemsReserved")
+ state2 should contain("OrderPlaced")
+ state2 should not contain("ItemsReserved")
+ events.toList.map(_.name) should contain("OrderPlaced")
+ events.toList.map(_.name) should not contain("ItemsReserved")
+ }
+ }
+ }
+ }
+}
+
+object BaaSIntegrationSpec {
+
+ def setupHappyPath(interactionNode: BaaSInteractionInstance)(implicit ec: ExecutionContext, timer: Timer[IO]): Future[CompiledRecipe] = {
+ val makePaymentInstance = InteractionInstance.unsafeFrom(new MakePaymentInstance())
+ val reserveItemsInstance = InteractionInstance.unsafeFrom(new ReserveItemsInstance())
+ val shipItemsInstance = InteractionInstance.unsafeFrom(new ShipItemsInstance())
+ val compiledRecipe = RecipeCompiler.compileRecipe(CheckoutFlowRecipe.recipe)
+ for {
+ _ <- Future { interactionNode.load(makePaymentInstance, reserveItemsInstance, shipItemsInstance) }
+ } yield compiledRecipe
+ }
+
+ def setupFailingOnceReserveItems(interactionNode: BaaSInteractionInstance)(implicit ec: ExecutionContext, timer: Timer[IO]): Future[CompiledRecipe] = {
+ val makePaymentInstance = InteractionInstance.unsafeFrom(new MakePaymentInstance())
+ val reserveItemsInstance = InteractionInstance.unsafeFrom(new FailingOnceReserveItemsInstance())
+ val shipItemsInstance = InteractionInstance.unsafeFrom(new ShipItemsInstance())
+ val compiledRecipe = RecipeCompiler.compileRecipe(CheckoutFlowRecipe.recipeWithBlockingStrategy)
+ for {
+ _ <- Future { interactionNode.load(makePaymentInstance, reserveItemsInstance, shipItemsInstance) }
+ } yield compiledRecipe
+ }
+
+ def setupFailingWithRetryReserveItems(interactionNode: BaaSInteractionInstance)(implicit ec: ExecutionContext, timer: Timer[IO]): Future[CompiledRecipe] = {
+ val makePaymentInstance = InteractionInstance.unsafeFrom(new MakePaymentInstance())
+ val reserveItemsInstance = InteractionInstance.unsafeFrom(new FailingReserveItemsInstance())
+ val shipItemsInstance = InteractionInstance.unsafeFrom(new ShipItemsInstance())
+ val compiledRecipe = RecipeCompiler.compileRecipe(CheckoutFlowRecipe.recipe)
+ for {
+ _ <- Future { interactionNode.load(makePaymentInstance, reserveItemsInstance, shipItemsInstance) }
+ } yield compiledRecipe
+ }
+
+ def setupEventListener(recipe: CompiledRecipe, eventListenerNode: BaaSEventListener)(implicit ec: ExecutionContext): Future[mutable.MutableList[EventInstance]] = {
+ val buffer = mutable.MutableList.empty[EventInstance]
+ eventListenerNode.registerEventListener(recipe.name, (_, event) => {
+ buffer.+=(event)
+ }).map(_ => buffer)
+ }
+
+ type IntegrationTest = ((ScalaBaker, ScalaBaker, BaaSInteractionInstance, BaaSEventListener) => Future[Assertion]) => Future[Assertion]
+
+ type WithOpenPort[A] = StateT[Future, Stream[Int], A]
+
+ def testWith[F[_], Lang <: LanguageApi]
+ (test: (ScalaBaker, ScalaBaker, BaaSInteractionInstance, BaaSEventListener) => Future[Assertion])
+ (implicit ec: ExecutionContext): Future[Assertion] = {
+ val testId: UUID = UUID.randomUUID()
+ val systemName: String = "BaaSIntegrationSpec-" + testId
+ val allPorts: Stream[Int] = Stream.from(50000, 1)
+ val program = for {
+ clusterTuple <- buildClusterActorSystem(systemName, seedPortCandidate = 0)
+ (stateNodeSystem, serverConfig) = clusterTuple
+ materializer = ActorMaterializer()(stateNodeSystem)
+ stateNodeBaker = AkkaBaker(serverConfig, stateNodeSystem)
+ httpPortAndBinding <- runStateNodeHttpServer(stateNodeBaker, stateNodeSystem, materializer)
+ (httpPort, httpServerBinding) = httpPortAndBinding
+ clientBaker = BakerClient.build(s"http://localhost:$httpPort/", Encryption.NoEncryption)(stateNodeSystem, materializer)
+ interactionNode = BaaSInteractionInstance(stateNodeSystem)
+ eventListenerNode = BaaSEventListener(stateNodeSystem)
+ a <- liftF(test(clientBaker, stateNodeBaker, interactionNode, eventListenerNode))
+ _ <- liftF(httpServerBinding.unbind())
+ _ <- liftF(stateNodeBaker.gracefulShutdown())
+ } yield a
+ program.run(allPorts).map(_._2)
+ }
+
+ private def buildClusterActorSystem(systemName: String, seedPortCandidate: Int)(implicit ec: ExecutionContext): WithOpenPort[(ActorSystem, Config)] =
+ withOpenPort { port =>
+ val config = genClusterConfig(systemName, port, seedPortCandidate)
+ Future { (ActorSystem(systemName, config), config) }
+ }
+
+ private def runStateNodeHttpServer(stateNodeBaker: ScalaBaker, stateNodeSystem: ActorSystem, materializer: Materializer)(implicit ec: ExecutionContext): WithOpenPort[(Int, Http.ServerBinding)] =
+ withOpenPort(port => BaaSServer.run(stateNodeBaker, "localhost", port)(stateNodeSystem, materializer).map(port -> _))
+
+ private def withOpenPort[T](f: Int => Future[T])(implicit ec: ExecutionContext): WithOpenPort[T] = {
+ def search(ports: Stream[Int]): Future[(Stream[Int], T)] =
+ ports match {
+ case #::(port, tail) => f(port).map(tail -> _).recoverWith {
+ case _: java.net.BindException => search(tail)
+ case _: ChannelException => search(tail)
+ case other => println("REVIEW withOpenPort function implementation, uncaught exception: " + Console.RED + other + Console.RESET); Future.failed(other)
+ }
+ }
+ StateT(search)
+ }
+
+ private def liftF[A](fa: Future[A])(implicit ec: ExecutionContext): WithOpenPort[A] =
+ StateT.liftF[Future, Stream[Int], A](fa)
+
+ private def genClusterConfig(systemName: String, port: Int, seedPortCandidate: Int): Config = {
+ val seedPort: Int = if(seedPortCandidate == 0) port else seedPortCandidate
+ ConfigFactory.parseString(
+ s"""
+ |baker {
+ | cluster {
+ | seed-nodes = [
+ | "akka.tcp://"$systemName"@localhost:"$seedPort]
+ | }
+ |}
+ |
+ |akka {
+ |
+ | remote {
+ | log-remote-lifecycle-events = off
+ | netty.tcp {
+ | hostname = "localhost"
+ | port = $port
+ | }
+ | }
+ |
+ | cluster {
+ |
+ | seed-nodes = [
+ | "akka.tcp://"$systemName"@localhost:"$seedPort]
+ |
+ | # auto downing is NOT safe for production deployments.
+ | # you may want to use it during development, read more about it in the akka docs.
+ | auto-down-unreachable-after = 10s
+ | }
+ |}
+ |""".stripMargin).withFallback(ConfigFactory.load())
+ }
+}
\ No newline at end of file
diff --git a/baas/src/main/protobuf/baas.proto b/baas/src/main/protobuf/baas.proto
deleted file mode 100644
index 97400fc0a..000000000
--- a/baas/src/main/protobuf/baas.proto
+++ /dev/null
@@ -1,67 +0,0 @@
-syntax = "proto2";
-
-import "scalapb/scalapb.proto";
-import "common.proto";
-
-option java_package = "com.ing.baker.runtime.baas.protobuf";
-option (scalapb.options) = {
- flat_package: true
-};
-
-message AddInteractionHTTPRequest {
- optional string name = 1;
- optional string uri = 2;
- repeated Type input = 3;
-}
-
-message AddInteractionHTTPResponse {
- optional string message = 1;
-}
-
-message AddRecipeRequest {
- optional CompiledRecipe compiledRecipe = 1;
-}
-
-message AddRecipeResponse {
- optional string recipeId = 1;
-}
-
-message BakeRequest {
- optional string recipeId= 1;
-}
-
-message BakeResponse {
- optional ProcessState processState= 1;
-}
-
-message EventsResponse {
- repeated RuntimeEvent runtimeEvent = 1;
-}
-
-message IngredientsResponse {
- map ingredients = 1;
-}
-
-message ProcessEventRequest {
- optional RuntimeEvent runtimeEvent = 1;
-}
-
-message ProcessEventResponse {
- optional SensoryEventStatus sensoryEventStatus = 1;
-}
-
-message StateResponse {
- optional ProcessState processState= 1;
-}
-
-message VisualStateResponse {
- optional string VisualStateResponse = 1;
-}
-
-message ExecuteInteractionHTTPRequest {
- repeated Ingredient ingredient = 1;
-}
-
-message ExecuteInteractionHTTPResponse {
- optional RuntimeEvent runtimeEvent = 1;
-}
\ No newline at end of file
diff --git a/baas/src/main/resources/reference.conf b/baas/src/main/resources/reference.conf
deleted file mode 100644
index b4faba05f..000000000
--- a/baas/src/main/resources/reference.conf
+++ /dev/null
@@ -1,20 +0,0 @@
-baker.engine.baas {
- client-host = "localhost"
- client-port = 8081
- baas-host = "localhost"
- baas-port = 8091
-}
-
-akka {
- actor {
- serializers {
- baas-protobuf = "com.ing.baker.baas.serialization.BaasProtobufSerializer"
- }
-
- serialization-bindings {
- // map baker classes to use protobuf serialization
- "com.ing.baker.baas.server.protocol.BaasRequest" = baas-protobuf
- "com.ing.baker.baas.server.protocol.BaasResponse" = baas-protobuf
- }
- }
-}
\ No newline at end of file
diff --git a/baas/src/test/resources/application.conf b/baas/src/test/resources/application.conf
deleted file mode 100644
index 08bf154e7..000000000
--- a/baas/src/test/resources/application.conf
+++ /dev/null
@@ -1,42 +0,0 @@
-include "baker.conf"
-//include "cluster.conf"
-// include "cassandra.conf"
-
-baker {
- engine-provider = "com.ing.baker.baas.client.BaasBakerProvider"
- engine.baas {
- actor-system-name = "ActorSystemName"
- client-host = "localhost"
- client-port = 8091
- baas-host = "localhost"
- baas-port = 8081
- }
-}
-
-akka {
- log-config-on-start = off
- jvm-exit-on-fatal-error = false
- loglevel = "DEBUG"
- coordinated-shutdown.run-by-jvm-shutdown-hook = off
-
- // No need to see the java serialization warnings for the tests in this module
- actor.allow-java-serialization = on
- actor.warn-about-java-serializer-usage = off
-
-// actor.serialize-messages = on
- actor.serialize-creators = off
-
- test.timefactor = 4
-
- loggers = ["akka.event.slf4j.Slf4jLogger"]
- loglevel = "DEBUG"
- logging-filter = "akka.event.slf4j.Slf4jLoggingFilter"
-}
-
-inmemory-read-journal {
- write-plugin = "inmemory-journal"
- offset-mode = "sequence"
- ask-timeout = "10s"
- refresh-interval = "50ms"
- max-buffer-size = "100"
-}
diff --git a/baas/src/test/resources/cassandra.conf b/baas/src/test/resources/cassandra.conf
deleted file mode 100644
index ae18df370..000000000
--- a/baas/src/test/resources/cassandra.conf
+++ /dev/null
@@ -1,15 +0,0 @@
-akka.persistence.journal.plugin = "cassandra-journal"
-akka.persistence.snapshot-store.plugin = "cassandra-snapshot-store"
-
-baker.actor.read-journal-plugin = "cassandra-query-journal"
-baker.journal-initialize-timeout = 30 seconds
-
-cassandra-config = {
- keyspace-autocreate = true
- tables-autocreate = true
- keyspace = baas
- cassandra-2x-compat = on
-}
-
-cassandra-journal = ${cassandra-config}
-cassandra-snapshot-store = ${cassandra-config}
\ No newline at end of file
diff --git a/baas/src/test/resources/cluster.conf b/baas/src/test/resources/cluster.conf
deleted file mode 100644
index c69da64b4..000000000
--- a/baas/src/test/resources/cluster.conf
+++ /dev/null
@@ -1,34 +0,0 @@
-akka {
- actor.provider = "akka.cluster.ClusterActorRefProvider"
-
- remote {
- maximum-payload-bytes = 10000000 bytes
- netty.tcp {
- hostname = "127.0.0.1"
- port = 2552
- message-frame-size = 10000000b
- send-buffer-size = 10000000b
- receive-buffer-size = 10000000b
- maximum-frame-size = 10000000b
- }
- }
-
- cluster {
-
- seed-nodes = [
- "akka.tcp://BAASAPIActorSystem@127.0.0.1:2552"
- ]
-
- sharding {
- least-shard-allocation-strategy.rebalance-threshold = 5
- remember-entities = on
- }
-
-// http.management {
-// hostname = "127.0.0.1"
-// port = 19999
-// }
- }
-}
-
-baker.actor.provider = "cluster-sharded"
diff --git a/baas/src/test/resources/logback.xml b/baas/src/test/resources/logback.xml
deleted file mode 100644
index 03c45b50f..000000000
--- a/baas/src/test/resources/logback.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
-
- %d{ISO8601} [%thread] [%X{recipeInstanceId}] %-5level %logger{36} - %msg%n
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/runtime/src/main/protobuf/common.proto b/baker-interface/src/main/protobuf/common.proto
similarity index 92%
rename from runtime/src/main/protobuf/common.proto
rename to baker-interface/src/main/protobuf/common.proto
index 6b86bd0b8..04fccf804 100644
--- a/runtime/src/main/protobuf/common.proto
+++ b/baker-interface/src/main/protobuf/common.proto
@@ -7,6 +7,14 @@ option (scalapb.options) = {
flat_package: true
};
+// other
+
+message RecipeInformation {
+ optional CompiledRecipe compiledRecipe = 1;
+ optional int64 recipeCreatedTime = 2;
+ repeated string errors = 3;
+}
+
// wrapper object for 'any' data
message SerializedData {
optional int32 serializer_id = 1;
@@ -144,6 +152,11 @@ message EventMoment {
optional int64 occurredOn = 2;
}
+message RecipeInstanceMetadata {
+ optional string recipeId = 1;
+ optional string recipeInstanceId = 2;
+ optional int64 createdTime = 3;
+}
message ProcessState {
optional string recipeInstanceId = 1;
@@ -157,6 +170,12 @@ message SensoryEventResult {
map ingredients = 3;
}
+message RecipeEventMetadata {
+ optional string recipeId = 1;
+ optional string recipeName = 2;
+ optional string recipeInstanceId = 3;
+}
+
enum SensoryEventStatus {
RECEIVED = 1;
COMPLETED = 2;
@@ -165,6 +184,11 @@ enum SensoryEventStatus {
ALREADY_RECEIVED = 5;
PROCESS_DELETED = 6;
}
+
+message BakerException {
+ optional string message = 1;
+ optional int32 enum = 2;
+}
// END DATA
// DESCRIPTORS (Intermediate Language messages)
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/common/Baker.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/common/Baker.scala
similarity index 98%
rename from runtime/src/main/scala/com/ing/baker/runtime/common/Baker.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/common/Baker.scala
index db80f412a..98fa9dd5c 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/common/Baker.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/common/Baker.scala
@@ -30,6 +30,8 @@ trait Baker[F[_]] extends LanguageApi {
type EventMomentType <: EventMoment { type Language <: self.Language}
+ type RecipeMetadataType <: RecipeEventMetadata { type Language <: self.Language }
+
/**
* Adds a recipe to baker and returns a recipeId for the recipe.
*
@@ -279,14 +281,14 @@ trait Baker[F[_]] extends LanguageApi {
*
* Note that the delivery guarantee is *AT MOST ONCE*. Do not use it for critical functionality
*/
- def registerEventListener(recipeName: String, listenerFunction: language.BiConsumerFunction[String, EventInstanceType]): F[Unit]
+ def registerEventListener(recipeName: String, listenerFunction: language.BiConsumerFunction[RecipeMetadataType, EventInstanceType]): F[Unit]
/**
* Registers a listener to all runtime events for all recipes that run in this Baker instance.
*
* Note that the delivery guarantee is *AT MOST ONCE*. Do not use it for critical functionality
*/
- def registerEventListener(listenerFunction: language.BiConsumerFunction[String, EventInstanceType]): F[Unit]
+ def registerEventListener(listenerFunction: language.BiConsumerFunction[RecipeMetadataType, EventInstanceType]): F[Unit]
/**
* Registers a listener function that listens to all BakerEvents
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/common/BakerEvent.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/common/BakerEvent.scala
similarity index 94%
rename from runtime/src/main/scala/com/ing/baker/runtime/common/BakerEvent.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/common/BakerEvent.scala
index 81433b2e0..f98132191 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/common/BakerEvent.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/common/BakerEvent.scala
@@ -1,12 +1,11 @@
package com.ing.baker.runtime.common
-import akka.actor.NoSerializationVerificationNeeded
import com.ing.baker.il.CompiledRecipe
import com.ing.baker.il.failurestrategy.ExceptionStrategyOutcome
import com.ing.baker.runtime.common.LanguageDataStructures.LanguageApi
// TODO: rename subtypes of BakerEvent to resamble the new names
-trait BakerEvent extends LanguageApi with NoSerializationVerificationNeeded {
+trait BakerEvent extends LanguageApi {
self =>
type Event <: EventInstance {type Language <: self.Language}
}
diff --git a/baker-interface/src/main/scala/com/ing/baker/runtime/common/BakerException.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/common/BakerException.scala
new file mode 100644
index 000000000..957bff926
--- /dev/null
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/common/BakerException.scala
@@ -0,0 +1,56 @@
+package com.ing.baker.runtime.common
+
+import scala.util.{Failure, Success, Try}
+
+sealed abstract class BakerException(val message: String = "An exception occurred at Baker", val enum: Int, val cause: Throwable = null)
+ extends RuntimeException(message, cause)
+
+object BakerException {
+
+ // TODO this has to be renamed to NoSuchRecipeInstanceException
+ case class NoSuchProcessException(recipeInstanceId: String)
+ extends BakerException(s"Recipe instance $recipeInstanceId does not exist in the index", 1)
+
+ // TODO this has to be renamed to RecipeInstanceDeletedException
+ case class ProcessDeletedException(recipeInstanceId: String)
+ extends BakerException(s"Recipe instance $recipeInstanceId is deleted", 2)
+
+ case class RecipeValidationException(validationErrors: String)
+ extends BakerException(validationErrors, 3)
+
+ case class ImplementationsException(implementationErrors: String)
+ extends BakerException(implementationErrors, 4)
+
+ case class NoSuchRecipeException(recipeId: String)
+ extends BakerException(s"No recipe found for recipe with id: $recipeId", 5)
+
+ // TODO this has to be renamed to RecipeInstanceAlreadyExistsException
+ case class ProcessAlreadyExistsException(recipeInstanceId: String)
+ extends BakerException(s"Process '$recipeInstanceId' already exists.", 6)
+
+ case class IllegalEventException(reason: String)
+ extends BakerException(reason, 7)
+
+ def encode(bakerException: BakerException): (String, Int) =
+ bakerException match {
+ case e @ NoSuchProcessException(recipeInstanceId) => (recipeInstanceId, e.enum)
+ case e @ ProcessDeletedException(recipeInstanceId) => (recipeInstanceId, e.enum)
+ case e @ RecipeValidationException(validationErrors) => (validationErrors, e.enum)
+ case e @ ImplementationsException(implementationErrors) => (implementationErrors, e.enum)
+ case e @ NoSuchRecipeException(recipeId) => (recipeId, e.enum)
+ case e @ ProcessAlreadyExistsException(recipeInstanceId) => (recipeInstanceId, e.enum)
+ case e @ IllegalEventException(reason) => (reason, e.enum)
+ }
+
+ def decode(message: String, enum: Int): Try[BakerException] =
+ enum match {
+ case 1 => Success(NoSuchProcessException(message))
+ case 2 => Success(ProcessDeletedException(message))
+ case 3 => Success(RecipeValidationException(message))
+ case 4 => Success(ImplementationsException(message))
+ case 5 => Success(NoSuchRecipeException(message))
+ case 6 => Success(ProcessAlreadyExistsException(message))
+ case 7 => Success(IllegalEventException(message))
+ case _ => Failure(new IllegalArgumentException(s"No BakerException with enum flag $enum"))
+ }
+}
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/common/EventInstance.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/common/EventInstance.scala
similarity index 100%
rename from runtime/src/main/scala/com/ing/baker/runtime/common/EventInstance.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/common/EventInstance.scala
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/common/EventMoment.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/common/EventMoment.scala
similarity index 100%
rename from runtime/src/main/scala/com/ing/baker/runtime/common/EventMoment.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/common/EventMoment.scala
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/common/EventResolutions.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/common/EventResolutions.scala
similarity index 100%
rename from runtime/src/main/scala/com/ing/baker/runtime/common/EventResolutions.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/common/EventResolutions.scala
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/common/IngredientInstance.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/common/IngredientInstance.scala
similarity index 100%
rename from runtime/src/main/scala/com/ing/baker/runtime/common/IngredientInstance.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/common/IngredientInstance.scala
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/common/InteractionInstance.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/common/InteractionInstance.scala
similarity index 100%
rename from runtime/src/main/scala/com/ing/baker/runtime/common/InteractionInstance.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/common/InteractionInstance.scala
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/common/LanguageDataStructures.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/common/LanguageDataStructures.scala
similarity index 97%
rename from runtime/src/main/scala/com/ing/baker/runtime/common/LanguageDataStructures.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/common/LanguageDataStructures.scala
index 355fb766d..03fe3eb53 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/common/LanguageDataStructures.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/common/LanguageDataStructures.scala
@@ -1,7 +1,5 @@
package com.ing.baker.runtime.common
-import java.util.Optional
-
sealed trait LanguageDataStructures {
type Map[A, B]
diff --git a/baker-interface/src/main/scala/com/ing/baker/runtime/common/RecipeEventMetadata.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/common/RecipeEventMetadata.scala
new file mode 100644
index 000000000..34f5b1f4c
--- /dev/null
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/common/RecipeEventMetadata.scala
@@ -0,0 +1,13 @@
+package com.ing.baker.runtime.common
+
+import com.ing.baker.runtime.common.LanguageDataStructures.LanguageApi
+
+trait RecipeEventMetadata extends LanguageApi {
+
+ def recipeId: String
+
+ def recipeName: String
+
+ def recipeInstanceId: String
+
+}
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/common/RecipeInformation.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/common/RecipeInformation.scala
similarity index 100%
rename from runtime/src/main/scala/com/ing/baker/runtime/common/RecipeInformation.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/common/RecipeInformation.scala
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/common/RecipeInstanceMetadata.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/common/RecipeInstanceMetadata.scala
similarity index 100%
rename from runtime/src/main/scala/com/ing/baker/runtime/common/RecipeInstanceMetadata.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/common/RecipeInstanceMetadata.scala
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/common/RecipeInstanceState.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/common/RecipeInstanceState.scala
similarity index 100%
rename from runtime/src/main/scala/com/ing/baker/runtime/common/RecipeInstanceState.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/common/RecipeInstanceState.scala
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/common/RejectReason.java b/baker-interface/src/main/scala/com/ing/baker/runtime/common/RejectReason.java
similarity index 100%
rename from runtime/src/main/scala/com/ing/baker/runtime/common/RejectReason.java
rename to baker-interface/src/main/scala/com/ing/baker/runtime/common/RejectReason.java
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/common/SensoryEventResult.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/common/SensoryEventResult.scala
similarity index 100%
rename from runtime/src/main/scala/com/ing/baker/runtime/common/SensoryEventResult.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/common/SensoryEventResult.scala
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/common/SensoryEventStatus.java b/baker-interface/src/main/scala/com/ing/baker/runtime/common/SensoryEventStatus.java
similarity index 100%
rename from runtime/src/main/scala/com/ing/baker/runtime/common/SensoryEventStatus.java
rename to baker-interface/src/main/scala/com/ing/baker/runtime/common/SensoryEventStatus.java
diff --git a/baker-interface/src/main/scala/com/ing/baker/runtime/common/package.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/common/package.scala
new file mode 100644
index 000000000..2532bca51
--- /dev/null
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/common/package.scala
@@ -0,0 +1,28 @@
+package com.ing.baker.runtime
+
+package object common {
+
+ /**
+ * Mockito breaks reflection when mocking classes, for example:
+ *
+ * interface A { }
+ * class B extends A
+ * val b = mock[B]
+ *
+ * When inspecting b, the fact that it extends from A can no longer be reflected.
+ *
+ * Here we obtain the original class that was mocked.
+ *
+ * @param clazz The (potentially mocked) class
+ * @return The original class
+ */
+ private[runtime] def unmock(clazz: Class[_]) = {
+
+ if (clazz.getName.contains("$$EnhancerByMockitoWithCGLIB$$")) {
+ val originalName: String = clazz.getName.split("\\$\\$EnhancerByMockitoWithCGLIB\\$\\$")(0)
+ clazz.getClassLoader.loadClass(originalName)
+ } else
+ clazz
+ }
+
+}
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/javadsl/Baker.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/Baker.scala
similarity index 73%
rename from runtime/src/main/scala/com/ing/baker/runtime/javadsl/Baker.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/Baker.scala
index e31589c5d..58df4170d 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/javadsl/Baker.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/Baker.scala
@@ -1,46 +1,22 @@
package com.ing.baker.runtime.javadsl
-import akka.actor.{ ActorSystem, Address }
-import cats.data.NonEmptyList
-import com.ing.baker.il.{ CompiledRecipe, RecipeVisualStyle }
-import com.ing.baker.runtime.akka.{ AkkaBaker, _ }
-import com.ing.baker.runtime.common.LanguageDataStructures.JavaApi
-import com.ing.baker.runtime.common.SensoryEventStatus
-import com.ing.baker.runtime.{ common, scaladsl }
-import com.ing.baker.types.Value
-import com.typesafe.config.Config
import java.util
import java.util.Optional
import java.util.concurrent.CompletableFuture
-import java.util.function.{ BiConsumer, Consumer }
+import java.util.function.{BiConsumer, Consumer}
+
+import com.ing.baker.il.{CompiledRecipe, RecipeVisualStyle}
+import com.ing.baker.runtime.common.LanguageDataStructures.JavaApi
+import com.ing.baker.runtime.common.SensoryEventStatus
+import com.ing.baker.runtime.{common, scaladsl}
+import com.ing.baker.types.Value
import javax.annotation.Nonnull
+
import scala.collection.JavaConverters._
import scala.compat.java8.FutureConverters
import scala.concurrent.Future
-object Baker {
-
- def akkaLocalDefault(actorSystem: ActorSystem): Baker =
- new Baker(new AkkaBaker(AkkaBakerConfig.localDefault(actorSystem)))
-
- def akkaClusterDefault(seedNodes: java.util.List[Address], actorSystem: ActorSystem): Baker = {
- val nodes =
- if (seedNodes.isEmpty) throw new IllegalStateException("Baker cluster configuration without baker.cluster.seed-nodes")
- else NonEmptyList.fromListUnsafe(seedNodes.asScala.toList)
- new Baker(new AkkaBaker(AkkaBakerConfig.clusterDefault(nodes, actorSystem)))
- }
-
- def akka(config: AkkaBakerConfig): Baker =
- new Baker(scaladsl.Baker.akka(config))
-
- def akka(config: Config, actorSystem: ActorSystem): Baker =
- new Baker(scaladsl.Baker.akka(config, actorSystem))
-
- def other(baker: scaladsl.Baker) =
- new Baker(baker)
-}
-
-class Baker private(private val baker: scaladsl.Baker) extends common.Baker[CompletableFuture] with JavaApi {
+class Baker private[baker](private val baker: scaladsl.Baker) extends common.Baker[CompletableFuture] with JavaApi {
override type SensoryEventResultType = SensoryEventResult
@@ -60,6 +36,8 @@ class Baker private(private val baker: scaladsl.Baker) extends common.Baker[Comp
override type EventMomentType = EventMoment
+ override type RecipeMetadataType = RecipeEventMetadata
+
/**
* Adds a recipe to baker and returns a recipeId for the recipe.
*
@@ -102,57 +80,57 @@ class Baker private(private val baker: scaladsl.Baker) extends common.Baker[Comp
def bake(@Nonnull recipeId: String, @Nonnull recipeInstanceId: String): CompletableFuture[Unit] =
toCompletableFuture(baker.bake(recipeId, recipeInstanceId))
- def fireEventAndResolveWhenReceived(recipeInstanceId: String, event: EventInstance, correlationId: String): CompletableFuture[SensoryEventStatus] =
+ def fireEventAndResolveWhenReceived(@Nonnull recipeInstanceId: String, @Nonnull event: EventInstance, @Nonnull correlationId: String): CompletableFuture[SensoryEventStatus] =
fireEventAndResolveWhenReceived(recipeInstanceId, event, Optional.of(correlationId))
- def fireEventAndResolveWhenCompleted(recipeInstanceId: String, event: EventInstance, correlationId: String): CompletableFuture[SensoryEventResult] =
+ def fireEventAndResolveWhenCompleted(@Nonnull recipeInstanceId: String, @Nonnull event: EventInstance, @Nonnull correlationId: String): CompletableFuture[SensoryEventResult] =
fireEventAndResolveWhenCompleted(recipeInstanceId, event, Optional.of(correlationId))
- def fireEventAndResolveOnEvent(recipeInstanceId: String, event: EventInstance, onEvent: String, correlationId: String): CompletableFuture[SensoryEventResult] =
+ def fireEventAndResolveOnEvent(@Nonnull recipeInstanceId: String, @Nonnull event: EventInstance, @Nonnull onEvent: String, @Nonnull correlationId: String): CompletableFuture[SensoryEventResult] =
fireEventAndResolveOnEvent(recipeInstanceId, event, onEvent, Optional.of(correlationId))
- def fireEvent(recipeInstanceId: String, event: EventInstance, correlationId: String): EventResolutions =
+ def fireEvent(@Nonnull recipeInstanceId: String, @Nonnull event: EventInstance, @Nonnull correlationId: String): EventResolutions =
fireEvent(recipeInstanceId, event, Optional.of(correlationId))
- def fireEventAndResolveWhenReceived(recipeInstanceId: String, event: EventInstance): CompletableFuture[SensoryEventStatus] =
+ def fireEventAndResolveWhenReceived(@Nonnull recipeInstanceId: String, @Nonnull event: EventInstance): CompletableFuture[SensoryEventStatus] =
fireEventAndResolveWhenReceived(recipeInstanceId, event, Optional.empty[String]())
- def fireEventAndResolveWhenCompleted(recipeInstanceId: String, event: EventInstance): CompletableFuture[SensoryEventResult] =
+ def fireEventAndResolveWhenCompleted(@Nonnull recipeInstanceId: String, @Nonnull event: EventInstance): CompletableFuture[SensoryEventResult] =
fireEventAndResolveWhenCompleted(recipeInstanceId, event, Optional.empty[String]())
- def fireEventAndResolveOnEvent(recipeInstanceId: String, event: EventInstance, onEvent: String): CompletableFuture[SensoryEventResult] =
+ def fireEventAndResolveOnEvent(@Nonnull recipeInstanceId: String, @Nonnull event: EventInstance, @Nonnull onEvent: String): CompletableFuture[SensoryEventResult] =
fireEventAndResolveOnEvent(recipeInstanceId, event, onEvent, Optional.empty[String]())
- def fireEvent(recipeInstanceId: String, event: EventInstance): EventResolutions =
+ def fireEvent(@Nonnull recipeInstanceId: String, @Nonnull event: EventInstance): EventResolutions =
fireEvent(recipeInstanceId, event, Optional.empty[String]())
- def fireEventAndResolveWhenReceived(recipeInstanceId: String, event: EventInstance, correlationId: Optional[String]): CompletableFuture[SensoryEventStatus] =
+ def fireEventAndResolveWhenReceived(@Nonnull recipeInstanceId: String, @Nonnull event: EventInstance, @Nonnull correlationId: Optional[String]): CompletableFuture[SensoryEventStatus] =
toCompletableFuture(baker.fireEventAndResolveWhenReceived(recipeInstanceId, event.asScala, Option.apply(correlationId.orElse(null))))
- def fireEventAndResolveWhenCompleted(recipeInstanceId: String, event: EventInstance, correlationId: Optional[String]): CompletableFuture[SensoryEventResult] =
+ def fireEventAndResolveWhenCompleted(@Nonnull recipeInstanceId: String, @Nonnull event: EventInstance, @Nonnull correlationId: Optional[String]): CompletableFuture[SensoryEventResult] =
toCompletableFuture(baker.fireEventAndResolveWhenCompleted(recipeInstanceId, event.asScala, Option.apply(correlationId.orElse(null)))).thenApply { result =>
- new SensoryEventResult(
+ SensoryEventResult(
sensoryEventStatus = result.sensoryEventStatus,
eventNames = result.eventNames.asJava,
ingredients = result.ingredients.asJava
)
}
- def fireEventAndResolveOnEvent(recipeInstanceId: String, event: EventInstance, onEvent: String, correlationId: Optional[String]): CompletableFuture[SensoryEventResult] =
+ def fireEventAndResolveOnEvent(@Nonnull recipeInstanceId: String, @Nonnull event: EventInstance, @Nonnull onEvent: String, @Nonnull correlationId: Optional[String]): CompletableFuture[SensoryEventResult] =
toCompletableFuture(baker.fireEventAndResolveOnEvent(recipeInstanceId, event.asScala, onEvent, Option.apply(correlationId.orElse(null)))).thenApply { result =>
- new SensoryEventResult(
+ SensoryEventResult(
sensoryEventStatus = result.sensoryEventStatus,
eventNames = result.eventNames.asJava,
ingredients = result.ingredients.asJava
)
}
- def fireEvent(recipeInstanceId: String, event: EventInstance, correlationId: Optional[String]): EventResolutions = {
+ def fireEvent(@Nonnull recipeInstanceId: String, @Nonnull event: EventInstance, @Nonnull correlationId: Optional[String]): EventResolutions = {
val scalaResult = baker.fireEvent(recipeInstanceId, event.asScala)
- new EventResolutions(
+ EventResolutions(
resolveWhenReceived = toCompletableFuture(scalaResult.resolveWhenReceived),
resolveWhenCompleted = toCompletableFuture(scalaResult.resolveWhenCompleted).thenApply { result =>
- new SensoryEventResult(
+ SensoryEventResult(
sensoryEventStatus = result.sensoryEventStatus,
eventNames = result.eventNames.asJava,
ingredients = result.ingredients.asJava
@@ -278,10 +256,9 @@ class Baker private(private val baker: scaladsl.Baker) extends common.Baker[Comp
* @param recipeName the name of all recipes this event listener should be triggered for
* @param listenerFunction The listener to subscribe to events.
*/
- override def registerEventListener(@Nonnull recipeName: String, @Nonnull listenerFunction: BiConsumer[String, EventInstance]): CompletableFuture[Unit] =
+ override def registerEventListener(@Nonnull recipeName: String, @Nonnull listenerFunction: BiConsumer[RecipeEventMetadata, EventInstance]): CompletableFuture[Unit] =
toCompletableFuture(baker.registerEventListener(recipeName,
- (recipeInstanceId: String, event: scaladsl.EventInstance) => listenerFunction.accept(recipeInstanceId, event.asJava)))
-
+ (recipeEventMetadata: scaladsl.RecipeEventMetadata, event: scaladsl.EventInstance) => listenerFunction.accept(recipeEventMetadata.asJava, event.asJava)))
/**
* Registers a listener function to all runtime events for this baker instance.
@@ -300,10 +277,9 @@ class Baker private(private val baker: scaladsl.Baker) extends common.Baker[Comp
*
* @param listenerFunction The listener function that is called once these events occur
*/
- override def registerEventListener(listenerFunction: BiConsumer[String, EventInstance]): CompletableFuture[Unit] =
+ override def registerEventListener(@Nonnull listenerFunction: BiConsumer[RecipeEventMetadata, EventInstance]): CompletableFuture[Unit] =
toCompletableFuture(baker.registerEventListener(
- (recipeInstanceId: String, event: scaladsl.EventInstance) => listenerFunction.accept(recipeInstanceId, event.asJava)))
-
+ (recipeEventMetadata: scaladsl.RecipeEventMetadata, event: scaladsl.EventInstance) => listenerFunction.accept(recipeEventMetadata.asJava, event.asJava)))
/**
* Registers a listener function to all runtime events for this baker instance.
@@ -323,9 +299,8 @@ class Baker private(private val baker: scaladsl.Baker) extends common.Baker[Comp
* @param eventListener The EventListener class the processEvent will be called once these events occur
*/
@deprecated(message = "Replaced with the consumer function variant", since = "3.0.0")
- def registerEventListener(eventListener: EventListener): Future[Unit] =
- baker.registerEventListener((recipeInstanceId: String, runtimeEvent: scaladsl.EventInstance) => eventListener.processEvent(recipeInstanceId, runtimeEvent.asJava))
-
+ def registerEventListener(@Nonnull eventListener: EventListener): Future[Unit] =
+ baker.registerEventListener((recipeEventMetadata: scaladsl.RecipeEventMetadata, runtimeEvent: scaladsl.EventInstance) => eventListener.processEvent(recipeEventMetadata.recipeInstanceId, runtimeEvent.asJava))
/**
* Registers a listener that listens to all Baker events
@@ -333,7 +308,7 @@ class Baker private(private val baker: scaladsl.Baker) extends common.Baker[Comp
* @param listenerFunction
* @return
*/
- override def registerBakerEventListener(listenerFunction: Consumer[BakerEvent]): CompletableFuture[Unit] =
+ override def registerBakerEventListener(@Nonnull listenerFunction: Consumer[BakerEvent]): CompletableFuture[Unit] =
toCompletableFuture(baker.registerBakerEventListener((event: scaladsl.BakerEvent) => listenerFunction.accept(event.asJava())))
@@ -352,19 +327,13 @@ class Baker private(private val baker: scaladsl.Baker) extends common.Baker[Comp
* @param recipeInstanceId The process identifier
* @return
*/
- def getVisualState(@Nonnull recipeInstanceId: String, style: RecipeVisualStyle): CompletableFuture[String] =
+ def getVisualState(@Nonnull recipeInstanceId: String, @Nonnull style: RecipeVisualStyle): CompletableFuture[String] =
toCompletableFuture(baker.getVisualState(recipeInstanceId, style))
- private def toCompletableFuture[T](scalaFuture: Future[T]): CompletableFuture[T] =
+ private def toCompletableFuture[T](@Nonnull scalaFuture: Future[T]): CompletableFuture[T] =
FutureConverters.toJava(scalaFuture).toCompletableFuture
- private def toCompletableFutureSet[T](scalaFuture: Future[Set[T]]): CompletableFuture[java.util.Set[T]] =
- FutureConverters.toJava(
- scalaFuture)
- .toCompletableFuture
- .thenApply(_.asJava)
-
- private def toCompletableFutureMap[K, V](scalaFuture: Future[Map[K, V]]): CompletableFuture[java.util.Map[K, V]] =
+ private def toCompletableFutureMap[K, V](@Nonnull scalaFuture: Future[Map[K, V]]): CompletableFuture[java.util.Map[K, V]] =
FutureConverters.toJava(
scalaFuture)
.toCompletableFuture
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/javadsl/BakerEvent.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/BakerEvent.scala
similarity index 100%
rename from runtime/src/main/scala/com/ing/baker/runtime/javadsl/BakerEvent.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/BakerEvent.scala
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/javadsl/EventInstance.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/EventInstance.scala
similarity index 100%
rename from runtime/src/main/scala/com/ing/baker/runtime/javadsl/EventInstance.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/EventInstance.scala
index 850a5e1cc..d6f4f3840 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/javadsl/EventInstance.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/EventInstance.scala
@@ -2,9 +2,9 @@ package com.ing.baker.runtime.javadsl
import java.util
+import com.ing.baker.runtime.{common, scaladsl}
import com.ing.baker.il.EventDescriptor
import com.ing.baker.runtime.common.LanguageDataStructures.JavaApi
-import com.ing.baker.runtime.{common, scaladsl}
import com.ing.baker.types.Value
import scala.collection.JavaConverters._
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/javadsl/EventListener.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/EventListener.scala
similarity index 100%
rename from runtime/src/main/scala/com/ing/baker/runtime/javadsl/EventListener.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/EventListener.scala
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/javadsl/EventMoment.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/EventMoment.scala
similarity index 100%
rename from runtime/src/main/scala/com/ing/baker/runtime/javadsl/EventMoment.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/EventMoment.scala
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/javadsl/EventResolutions.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/EventResolutions.scala
similarity index 100%
rename from runtime/src/main/scala/com/ing/baker/runtime/javadsl/EventResolutions.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/EventResolutions.scala
index 9275cce24..456e8ab8b 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/javadsl/EventResolutions.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/EventResolutions.scala
@@ -2,9 +2,9 @@ package com.ing.baker.runtime.javadsl
import java.util.concurrent.CompletableFuture
-import com.ing.baker.runtime.common.SensoryEventStatus
import com.ing.baker.runtime.common
import com.ing.baker.runtime.common.LanguageDataStructures.JavaApi
+import com.ing.baker.runtime.common.SensoryEventStatus
case class EventResolutions(resolveWhenReceived: CompletableFuture[SensoryEventStatus],
resolveWhenCompleted: CompletableFuture[SensoryEventResult]
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/javadsl/IngredientInstance.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/IngredientInstance.scala
similarity index 84%
rename from runtime/src/main/scala/com/ing/baker/runtime/javadsl/IngredientInstance.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/IngredientInstance.scala
index 675694c73..b94fee297 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/javadsl/IngredientInstance.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/IngredientInstance.scala
@@ -1,8 +1,7 @@
package com.ing.baker.runtime.javadsl
-import com.ing.baker.runtime.scaladsl
-import com.ing.baker.runtime.common
import com.ing.baker.runtime.common.LanguageDataStructures.JavaApi
+import com.ing.baker.runtime.{common, scaladsl}
import com.ing.baker.types.Value
case class IngredientInstance(name: String, value: Value) extends common.IngredientInstance with JavaApi {
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/javadsl/InteractionInstance.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/InteractionInstance.scala
similarity index 95%
rename from runtime/src/main/scala/com/ing/baker/runtime/javadsl/InteractionInstance.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/InteractionInstance.scala
index 7a76866e5..3add46f5e 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/javadsl/InteractionInstance.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/InteractionInstance.scala
@@ -5,11 +5,9 @@ import java.util
import java.util.Optional
import java.util.concurrent.CompletableFuture
-import com.ing.baker.runtime.akka
-import com.ing.baker.runtime.scaladsl
-import com.ing.baker.runtime.common
import com.ing.baker.runtime.common.LanguageDataStructures.JavaApi
-import com.ing.baker.types.{Converters, Type, Value}
+import com.ing.baker.runtime.{common, scaladsl}
+import com.ing.baker.types.{Converters, Type}
import scala.collection.JavaConverters._
import scala.compat.java8.FutureConverters
@@ -54,7 +52,7 @@ object InteractionInstance {
new InteractionInstance {
val method: Method = {
- val unmockedClass = akka.unmock(implementation.getClass)
+ val unmockedClass = common.unmock(implementation.getClass)
unmockedClass.getMethods.count(_.getName == "apply") match {
case 0 => throw new IllegalArgumentException("Implementation does not have a apply function")
case n if n > 1 => throw new IllegalArgumentException("Implementation has multiple apply functions")
diff --git a/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/RecipeEventMetadata.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/RecipeEventMetadata.scala
new file mode 100644
index 000000000..8dd1b5c55
--- /dev/null
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/RecipeEventMetadata.scala
@@ -0,0 +1,21 @@
+package com.ing.baker.runtime.javadsl
+
+import com.ing.baker.runtime.common
+import com.ing.baker.runtime.scaladsl
+import com.ing.baker.runtime.common.LanguageDataStructures.JavaApi
+
+case class RecipeEventMetadata(recipeId: String, recipeName: String, recipeInstanceId: String) extends common.RecipeEventMetadata with JavaApi {
+
+ def getRecipeId: String = recipeId
+
+ def getRecipeName: String = recipeName
+
+ def getRecipeInstanceId: String = recipeInstanceId
+
+ def asScala: scaladsl.RecipeEventMetadata =
+ scaladsl.RecipeEventMetadata(
+ recipeId = recipeId,
+ recipeName = recipeName,
+ recipeInstanceId = recipeInstanceId
+ )
+}
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/javadsl/RecipeInformation.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/RecipeInformation.scala
similarity index 91%
rename from runtime/src/main/scala/com/ing/baker/runtime/javadsl/RecipeInformation.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/RecipeInformation.scala
index 3116a13a7..3e11bf57a 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/javadsl/RecipeInformation.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/RecipeInformation.scala
@@ -2,8 +2,7 @@ package com.ing.baker.runtime.javadsl
import com.ing.baker.il.CompiledRecipe
import com.ing.baker.runtime.common.LanguageDataStructures.JavaApi
-import com.ing.baker.runtime.common
-import com.ing.baker.runtime.scaladsl
+import com.ing.baker.runtime.{common, scaladsl}
import scala.collection.JavaConverters._
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/javadsl/RecipeInstanceMetadata.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/RecipeInstanceMetadata.scala
similarity index 93%
rename from runtime/src/main/scala/com/ing/baker/runtime/javadsl/RecipeInstanceMetadata.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/RecipeInstanceMetadata.scala
index 626168bbf..fbf28db72 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/javadsl/RecipeInstanceMetadata.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/RecipeInstanceMetadata.scala
@@ -1,8 +1,7 @@
package com.ing.baker.runtime.javadsl
-import com.ing.baker.runtime.scaladsl
-import com.ing.baker.runtime.common
import com.ing.baker.runtime.common.LanguageDataStructures.JavaApi
+import com.ing.baker.runtime.{common, scaladsl}
case class RecipeInstanceMetadata(recipeId: String, recipeInstanceId: String, createdTime: Long) extends common.RecipeInstanceMetadata with JavaApi {
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/javadsl/RecipeInstanceState.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/RecipeInstanceState.scala
similarity index 100%
rename from runtime/src/main/scala/com/ing/baker/runtime/javadsl/RecipeInstanceState.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/RecipeInstanceState.scala
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/javadsl/SensoryEventResult.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/SensoryEventResult.scala
similarity index 74%
rename from runtime/src/main/scala/com/ing/baker/runtime/javadsl/SensoryEventResult.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/SensoryEventResult.scala
index b9ea4b617..b761c0f20 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/javadsl/SensoryEventResult.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/javadsl/SensoryEventResult.scala
@@ -1,10 +1,12 @@
package com.ing.baker.runtime.javadsl
-import com.ing.baker.runtime.common.SensoryEventStatus
-import com.ing.baker.runtime.common
import com.ing.baker.runtime.common.LanguageDataStructures.JavaApi
+import com.ing.baker.runtime.common.SensoryEventStatus
+import com.ing.baker.runtime.{common, scaladsl}
import com.ing.baker.types.Value
+import scala.collection.JavaConverters._
+
case class SensoryEventResult(
sensoryEventStatus: SensoryEventStatus,
eventNames: java.util.List[String],
@@ -16,4 +18,7 @@ case class SensoryEventResult(
def getEventNames: java.util.List[String] = eventNames
def getIngredients: java.util.Map[String, Value] = ingredients
+
+ def asScala: scaladsl.SensoryEventResult =
+ scaladsl.SensoryEventResult(sensoryEventStatus, eventNames.asScala, ingredients.asScala.toMap)
}
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/scaladsl/Baker.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/Baker.scala
similarity index 79%
rename from runtime/src/main/scala/com/ing/baker/runtime/scaladsl/Baker.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/Baker.scala
index 7216e89f2..da0d0d715 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/scaladsl/Baker.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/Baker.scala
@@ -1,29 +1,10 @@
package com.ing.baker.runtime.scaladsl
-import akka.actor.{ ActorSystem, Address }
-import cats.data.NonEmptyList
-import com.ing.baker.runtime.akka.{ AkkaBaker, AkkaBakerConfig }
import com.ing.baker.runtime.common
import com.ing.baker.runtime.common.LanguageDataStructures.ScalaApi
import com.ing.baker.runtime.common.SensoryEventStatus
-import com.typesafe.config.Config
-import scala.concurrent.Future
-
-object Baker {
-
- def akkaLocalDefault(actorSystem: ActorSystem): AkkaBaker =
- new AkkaBaker(AkkaBakerConfig.localDefault(actorSystem))
-
- def akkaClusterDefault(seedNodes: NonEmptyList[Address], actorSystem: ActorSystem): AkkaBaker =
- new AkkaBaker(AkkaBakerConfig.clusterDefault(seedNodes, actorSystem))
-
- def akka(config: AkkaBakerConfig): AkkaBaker =
- new AkkaBaker(config)
- def akka(config: Config, actorSystem: ActorSystem): AkkaBaker =
- new AkkaBaker(AkkaBakerConfig.from(config, actorSystem))
-
-}
+import scala.concurrent.Future
/**
* The Baker is the component of the Baker library that runs one or multiples recipes.
@@ -49,6 +30,8 @@ trait Baker extends common.Baker[Future] with ScalaApi {
override type EventMomentType = EventMoment
+ override type RecipeMetadataType = RecipeEventMetadata
+
override def fireEventAndResolveWhenReceived(recipeInstanceId: String, event: EventInstance): Future[SensoryEventStatus] =
fireEventAndResolveWhenReceived(recipeInstanceId, event, None)
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/scaladsl/BakerEvent.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/BakerEvent.scala
similarity index 98%
rename from runtime/src/main/scala/com/ing/baker/runtime/scaladsl/BakerEvent.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/BakerEvent.scala
index 07b00ac5e..f488c212a 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/scaladsl/BakerEvent.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/BakerEvent.scala
@@ -5,10 +5,9 @@ import java.util.Optional
import com.ing.baker.il.CompiledRecipe
import com.ing.baker.il.failurestrategy.ExceptionStrategyOutcome
-import com.ing.baker.runtime.common
-import com.ing.baker.runtime.javadsl
import com.ing.baker.runtime.common.LanguageDataStructures.ScalaApi
import com.ing.baker.runtime.common.RejectReason
+import com.ing.baker.runtime.{common, javadsl}
sealed trait BakerEvent extends common.BakerEvent with ScalaApi {
type Event = EventInstance
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/scaladsl/EventInstance.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/EventInstance.scala
similarity index 96%
rename from runtime/src/main/scala/com/ing/baker/runtime/scaladsl/EventInstance.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/EventInstance.scala
index 213a57941..d1365be2c 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/scaladsl/EventInstance.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/EventInstance.scala
@@ -1,9 +1,8 @@
package com.ing.baker.runtime.scaladsl
import com.ing.baker.il.EventDescriptor
-import com.ing.baker.runtime.javadsl
-import com.ing.baker.runtime.common
import com.ing.baker.runtime.common.LanguageDataStructures.ScalaApi
+import com.ing.baker.runtime.{common, javadsl}
import com.ing.baker.types.{Converters, NullValue, RecordValue, Value}
import scala.collection.JavaConverters._
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/scaladsl/EventMoment.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/EventMoment.scala
similarity index 80%
rename from runtime/src/main/scala/com/ing/baker/runtime/scaladsl/EventMoment.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/EventMoment.scala
index fb90dfe88..3319ab5a8 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/scaladsl/EventMoment.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/EventMoment.scala
@@ -1,8 +1,7 @@
package com.ing.baker.runtime.scaladsl
-import com.ing.baker.runtime.common
import com.ing.baker.runtime.common.LanguageDataStructures.ScalaApi
-import com.ing.baker.runtime.javadsl
+import com.ing.baker.runtime.{common, javadsl}
case class EventMoment(name: String,
occurredOn: Long)
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/scaladsl/EventResolutions.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/EventResolutions.scala
similarity index 100%
rename from runtime/src/main/scala/com/ing/baker/runtime/scaladsl/EventResolutions.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/EventResolutions.scala
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/scaladsl/IngredientInstance.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/IngredientInstance.scala
similarity index 61%
rename from runtime/src/main/scala/com/ing/baker/runtime/scaladsl/IngredientInstance.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/IngredientInstance.scala
index 49e3506bc..ffbfa778b 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/scaladsl/IngredientInstance.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/IngredientInstance.scala
@@ -1,12 +1,11 @@
package com.ing.baker.runtime.scaladsl
-import com.ing.baker.runtime.javadsl
-import com.ing.baker.runtime.common
import com.ing.baker.runtime.common.LanguageDataStructures.ScalaApi
+import com.ing.baker.runtime.{common, javadsl}
import com.ing.baker.types.Value
case class IngredientInstance(name: String, value: Value) extends common.IngredientInstance with ScalaApi {
- def asJava: javadsl.IngredientInstance = new javadsl.IngredientInstance(name, value)
+ def asJava: javadsl.IngredientInstance = javadsl.IngredientInstance(name, value)
}
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/scaladsl/InteractionInstance.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/InteractionInstance.scala
similarity index 96%
rename from runtime/src/main/scala/com/ing/baker/runtime/scaladsl/InteractionInstance.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/InteractionInstance.scala
index 622ea9c3e..c0bacb34f 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/scaladsl/InteractionInstance.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/InteractionInstance.scala
@@ -5,15 +5,13 @@ import java.util
import java.util.Optional
import java.util.concurrent.CompletableFuture
-import com.ing.baker.runtime.akka
-import com.ing.baker.runtime.javadsl
-import com.ing.baker.runtime.common
import com.ing.baker.runtime.common.LanguageDataStructures.ScalaApi
+import com.ing.baker.runtime.{common, javadsl}
import com.ing.baker.types.{Converters, Type}
-import scala.concurrent.{ExecutionContext, Future}
import scala.collection.JavaConverters._
import scala.compat.java8.FutureConverters
+import scala.concurrent.{ExecutionContext, Future}
import scala.reflect.ClassTag
import scala.util.Try
@@ -58,7 +56,7 @@ object InteractionInstance {
def unsafeFrom(implementation: AnyRef)(implicit ec: ExecutionContext): InteractionInstance = {
val method: Method = {
- val unmockedClass = akka.unmock(implementation.getClass)
+ val unmockedClass = common.unmock(implementation.getClass)
unmockedClass.getMethods.count(_.getName == "apply") match {
case 0 => throw new IllegalArgumentException("Implementation does not have a apply function")
case n if n > 1 => throw new IllegalArgumentException("Implementation has multiple apply functions")
diff --git a/baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/RecipeEventMetadata.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/RecipeEventMetadata.scala
new file mode 100644
index 000000000..fb37f161c
--- /dev/null
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/RecipeEventMetadata.scala
@@ -0,0 +1,15 @@
+package com.ing.baker.runtime.scaladsl
+
+import com.ing.baker.runtime.common
+import com.ing.baker.runtime.javadsl
+import com.ing.baker.runtime.common.LanguageDataStructures.ScalaApi
+
+case class RecipeEventMetadata(recipeId: String, recipeName: String, recipeInstanceId: String) extends common.RecipeEventMetadata with ScalaApi {
+
+ def asJava: javadsl.RecipeEventMetadata =
+ javadsl.RecipeEventMetadata(
+ recipeId = recipeId,
+ recipeName = recipeName,
+ recipeInstanceId = recipeInstanceId
+ )
+}
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/scaladsl/RecipeInformation.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/RecipeInformation.scala
similarity index 75%
rename from runtime/src/main/scala/com/ing/baker/runtime/scaladsl/RecipeInformation.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/RecipeInformation.scala
index 6e3306aac..d6e8853be 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/scaladsl/RecipeInformation.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/RecipeInformation.scala
@@ -1,10 +1,9 @@
package com.ing.baker.runtime.scaladsl
import com.ing.baker.il.CompiledRecipe
-
import com.ing.baker.runtime.common.LanguageDataStructures.ScalaApi
-import com.ing.baker.runtime.common
-import com.ing.baker.runtime.javadsl
+import com.ing.baker.runtime.{common, javadsl}
+
import scala.collection.JavaConverters._
case class RecipeInformation(
@@ -13,5 +12,5 @@ case class RecipeInformation(
errors: Set[String]) extends common.RecipeInformation with ScalaApi {
def asJava: javadsl.RecipeInformation =
- new javadsl.RecipeInformation(compiledRecipe, recipeCreatedTime, errors.asJava)
+ javadsl.RecipeInformation(compiledRecipe, recipeCreatedTime, errors.asJava)
}
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/scaladsl/RecipeInstanceMetadata.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/RecipeInstanceMetadata.scala
similarity index 100%
rename from runtime/src/main/scala/com/ing/baker/runtime/scaladsl/RecipeInstanceMetadata.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/RecipeInstanceMetadata.scala
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/scaladsl/RecipeInstanceState.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/RecipeInstanceState.scala
similarity index 100%
rename from runtime/src/main/scala/com/ing/baker/runtime/scaladsl/RecipeInstanceState.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/RecipeInstanceState.scala
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/scaladsl/SensoryEventResult.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/SensoryEventResult.scala
similarity index 100%
rename from runtime/src/main/scala/com/ing/baker/runtime/scaladsl/SensoryEventResult.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/scaladsl/SensoryEventResult.scala
diff --git a/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/BakerSerializable.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/BakerSerializable.scala
new file mode 100644
index 000000000..8eddd451e
--- /dev/null
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/BakerSerializable.scala
@@ -0,0 +1,3 @@
+package com.ing.baker.runtime.serialization
+
+trait BakerSerializable
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/Encryption.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/Encryption.scala
similarity index 95%
rename from runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/Encryption.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/serialization/Encryption.scala
index 585bb48df..295d6d359 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/Encryption.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/Encryption.scala
@@ -1,4 +1,4 @@
-package com.ing.baker.runtime.akka.actor.serialization
+package com.ing.baker.runtime.serialization
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/ProtoMap.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/ProtoMap.scala
similarity index 76%
rename from runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/ProtoMap.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/serialization/ProtoMap.scala
index 3fed2ef5d..96a4b2bd4 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/ProtoMap.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/ProtoMap.scala
@@ -1,12 +1,12 @@
-package com.ing.baker.runtime.akka.actor.serialization
+package com.ing.baker.runtime.serialization
import akka.actor.ActorRef
-import com.ing.baker.il
-import com.ing.baker.types
-import com.ing.baker.runtime.akka.actor.protobuf
-import com.ing.baker.runtime.akka.actor.serialization.protomappings._
-import com.ing.baker.runtime.scaladsl.{EventMoment, RecipeInstanceState, EventInstance, SensoryEventResult}
+import com.ing.baker.runtime.common.BakerException
+import com.ing.baker.runtime.scaladsl._
+import com.ing.baker.runtime.serialization.protomappings._
+import com.ing.baker.{il, types}
import scalapb.GeneratedMessageCompanion
+import com.ing.baker.runtime.akka.actor.protobuf
import scala.util.{Success, Try}
@@ -44,12 +44,21 @@ object ProtoMap {
implicit def akkaActorRefMapping(implicit ev0: SerializersProvider): ProtoMap[ActorRef, protobuf.ActorRefId] =
new ActorRefMapping(ev0)
+ implicit def recipeInformationMapping(implicit ev0: SerializersProvider): ProtoMap[RecipeInformation, protobuf.RecipeInformation] =
+ new RecipeInformationMapping()
+
+ implicit val bakerExceptionMapping: ProtoMap[BakerException, protobuf.BakerException] =
+ new BakerExceptionMapping
+
implicit val eventDescriptorMapping: ProtoMap[il.EventDescriptor, protobuf.EventDescriptor] =
new EventDescriptorMapping
implicit val ingredientDescriptorMapping: ProtoMap[il.IngredientDescriptor, protobuf.IngredientDescriptor] =
new IngredientDescriptorMapping
+ implicit val ingredientInstanceMapping: ProtoMap[IngredientInstance, protobuf.Ingredient] =
+ new IngredientInstanceMapping
+
implicit val bakerTypeMapping: ProtoMap[types.Type, protobuf.Type] =
new BakerTypesMapping
@@ -65,9 +74,15 @@ object ProtoMap {
implicit val runtimeEventMapping: ProtoMap[EventInstance, protobuf.RuntimeEvent] =
new RuntimeEventMapping
+ implicit val recipeInstanceMetadataMapping: ProtoMap[RecipeInstanceMetadata, protobuf.RecipeInstanceMetadata] =
+ new RecipeInstanceMetadataMapping
+
implicit val processStateMapping: ProtoMap[RecipeInstanceState, protobuf.ProcessState] =
new ProcessStateMapping
+ implicit val recipeEventMetadataMapping: ProtoMap[RecipeEventMetadata, protobuf.RecipeEventMetadata] =
+ new RecipeEventMetadataMapping
+
implicit val eventMomentMapping: ProtoMap[EventMoment, protobuf.EventMoment] =
new EventMomentMapping
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/SerializersProvider.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/SerializersProvider.scala
similarity index 56%
rename from runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/SerializersProvider.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/serialization/SerializersProvider.scala
index 766d28c05..7efdfe6ad 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/SerializersProvider.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/SerializersProvider.scala
@@ -1,4 +1,4 @@
-package com.ing.baker.runtime.akka.actor.serialization
+package com.ing.baker.runtime.serialization
import akka.actor.{ActorRefProvider, ActorSystem}
import akka.serialization.{Serialization, SerializationExtension, Serializer}
@@ -7,7 +7,7 @@ case class SerializersProvider(getSerializerFor: AnyRef => Serializer, serialize
object SerializersProvider {
- def apply(system: ActorSystem, actorRefProvider: ActorRefProvider, encryption: Encryption = Encryption.NoEncryption): SerializersProvider = {
+ def apply(system: ActorSystem, actorRefProvider: ActorRefProvider, encryption: Encryption): SerializersProvider = {
val serialization: Serialization = SerializationExtension.get(system)
SerializersProvider(
serialization.findSerializerFor,
@@ -16,4 +16,16 @@ object SerializersProvider {
actorRefProvider
)
}
+
+ def apply(system: ActorSystem, actorRefProvider: ActorRefProvider): SerializersProvider = {
+ apply(system, actorRefProvider, Encryption.NoEncryption)
+ }
+
+ def apply(system: ActorSystem, encryption: Encryption): SerializersProvider = {
+ apply(system, null, encryption)
+ }
+
+ def apply(system: ActorSystem): SerializersProvider = {
+ apply(system, null, Encryption.NoEncryption)
+ }
}
diff --git a/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/TokenIdentifier.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/TokenIdentifier.scala
new file mode 100644
index 000000000..f8e4c9674
--- /dev/null
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/TokenIdentifier.scala
@@ -0,0 +1,23 @@
+package com.ing.baker.runtime.serialization
+
+import java.security.MessageDigest
+
+object TokenIdentifier {
+
+ /**
+ * TODO:
+ *
+ * This approach is fragile, the identifier function cannot change ever or recovery breaks
+ * a more robust alternative is to generate the ids and persist them
+ */
+ def apply(tokenValue: Any): Long = tokenValue match {
+ case null => -1
+ case str: String => sha256(str)
+ case obj => obj.hashCode()
+ }
+
+ def sha256(str: String) = {
+ val sha256Digest: MessageDigest = MessageDigest.getInstance("SHA-256")
+ BigInt(1, sha256Digest.digest(str.getBytes("UTF-8"))).toLong
+ }
+}
diff --git a/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/TypedProtobufSerializer.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/TypedProtobufSerializer.scala
new file mode 100644
index 000000000..de3041130
--- /dev/null
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/TypedProtobufSerializer.scala
@@ -0,0 +1,101 @@
+package com.ing.baker.runtime.serialization
+
+import akka.actor.ExtendedActorSystem
+import akka.serialization.SerializerWithStringManifest
+import com.ing.baker.runtime.serialization.TypedProtobufSerializer.BinarySerializable
+import org.slf4j.LoggerFactory
+
+import scala.reflect.ClassTag
+import scala.util.Try
+
+object TypedProtobufSerializer {
+
+ private val log = LoggerFactory.getLogger(classOf[TypedProtobufSerializer])
+
+ def forType[A <: AnyRef](implicit tag: ClassTag[A]): RegisterFor[A] = new RegisterFor[A](tag)
+
+ class RegisterFor[A <: AnyRef](classTag: ClassTag[A]) {
+
+ def register[P <: scalapb.GeneratedMessage with scalapb.Message[P]](implicit protoMap: ProtoMap[A, P]): BinarySerializable =
+ register[P](None)
+
+ def register[P <: scalapb.GeneratedMessage with scalapb.Message[P]](overrideName: String)(implicit protoMap: ProtoMap[A, P]): BinarySerializable =
+ register[P](Some(overrideName))
+
+ def register[P <: scalapb.GeneratedMessage with scalapb.Message[P]](overrideName: Option[String])(implicit protoMap: ProtoMap[A, P]): BinarySerializable = {
+ new BinarySerializable {
+
+ override type Type = A
+
+ override val tag: Class[_] = classTag.runtimeClass
+
+ override val manifest: String = overrideName.getOrElse(classTag.runtimeClass.getName)
+
+ override def toBinary(a: Type): Array[Byte] = protoMap.toByteArray(a)
+
+ override def fromBinary(binary: Array[Byte]): Try[Type] = protoMap.fromByteArray(binary)
+ }
+ }
+ }
+
+ trait BinarySerializable {
+
+ type Type <: AnyRef
+
+ val tag: Class[_]
+
+ def manifest: String
+
+ def toBinary(a: Type): Array[Byte]
+
+ // The actor resolver is commented for future Akka Typed implementation
+ def fromBinary(binary: Array[Byte]/*, resolver: ActorRefResolver*/): Try[Type]
+
+ def isInstance(o: AnyRef): Boolean =
+ tag.isInstance(o)
+
+ def unsafeToBinary(a: AnyRef): Array[Byte] =
+ toBinary(a.asInstanceOf[Type])
+
+ // The actor resolver is commented for future Akka Typed implementation
+ def fromBinaryAnyRef(binary: Array[Byte]/*, resolver: ActorRefResolver*/): Try[AnyRef] =
+ fromBinary(binary)
+
+ }
+}
+
+abstract class TypedProtobufSerializer(system: ExtendedActorSystem, _indentifier: Int, entries: SerializersProvider => List[BinarySerializable]) extends SerializerWithStringManifest {
+
+ implicit def serializersProvider: SerializersProvider =
+ SerializersProvider(system, system.provider)
+
+ lazy val entriesMem: List[BinarySerializable] =
+ entries(serializersProvider)
+
+ override def identifier: Int =
+ _indentifier
+
+ override def manifest(o: AnyRef): String = {
+ entriesMem
+ .find(_.isInstance(o))
+ .map(_.manifest)
+ .getOrElse(throw new IllegalStateException(s"Unsupported object of type: ${o.getClass}"))
+ }
+
+ override def toBinary(o: AnyRef): Array[Byte] =
+ entriesMem
+ .find(_.isInstance(o))
+ .map(_.unsafeToBinary(o))
+ .getOrElse(throw new IllegalStateException(s"Unsupported object of type: ${o.getClass}"))
+
+ override def fromBinary(bytes: Array[Byte], manifest: String): AnyRef =
+ entriesMem
+ .find(_.manifest == manifest)
+ .map(_.fromBinaryAnyRef(bytes))
+ .getOrElse(throw new IllegalStateException(s"Unsupported object with manifest $manifest"))
+ .fold(
+ { e => TypedProtobufSerializer.log.error(s"Failed to deserialize bytes with manifest $manifest", e); throw e },
+ identity
+ )
+}
+
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/ActorRefMapping.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/ActorRefMapping.scala
similarity index 69%
rename from runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/ActorRefMapping.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/ActorRefMapping.scala
index 1b647a0f9..361d8c4ef 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/ActorRefMapping.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/ActorRefMapping.scala
@@ -1,10 +1,10 @@
-package com.ing.baker.runtime.akka.actor.serialization.protomappings
+package com.ing.baker.runtime.serialization.protomappings
import akka.actor.ActorRef
-import com.ing.baker.runtime.akka.actor.serialization.{ProtoMap, SerializersProvider}
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap.versioned
+import com.ing.baker.runtime.serialization.ProtoMap.versioned
import com.ing.baker.runtime.akka.actor.protobuf
import com.ing.baker.runtime.akka.actor.protobuf.ActorRefId
+import com.ing.baker.runtime.serialization.{ProtoMap, SerializersProvider}
import scala.util.Try
@@ -12,7 +12,7 @@ class ActorRefMapping(provider: SerializersProvider) extends ProtoMap[ActorRef,
val companion = protobuf.ActorRefId
- override def toProto(a: ActorRef): ActorRefId =
+ override def toProto(a: ActorRef): protobuf.ActorRefId =
protobuf.ActorRefId(Some(akka.serialization.Serialization.serializedActorPath(a)))
override def fromProto(message: ActorRefId): Try[ActorRef] =
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/AnyRefMapping.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/AnyRefMapping.scala
similarity index 88%
rename from runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/AnyRefMapping.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/AnyRefMapping.scala
index 39adbafdb..bee47e4f5 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/AnyRefMapping.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/AnyRefMapping.scala
@@ -1,10 +1,10 @@
-package com.ing.baker.runtime.akka.actor.serialization.protomappings
+package com.ing.baker.runtime.serialization.protomappings
-import com.google.protobuf.ByteString
import akka.serialization.{Serializer, SerializerWithStringManifest}
-import com.ing.baker.runtime.akka.actor.serialization.{ProtoMap, SerializersProvider}
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap.versioned
+import com.google.protobuf.ByteString
+import com.ing.baker.runtime.serialization.ProtoMap.versioned
import com.ing.baker.runtime.akka.actor.protobuf
+import com.ing.baker.runtime.serialization.{ProtoMap, SerializersProvider}
import scala.util.{Failure, Success, Try}
diff --git a/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/BakerExceptionMapping.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/BakerExceptionMapping.scala
new file mode 100644
index 000000000..a055b4aed
--- /dev/null
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/BakerExceptionMapping.scala
@@ -0,0 +1,26 @@
+package com.ing.baker.runtime.serialization.protomappings
+
+import com.ing.baker.runtime.akka.actor.protobuf
+import com.ing.baker.runtime.serialization.ProtoMap.versioned
+import com.ing.baker.runtime.common.BakerException
+import com.ing.baker.runtime.serialization.ProtoMap
+
+import scala.util.Try
+
+class BakerExceptionMapping extends ProtoMap[BakerException, protobuf.BakerException] {
+
+ val companion: protobuf.BakerException.type = protobuf.BakerException
+
+ override def toProto(a: BakerException): protobuf.BakerException =
+ BakerException.encode(a) match {
+ case (message, enum) =>
+ protobuf.BakerException(Some(message), Some(enum))
+ }
+
+ override def fromProto(message: protobuf.BakerException): Try[BakerException] =
+ for {
+ msg <- versioned(message.message, "message")
+ enum <- versioned(message.enum, "enum")
+ decoded <- BakerException.decode(msg, enum)
+ } yield decoded
+ }
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/BakerTypesMapping.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/BakerTypesMapping.scala
similarity index 95%
rename from runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/BakerTypesMapping.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/BakerTypesMapping.scala
index 833dab6f2..5f5359bb2 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/BakerTypesMapping.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/BakerTypesMapping.scala
@@ -1,13 +1,13 @@
-package com.ing.baker.runtime.akka.actor.serialization.protomappings
+package com.ing.baker.runtime.serialization.protomappings
import cats.implicits._
-import com.ing.baker.types
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap
import com.ing.baker.runtime.akka.actor.protobuf
-import com.ing.baker.runtime.akka.actor.protobuf._
-import Type.OneofType._
-import PrimitiveType._
+import com.ing.baker.runtime.akka.actor.protobuf.PrimitiveType._
import com.ing.baker.runtime.akka.actor.protobuf.Type.OneofType
+import com.ing.baker.runtime.akka.actor.protobuf.Type.OneofType.Primitive
+import com.ing.baker.runtime.akka.actor.protobuf._
+import com.ing.baker.runtime.serialization.ProtoMap
+import com.ing.baker.types
import scala.util.{Failure, Success, Try}
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/BakerValuesMapping.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/BakerValuesMapping.scala
similarity index 94%
rename from runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/BakerValuesMapping.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/BakerValuesMapping.scala
index d2ef70c92..2479a2911 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/BakerValuesMapping.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/BakerValuesMapping.scala
@@ -1,15 +1,13 @@
-package com.ing.baker.runtime.akka.actor.serialization.protomappings
+package com.ing.baker.runtime.serialization.protomappings
-import cats.instances.list._
-import cats.instances.try_._
-import cats.syntax.traverse._
+import cats.implicits._
import com.google.protobuf.ByteString
-import com.ing.baker.types
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap
import com.ing.baker.runtime.akka.actor.protobuf
-import protobuf.Value.OneofValue._
-import org.joda.time.{LocalDate, LocalDateTime, LocalTime}
+import com.ing.baker.runtime.akka.actor.protobuf.Value.OneofValue._
+import com.ing.baker.runtime.serialization.ProtoMap
+import com.ing.baker.types
import org.joda.time.format.ISODateTimeFormat
+import org.joda.time.{LocalDate, LocalDateTime, LocalTime}
import scala.util.{Failure, Success, Try}
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/CompiledRecipeMapping.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/CompiledRecipeMapping.scala
similarity index 96%
rename from runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/CompiledRecipeMapping.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/CompiledRecipeMapping.scala
index 7f535fa25..60f78cf26 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/CompiledRecipeMapping.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/CompiledRecipeMapping.scala
@@ -1,19 +1,15 @@
-package com.ing.baker.runtime.akka.actor.serialization.protomappings
+package com.ing.baker.runtime.serialization.protomappings
import java.util.concurrent.TimeUnit
-import cats.syntax.traverse._
-import cats.instances.list._
-import cats.instances.option._
-import cats.instances.try_._
+import cats.implicits._
import com.ing.baker.il
import com.ing.baker.petrinet.api._
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap
-import com.ing.baker.runtime.akka.actor.process_instance.ProcessInstanceSerialization.tokenIdentifier
import com.ing.baker.runtime.akka.actor.protobuf
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap.{versioned, ctxFromProto, ctxToProto}
+import com.ing.baker.runtime.serialization.ProtoMap.{ctxFromProto, ctxToProto, versioned}
import com.ing.baker.il.petrinet.{Node, Place, RecipePetriNet, Transition}
import com.ing.baker.petrinet.api.Marking
+import com.ing.baker.runtime.serialization.{ProtoMap, TokenIdentifier}
import com.ing.baker.types.Value
import scalax.collection.GraphEdge
import scalax.collection.edge.WLDiEdge
@@ -127,7 +123,7 @@ class CompiledRecipeMapping(anyMapping: ProtoMap[AnyRef, protobuf.SerializedData
case (place, tokens) ⇒ tokens.toSeq.map {
case (value, count) ⇒ protobuf.ProducedToken(
placeId = Option(place.id),
- tokenId = Option(tokenIdentifier(value)),
+ tokenId = Option(TokenIdentifier(value)),
count = Option(count),
tokenData = Option(anyMapping.toProto(value.asInstanceOf[AnyRef]))
)
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/EventDescriptorMapping.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/EventDescriptorMapping.scala
similarity index 77%
rename from runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/EventDescriptorMapping.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/EventDescriptorMapping.scala
index 0a531a3a3..1385dcce3 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/EventDescriptorMapping.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/EventDescriptorMapping.scala
@@ -1,10 +1,10 @@
-package com.ing.baker.runtime.akka.actor.serialization.protomappings
+package com.ing.baker.runtime.serialization.protomappings
import cats.implicits._
import com.ing.baker.il
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap.{ ctxToProto, ctxFromProto, versioned }
+import com.ing.baker.runtime.serialization.ProtoMap.{ctxFromProto, ctxToProto, versioned}
import com.ing.baker.runtime.akka.actor.protobuf
+import com.ing.baker.runtime.serialization.ProtoMap
import scala.util.Try
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/EventMomentMapping.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/EventMomentMapping.scala
similarity index 73%
rename from runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/EventMomentMapping.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/EventMomentMapping.scala
index 3fb0f51a7..54439f4c9 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/EventMomentMapping.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/EventMomentMapping.scala
@@ -1,9 +1,9 @@
-package com.ing.baker.runtime.akka.actor.serialization.protomappings
+package com.ing.baker.runtime.serialization.protomappings
import com.ing.baker.runtime.akka.actor.protobuf
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap.versioned
+import com.ing.baker.runtime.serialization.ProtoMap.versioned
import com.ing.baker.runtime.scaladsl.EventMoment
+import com.ing.baker.runtime.serialization.ProtoMap
import scala.util.Try
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/EventOutputTransformerMapping.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/EventOutputTransformerMapping.scala
similarity index 78%
rename from runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/EventOutputTransformerMapping.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/EventOutputTransformerMapping.scala
index f50949288..2f7785079 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/EventOutputTransformerMapping.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/EventOutputTransformerMapping.scala
@@ -1,10 +1,10 @@
-package com.ing.baker.runtime.akka.actor.serialization.protomappings
+package com.ing.baker.runtime.serialization.protomappings
import com.ing.baker.il
import com.ing.baker.il.EventOutputTransformer
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap
import com.ing.baker.runtime.akka.actor.protobuf
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap.versioned
+import com.ing.baker.runtime.serialization.ProtoMap.versioned
+import com.ing.baker.runtime.serialization.ProtoMap
import scala.util.Try
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/IngredientDescriptorMapping.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/IngredientDescriptorMapping.scala
similarity index 76%
rename from runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/IngredientDescriptorMapping.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/IngredientDescriptorMapping.scala
index 4d9d98276..ff7c84163 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/IngredientDescriptorMapping.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/IngredientDescriptorMapping.scala
@@ -1,9 +1,9 @@
-package com.ing.baker.runtime.akka.actor.serialization.protomappings
+package com.ing.baker.runtime.serialization.protomappings
import com.ing.baker.il
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap.{ ctxToProto, ctxFromProto, versioned }
+import com.ing.baker.runtime.serialization.ProtoMap.{ctxFromProto, ctxToProto, versioned}
import com.ing.baker.runtime.akka.actor.protobuf
+import com.ing.baker.runtime.serialization.ProtoMap
import scala.util.Try
diff --git a/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/IngredientInstanceMapping.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/IngredientInstanceMapping.scala
new file mode 100644
index 000000000..bed54700a
--- /dev/null
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/IngredientInstanceMapping.scala
@@ -0,0 +1,24 @@
+package com.ing.baker.runtime.serialization.protomappings
+
+import com.ing.baker.runtime.akka.actor.protobuf
+import com.ing.baker.runtime.scaladsl.IngredientInstance
+import com.ing.baker.runtime.serialization.ProtoMap.{ctxFromProto, ctxToProto, versioned}
+import com.ing.baker.runtime.serialization.ProtoMap
+
+import scala.util.Try
+
+class IngredientInstanceMapping extends ProtoMap[IngredientInstance, protobuf.Ingredient] {
+
+ val companion = protobuf.Ingredient
+
+ override def toProto(data: IngredientInstance): protobuf.Ingredient =
+ protobuf.Ingredient(Option(data.name), None, Some(ctxToProto(data.value)))
+
+ override def fromProto(message: protobuf.Ingredient): Try[IngredientInstance] =
+ for {
+ name <- versioned(message.name, "name")
+ valueProto <- versioned(message.value, "value")
+ value <- ctxFromProto(valueProto)
+ } yield IngredientInstance(name, value)
+
+}
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/InteractionFailureStrategyMapping.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/InteractionFailureStrategyMapping.scala
similarity index 93%
rename from runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/InteractionFailureStrategyMapping.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/InteractionFailureStrategyMapping.scala
index dff5c3eb1..293dd4327 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/InteractionFailureStrategyMapping.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/InteractionFailureStrategyMapping.scala
@@ -1,13 +1,13 @@
-package com.ing.baker.runtime.akka.actor.serialization.protomappings
+package com.ing.baker.runtime.serialization.protomappings
import java.util.concurrent.TimeUnit
import cats.implicits._
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap
import com.ing.baker.il
import com.ing.baker.il.failurestrategy.InteractionFailureStrategy
import com.ing.baker.runtime.akka.actor.protobuf
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap.{versioned, ctxFromProto, ctxToProto}
+import com.ing.baker.runtime.serialization.ProtoMap.{ctxFromProto, ctxToProto, versioned}
+import com.ing.baker.runtime.serialization.ProtoMap
import scala.util.{Failure, Success, Try}
import scala.concurrent.duration._
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/ProcessStateMapping.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/ProcessStateMapping.scala
similarity index 79%
rename from runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/ProcessStateMapping.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/ProcessStateMapping.scala
index 3e18a8d8f..6b48224c7 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/ProcessStateMapping.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/ProcessStateMapping.scala
@@ -1,13 +1,11 @@
-package com.ing.baker.runtime.akka.actor.serialization.protomappings
+package com.ing.baker.runtime.serialization.protomappings
-import cats.instances.list._
-import cats.instances.try_._
-import cats.syntax.traverse._
+import cats.implicits._
import com.ing.baker.types.Value
import com.ing.baker.runtime.akka.actor.{protobuf => proto}
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap.{ctxFromProto, ctxToProto, versioned}
+import com.ing.baker.runtime.serialization.ProtoMap.{ctxFromProto, ctxToProto, versioned}
import com.ing.baker.runtime.scaladsl.{EventMoment, RecipeInstanceState}
+import com.ing.baker.runtime.serialization.ProtoMap
import scala.util.Try
diff --git a/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/RecipeEventMetadataMapping.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/RecipeEventMetadataMapping.scala
new file mode 100644
index 000000000..8c7ba06b5
--- /dev/null
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/RecipeEventMetadataMapping.scala
@@ -0,0 +1,24 @@
+package com.ing.baker.runtime.serialization.protomappings
+
+import com.ing.baker.runtime.akka.actor.{protobuf => proto}
+import com.ing.baker.runtime.scaladsl.RecipeEventMetadata
+import com.ing.baker.runtime.serialization.ProtoMap
+import com.ing.baker.runtime.serialization.ProtoMap.versioned
+
+import scala.util.Try
+
+class RecipeEventMetadataMapping extends ProtoMap[RecipeEventMetadata, proto.RecipeEventMetadata] {
+
+ val companion = proto.RecipeEventMetadata
+
+ def toProto(a: RecipeEventMetadata): proto.RecipeEventMetadata = {
+ proto.RecipeEventMetadata(Some(a.recipeId), Some(a.recipeName), Some(a.recipeInstanceId))
+ }
+
+ def fromProto(message: proto.RecipeEventMetadata): Try[RecipeEventMetadata] =
+ for {
+ recipeId <- versioned(message.recipeId, "recipeId")
+ recipeName <- versioned(message.recipeName, "recipeName")
+ recipeInstanceId <- versioned(message.recipeInstanceId, "recipeInstanceId")
+ } yield RecipeEventMetadata(recipeId, recipeName, recipeInstanceId)
+}
diff --git a/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/RecipeInformationMapping.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/RecipeInformationMapping.scala
new file mode 100644
index 000000000..f295d2a90
--- /dev/null
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/RecipeInformationMapping.scala
@@ -0,0 +1,24 @@
+package com.ing.baker.runtime.serialization.protomappings
+
+import com.ing.baker.runtime.serialization.ProtoMap.{ctxFromProto, ctxToProto, versioned}
+import com.ing.baker.runtime.akka.actor.{protobuf => proto}
+import com.ing.baker.runtime.scaladsl.RecipeInformation
+import com.ing.baker.runtime.serialization.{ProtoMap, SerializersProvider}
+
+import scala.util.Try
+
+class RecipeInformationMapping(implicit ev0: SerializersProvider) extends ProtoMap[RecipeInformation, proto.RecipeInformation] {
+
+ val companion = proto.RecipeInformation
+
+ def toProto(a: RecipeInformation): proto.RecipeInformation = {
+ proto.RecipeInformation(Some(ctxToProto(a.compiledRecipe)), Some(a.recipeCreatedTime), a.errors.toSeq)
+ }
+
+ def fromProto(message: proto.RecipeInformation): Try[RecipeInformation] =
+ for {
+ compiledRecipeProto <- versioned(message.compiledRecipe, "compiledRecipe")
+ compiledRecipe <- ctxFromProto(compiledRecipeProto)
+ recipeCreatedTime <- versioned(message.recipeCreatedTime, "recipeCreatedTime")
+ } yield RecipeInformation(compiledRecipe, recipeCreatedTime, message.errors.toSet)
+}
diff --git a/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/RecipeInstanceMetadataMapping.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/RecipeInstanceMetadataMapping.scala
new file mode 100644
index 000000000..da3614a5b
--- /dev/null
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/RecipeInstanceMetadataMapping.scala
@@ -0,0 +1,24 @@
+package com.ing.baker.runtime.serialization.protomappings
+
+import com.ing.baker.runtime.serialization.ProtoMap.versioned
+import com.ing.baker.runtime.akka.actor.{protobuf => proto}
+import com.ing.baker.runtime.scaladsl.RecipeInstanceMetadata
+import com.ing.baker.runtime.serialization.ProtoMap
+
+import scala.util.Try
+
+class RecipeInstanceMetadataMapping extends ProtoMap[RecipeInstanceMetadata, proto.RecipeInstanceMetadata] {
+
+ val companion = proto.RecipeInstanceMetadata
+
+ def toProto(a: RecipeInstanceMetadata): proto.RecipeInstanceMetadata = {
+ proto.RecipeInstanceMetadata(Some(a.recipeId), Some(a.recipeInstanceId), Some(a.createdTime))
+ }
+
+ def fromProto(message: proto.RecipeInstanceMetadata): Try[RecipeInstanceMetadata] =
+ for {
+ recipeId <- versioned(message.recipeId, "recipeId")
+ recipeInstanceId <- versioned(message.recipeInstanceId, "recipeInstanceId")
+ createdTime <- versioned(message.createdTime, "createdTime")
+ } yield RecipeInstanceMetadata(recipeId, recipeInstanceId, createdTime)
+ }
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/RuntimeEventMapping.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/RuntimeEventMapping.scala
similarity index 76%
rename from runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/RuntimeEventMapping.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/RuntimeEventMapping.scala
index 810e4a9e6..f71e6a0b1 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/RuntimeEventMapping.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/RuntimeEventMapping.scala
@@ -1,12 +1,10 @@
-package com.ing.baker.runtime.akka.actor.serialization.protomappings
+package com.ing.baker.runtime.serialization.protomappings
-import cats.instances.list._
-import cats.instances.try_._
-import cats.syntax.traverse._
+import cats.implicits._
import com.ing.baker.runtime.akka.actor.protobuf
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap.{ctxFromProto, ctxToProto, versioned}
+import com.ing.baker.runtime.serialization.ProtoMap.{ctxFromProto, ctxToProto, versioned}
import com.ing.baker.runtime.scaladsl.EventInstance
+import com.ing.baker.runtime.serialization.ProtoMap
import com.ing.baker.types.Value
import scala.util.Try
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/SensoryEventResultMapping.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/SensoryEventResultMapping.scala
similarity index 78%
rename from runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/SensoryEventResultMapping.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/SensoryEventResultMapping.scala
index db2764b77..f5a400799 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/SensoryEventResultMapping.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/SensoryEventResultMapping.scala
@@ -1,12 +1,10 @@
-package com.ing.baker.runtime.akka.actor.serialization.protomappings
+package com.ing.baker.runtime.serialization.protomappings
-import cats.instances.list._
-import cats.instances.try_._
-import cats.syntax.traverse._
+import cats.implicits._
import com.ing.baker.runtime.akka.actor.protobuf
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap.{ctxFromProto, ctxToProto, versioned}
+import com.ing.baker.runtime.serialization.ProtoMap.{ctxFromProto, ctxToProto, versioned}
import com.ing.baker.runtime.scaladsl.SensoryEventResult
+import com.ing.baker.runtime.serialization.ProtoMap
import com.ing.baker.types.Value
import scalapb.GeneratedMessageCompanion
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/SensoryEventStatusMappingHelper.scala b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/SensoryEventStatusMappingHelper.scala
similarity index 96%
rename from runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/SensoryEventStatusMappingHelper.scala
rename to baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/SensoryEventStatusMappingHelper.scala
index 3186e24d2..8d145df13 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/protomappings/SensoryEventStatusMappingHelper.scala
+++ b/baker-interface/src/main/scala/com/ing/baker/runtime/serialization/protomappings/SensoryEventStatusMappingHelper.scala
@@ -1,4 +1,4 @@
-package com.ing.baker.runtime.akka.actor.serialization.protomappings
+package com.ing.baker.runtime.serialization.protomappings
import com.ing.baker.runtime.akka.actor.protobuf
import com.ing.baker.runtime.common.SensoryEventStatus
diff --git a/build.sbt b/build.sbt
index 68d91bc7f..04c907135 100644
--- a/build.sbt
+++ b/build.sbt
@@ -23,6 +23,7 @@ val commonSettings = Defaults.coreDefaultSettings ++ Seq(
s"-target:jvm-$jvmV",
"-Xfatal-warnings"
),
+ coverageExcludedPackages := ";.*.javadsl;.*.scaladsl;.*.common;.*.protobuf",
packageOptions in (Compile, packageBin) +=
Package.ManifestAttributes(
"Build-Time" -> new java.util.Date().toString,
@@ -31,11 +32,10 @@ val commonSettings = Defaults.coreDefaultSettings ++ Seq(
)
val dependencyOverrideSettings = Seq(
- // note that this does NOT add the dependencies, just forces the version
dependencyOverrides ++= Seq(
catsCore,
akkaActor,
- "com.github.jnr" % "jnr-constants" % "0.9.9"
+ jnrConstants
)
)
@@ -77,6 +77,18 @@ lazy val intermediateLanguage = project.in(file("intermediate-language"))
) ++ testDeps(scalaTest, scalaCheck, logback)
).dependsOn(bakertypes)
+lazy val `baker-interface` = project.in(file("baker-interface"))
+ .settings(defaultModuleSettings)
+ .settings(scalaPBSettings)
+ .settings(
+ moduleName := "baker-interface",
+ libraryDependencies ++= Seq(
+ akkaActor,
+ catsCore,
+ scalaJava8Compat
+ ) ++ providedDeps(findbugs)
+ )
+ .dependsOn(intermediateLanguage)
lazy val runtime = project.in(file("runtime"))
.settings(defaultModuleSettings)
@@ -90,6 +102,9 @@ lazy val runtime = project.in(file("runtime"))
akkaActor,
akkaPersistence,
akkaPersistenceQuery,
+ akkaCluster,
+ akkaClusterTools,
+ akkaDistributedData,
akkaClusterSharding,
akkaBoostrap,
akkaSlf4j,
@@ -118,7 +133,14 @@ lazy val runtime = project.in(file("runtime"))
logback)
++ providedDeps(findbugs)
)
- .dependsOn(intermediateLanguage, testScope(recipeDsl), testScope(recipeCompiler), testScope(bakertypes))
+ .dependsOn(
+ intermediateLanguage,
+ `baker-interface`,
+ `baas-protocol-interaction-scheduling`,
+ `baas-protocol-recipe-event-publishing`,
+ testScope(recipeDsl),
+ testScope(recipeCompiler),
+ testScope(bakertypes))
.enablePlugins(MultiJvmPlugin)
.configs(MultiJvm)
@@ -177,17 +199,104 @@ lazy val recipeCompiler = project.in(file("compiler"))
)
.dependsOn(recipeDsl, intermediateLanguage, testScope(recipeDsl))
-lazy val baas = project.in(file("baas"))
+lazy val `baas-protocol-baker` = project.in(file("baas-protocol-baker"))
.settings(defaultModuleSettings)
.settings(scalaPBSettings)
.settings(
- moduleName := "baker-baas",
- libraryDependencies ++=
+ moduleName := "baas-protocol-baker",
+ libraryDependencies ++= Seq(
+ akkaStream,
+ akkaHttp
+ )
+ )
+ .dependsOn(`baker-interface`)
+
+lazy val `baas-protocol-interaction-scheduling` = project.in(file("baas-protocol-interaction-scheduling"))
+ .settings(defaultModuleSettings)
+ .settings(scalaPBSettings)
+ .settings(
+ moduleName := "baas-protocol-interaction-scheduling"
+ )
+ .dependsOn(`baker-interface`)
+
+lazy val `baas-protocol-recipe-event-publishing` = project.in(file("baas-protocol-recipe-event-publishing"))
+ .settings(defaultModuleSettings)
+ .settings(scalaPBSettings)
+ .settings(
+ moduleName := "baas-protocol-recipe-event-publishing"
+ )
+ .dependsOn(`baker-interface`)
+
+lazy val `baas-node-client` = project.in(file("baas-node-client"))
+ .settings(defaultModuleSettings)
+ .settings(
+ moduleName := "baas-node-client",
+ libraryDependencies ++= Seq(
+ akkaStream,
+ akkaHttp
+ )
+ )
+ .dependsOn(`baker-interface`, `baas-protocol-baker`)
+
+lazy val `baas-node-state` = project.in(file("baas-node-state"))
+ .enablePlugins(JavaAppPackaging)
+ .settings(commonSettings)
+ .settings(
+ moduleName := "baas-node-state",
+ scalacOptions ++= Seq(
+ "-Ypartial-unification"
+ ),
+ libraryDependencies ++= Seq(
+ akkaHttp,
+ akkaPersistenceCassandra,
+ akkaManagementHttp,
+ akkaClusterBoostrap,
+ akkaDiscoveryKube
+ )
+ )
+ .settings(
+ maintainer in Docker := "The Apollo Squad",
+ packageSummary in Docker := "The core node",
+ packageName in Docker := "baas-node-state",
+ dockerExposedPorts := Seq(8080)
+ )
+ .dependsOn(runtime, `baas-protocol-baker`, `baas-protocol-interaction-scheduling`)
+
+lazy val `baas-node-interaction` = project.in(file("baas-node-interaction"))
+ .settings(defaultModuleSettings)
+ .settings(
+ moduleName := "baas-node-interaction",
+ libraryDependencies ++= Seq(
+ akkaCluster,
+ akkaClusterTools,
+ slf4jApi
+ )
+ )
+ .dependsOn(`baas-protocol-interaction-scheduling`, `baker-interface`)
+
+lazy val `baas-node-event-listener` = project.in(file("baas-node-event-listener"))
+ .settings(defaultModuleSettings)
+ .settings(
+ moduleName := "baas-node-event-listener",
+ libraryDependencies ++= Seq(
+ akkaCluster,
+ akkaClusterTools,
+ slf4jApi
+ )
+ )
+ .dependsOn(`baas-protocol-recipe-event-publishing`, `baker-interface`)
+
+lazy val `baas-tests` = project.in(file("baas-tests"))
+ .settings(defaultModuleSettings)
+ .settings(noPublishSettings)
+ .settings(
+ moduleName := "baas-tests",
+ libraryDependencies ++= Seq() ++
testDeps(
akkaSlf4j,
akkaTestKit,
+ akkaInmemoryJournal,
logback,
- mockito,
scalaTest,
junitInterface,
levelDB,
@@ -195,13 +304,13 @@ lazy val baas = project.in(file("baas"))
scalaCheck
)
)
- .dependsOn(recipeDsl, recipeCompiler, intermediateLanguage, runtime, testScope(runtime))
+ .dependsOn(`baas-node-client`, `baas-node-state`, `baas-node-interaction`, `baas-node-event-listener`, recipeCompiler)
+ .aggregate(`baas-node-client`, `baas-node-state`, `baas-node-interaction`, `baas-node-event-listener`)
-lazy val baker = project
- .in(file("."))
+lazy val baker = project.in(file("."))
.settings(defaultModuleSettings)
.settings(noPublishSettings)
- .aggregate(bakertypes, runtime, recipeCompiler, recipeDsl, intermediateLanguage, splitBrainResolver, baas)
+ .aggregate(bakertypes, runtime, recipeCompiler, recipeDsl, intermediateLanguage, splitBrainResolver, `baas-tests`)
lazy val integration = project.in(file("integration"))
.dependsOn(testScope(runtime))
@@ -225,13 +334,42 @@ lazy val integration = project.in(file("integration"))
.enablePlugins(MultiJvmPlugin)
.configs(MultiJvm)
-lazy val examples = project
- .in(file("examples"))
+lazy val playground = project
+ .in(file("playground"))
+ .settings(
+ name := "baker-playground",
+ version := "0.1.0",
+ organization := "com.ing.baker",
+ scalaVersion := "2.12.4",
+ libraryDependencies ++= Seq(
+ catsEffect,
+ console4Cats,
+ scalaTest,
+ scalaCheck,
+ scalaLogging
+ ),
+ scalacOptions := Seq(
+ "-unchecked",
+ "-deprecation",
+ "-feature",
+ "-Ywarn-dead-code",
+ "-language:higherKinds",
+ "-language:existentials",
+ "-language:implicitConversions",
+ "-language:postfixOps",
+ "-encoding", "utf8",
+ s"-target:jvm-$jvmV",
+ "-Xfatal-warnings"
+ )
+ )
+
+lazy val `baker-example` = project
+ .in(file("examples/baker-example"))
.enablePlugins(JavaAppPackaging)
.settings(commonSettings)
.settings(noPublishSettings)
.settings(
- moduleName := "examples",
+ moduleName := "baker-example",
scalacOptions ++= Seq(
"-Ypartial-unification"
),
@@ -261,7 +399,173 @@ lazy val examples = project
.settings(
maintainer in Docker := "The Apollo Squad",
packageSummary in Docker := "A web-shop checkout service example running baker",
- packageName in Docker := "apollo.docker.ing.net/baker-example-app",
+ packageName in Docker := "baker-example-app",
dockerExposedPorts := Seq(8080)
)
.dependsOn(bakertypes, runtime, recipeCompiler, recipeDsl, intermediateLanguage)
+
+lazy val `baas-client-example` = project
+ .in(file("examples/baas-client-example"))
+ .enablePlugins(JavaAppPackaging)
+ .settings(commonSettings)
+ .settings(noPublishSettings)
+ .settings(
+ moduleName := "baas-client-example",
+ scalacOptions ++= Seq(
+ "-Ypartial-unification"
+ ),
+ libraryDependencies ++=
+ compileDeps(
+ slf4jApi,
+ slf4jSimple,
+ http4s,
+ http4sDsl,
+ http4sServer,
+ http4sCirce,
+ circe,
+ circeGeneric
+ ) ++ testDeps(
+ scalaTest,
+ scalaCheck
+ )
+ )
+ .settings(
+ maintainer in Docker := "The Apollo Squad",
+ packageSummary in Docker := "A web-shop checkout service example running on baas",
+ packageName in Docker := "baas-client-example",
+ dockerExposedPorts := Seq(8080)
+ )
+ .dependsOn(bakertypes, `baas-node-client`, recipeCompiler, recipeDsl)
+
+lazy val `baas-interactions-example` = project
+ .in(file("examples/baas-interactions-example"))
+ .enablePlugins(JavaAppPackaging)
+ .settings(commonSettings)
+ .settings(noPublishSettings)
+ .settings(
+ moduleName := "baas-interactions-example",
+ scalacOptions ++= Seq(
+ "-Ypartial-unification"
+ ),
+ libraryDependencies ++=
+ compileDeps(
+ slf4jApi,
+ slf4jSimple,
+ catsEffect
+ ) ++ testDeps(
+ scalaTest,
+ scalaCheck
+ )
+ )
+ .settings(
+ maintainer in Docker := "The Apollo Squad",
+ packageSummary in Docker := "A web-shop checkout service interaction instances example running on baas",
+ packageName in Docker := "baas-interactions-example",
+ dockerExposedPorts := Seq(2551)
+ )
+ .dependsOn(`baas-node-interaction`)
+
+lazy val `baas-event-listener-example` = project
+ .in(file("examples/baas-event-listener-example"))
+ .enablePlugins(JavaAppPackaging)
+ .settings(commonSettings)
+ .settings(noPublishSettings)
+ .settings(
+ moduleName := "baas-event-listener-example",
+ scalacOptions ++= Seq(
+ "-Ypartial-unification"
+ ),
+ libraryDependencies ++=
+ compileDeps(
+ slf4jApi,
+ slf4jSimple,
+ catsEffect
+ ) ++ testDeps(
+ scalaTest,
+ scalaCheck
+ )
+ )
+ .settings(
+ maintainer in Docker := "The Apollo Squad",
+ packageSummary in Docker := "A web-shop checkout service interaction instances example running on baas",
+ packageName in Docker := "baas-event-listener-example",
+ dockerExposedPorts := Seq(2551)
+ )
+ .dependsOn(`baas-node-event-listener`)
+
+lazy val `baas-minikube-state` = project.in(file("examples/baas-minikube-setup/baas-minikube-state"))
+ .enablePlugins(JavaAppPackaging)
+ .settings(commonSettings)
+ .settings(
+ moduleName := "baas-minikube-state",
+ scalacOptions ++= Seq(
+ "-Ypartial-unification"
+ ),
+ javaOptions in Universal ++= Seq("-Dconfig.resource=kubernetes.conf"),
+ mainClass in Compile := Some("com.ing.baker.baas.state.Main")
+ )
+ .settings(
+ maintainer in Docker := "The Apollo Squad",
+ packageSummary in Docker := "The core node",
+ packageName in Docker := "baas-minikube-state",
+ dockerExposedPorts := Seq(8080)
+ )
+ .dependsOn(`baas-node-state`)
+
+lazy val `baas-minikube-event-listener` = project.in(file("examples/baas-minikube-setup/baas-minikube-event-listener"))
+ .enablePlugins(JavaAppPackaging)
+ .settings(commonSettings)
+ .settings(
+ moduleName := "baas-minikube-event-listener",
+ scalacOptions ++= Seq(
+ "-Ypartial-unification"
+ ),
+ libraryDependencies ++=
+ compileDeps(
+ slf4jApi,
+ slf4jSimple,
+ catsEffect,
+ akkaManagementHttp,
+ akkaClusterBoostrap,
+ akkaDiscoveryKube
+ ) ++ testDeps(
+ scalaTest,
+ scalaCheck
+ )
+ )
+ .settings(
+ maintainer in Docker := "The Apollo Squad",
+ packageSummary in Docker := "The event listener node",
+ packageName in Docker := "baas-minikube-event-listener",
+ dockerExposedPorts := Seq()
+ )
+ .dependsOn(`baas-node-event-listener`)
+
+lazy val `baas-minikube-interactions` = project.in(file("examples/baas-minikube-setup/baas-minikube-interactions"))
+ .enablePlugins(JavaAppPackaging)
+ .settings(commonSettings)
+ .settings(
+ moduleName := "baas-minikube-interactions",
+ scalacOptions ++= Seq(
+ "-Ypartial-unification"
+ ),
+ libraryDependencies ++=
+ compileDeps(
+ slf4jApi,
+ slf4jSimple,
+ catsEffect,
+ akkaManagementHttp,
+ akkaClusterBoostrap,
+ akkaDiscoveryKube
+ ) ++ testDeps(
+ scalaTest,
+ scalaCheck
+ )
+ )
+ .settings(
+ maintainer in Docker := "The Apollo Squad",
+ packageSummary in Docker := "The interactions node",
+ packageName in Docker := "baas-minikube-interactions",
+ dockerExposedPorts := Seq()
+ )
+ .dependsOn(`baas-node-interaction`)
diff --git a/docs/sections/versions/baker-3-release-notes.md b/docs/sections/versions/baker-3-release-notes.md
index 13d93a7e2..59d961519 100644
--- a/docs/sections/versions/baker-3-release-notes.md
+++ b/docs/sections/versions/baker-3-release-notes.md
@@ -139,7 +139,7 @@ case class SensoryEventResult(
sensoryEventStatus: SensoryEventStatus,
eventNames: Seq[String],
ingredients: Map[String, Value]
-) extends common.SensoryEventResult with ScalaApi
+) extends com.ing.baker.runtime.common.SensoryEventResult with ScalaApi
```
```java tab="Java"
@@ -147,7 +147,7 @@ case class SensoryEventResult(
sensoryEventStatus: SensoryEventStatus,
eventNames: java.util.List[String],
ingredients: java.util.Map[String, Value]
-) extends common.SensoryEventResult with JavaApi {
+) extends com.ing.baker.runtime.common.SensoryEventResult with JavaApi {
def getSensoryEventStatus: SensoryEventStatus = sensoryEventStatus
diff --git a/docs/specs/GuildsAndAdventurers.tla b/docs/specs/GuildsAndAdventurers.tla
new file mode 100644
index 000000000..871a61802
--- /dev/null
+++ b/docs/specs/GuildsAndAdventurers.tla
@@ -0,0 +1,116 @@
+---------------------- MODULE InteractionManagerAgent ----------------------
+
+CONSTANTS GUILDS, ADVENTURERS
+
+VARIABLES guildsState, adventurersState
+
+----------------------------------------------------------------------------
+
+TypeOk == TRUE
+ /\ guildsState \in [GUILDS -> UNION {{ <<"requesting", "">>, <<"completed", "">>, <<"committed", adv>>} : adv \in ADVENTURERS}]
+ /\ adventurersState \in [ADVENTURERS -> UNION {{<<"looking-for-quest", "">>, <<"considering", guild>>, <<"committed", guild>>} : guild \in GUILDS}]
+
+Init ==
+ /\ guildsState = [guild \in GUILDS |-> <<"requesting", "">>]
+ /\ adventurersState = [adventurers \in ADVENTURERS |-> <<"looking-for-quest", "">>]
+
+AdventurerIsConsideringGuild(guild, adv) ==
+ adventurersState[adv] = <<"considering", guild>>
+
+AdventurerIsCommittedWithGuild(guild, adv) ==
+ adventurersState[adv] = <<"committed", guild>>
+
+GuildIsCommittedWithAdventurer(guild, adv) ==
+ guildsState[guild] = <<"committed", adv>>
+
+AreCommitted(guild, adv) ==
+ /\ GuildIsCommittedWithAdventurer(guild, adv)
+ /\ AdventurerIsCommittedWithGuild(guild, adv)
+
+MatchExistsBetween(guild, adv) ==
+ /\ guildsState[guild] = <<"requesting", "">>
+ /\ adventurersState[adv] = <<"looking-for-quest", "">>
+
+AdventurerIsReadyOk(guild, adv) ==
+ /\ guildsState[guild] = <<"requesting", "">>
+ /\ adventurersState[adv] = <<"considering", guild>>
+
+GuildIsReadyOk(guild, adv) ==
+ /\ guildsState[guild] = <<"committed", adv>>
+ /\ adventurersState[adv] = <<"considering", guild>>
+
+QuestInProgress(guild, adv) ==
+ AreCommitted(guild, adv)
+
+QuestWasAlreadyTakenByAdv1(guild, adv1, adv2) ==
+ /\ adv1 # adv2
+ /\ ( guildsState[guild] = <<"committed", adv1>> \/ guildsState[guild] = <<"completed", "">> )
+ /\ adventurersState[adv2] = <<"considering", guild>>
+
+----------------------------------------------------------------------------
+
+AdventurerConsidersAQuest ==
+ /\ \E <> \in GUILDS \X ADVENTURERS : MatchExistsBetween(guild, adv)
+ /\ LET guildAdv == CHOOSE <> \in GUILDS \X ADVENTURERS : MatchExistsBetween(guild, adv)
+ guild == guildAdv[1]
+ adv == guildAdv[2]
+ IN /\ adventurersState' = [adventurersState EXCEPT ![adv] = <<"considering", guild>>]
+ /\ UNCHANGED guildsState
+
+GuildCommitsToAnAdventurer ==
+ /\ \E <> \in GUILDS \X ADVENTURERS : AdventurerIsReadyOk(guild, adv)
+ /\ LET guildAdv == CHOOSE <> \in GUILDS \X ADVENTURERS : AdventurerIsReadyOk(guild, adv)
+ guild == guildAdv[1]
+ adv == guildAdv[2]
+ IN /\ guildsState' = [guildsState EXCEPT ![guild] = <<"committed", adv>>]
+ /\ UNCHANGED adventurersState
+
+AdventurerCommitsToAGuild ==
+ /\ \E <> \in GUILDS \X ADVENTURERS : GuildIsReadyOk(guild, adv)
+ /\ LET guildAdv == CHOOSE <> \in GUILDS \X ADVENTURERS : GuildIsReadyOk(guild, adv)
+ guild == guildAdv[1]
+ adv == guildAdv[2]
+ IN /\ adventurersState' = [adventurersState EXCEPT ![adv] = <<"committed", guild>>]
+ /\ UNCHANGED guildsState
+
+AdventurerDropsTakenQuest ==
+ /\ \E <> \in GUILDS \X ADVENTURERS \X ADVENTURERS: QuestWasAlreadyTakenByAdv1(guild, adv1, adv2)
+ /\ LET guildAdv == CHOOSE <> \in GUILDS \X ADVENTURERS \X ADVENTURERS : QuestWasAlreadyTakenByAdv1(guild, adv1, adv2)
+ guild == guildAdv[1]
+ adv == guildAdv[3]
+ IN /\ adventurersState' = [adventurersState EXCEPT ![adv] = <<"looking-for-quest", "">>]
+ /\ UNCHANGED guildsState
+
+AdventurerFinishesTheQuest ==
+ /\ \E <> \in GUILDS \X ADVENTURERS : QuestInProgress(guild, adv)
+ /\ LET guildAdv == CHOOSE <> \in GUILDS \X ADVENTURERS : QuestInProgress(guild, adv)
+ guild == guildAdv[1]
+ adv == guildAdv[2]
+ IN /\ adventurersState' = [adventurersState EXCEPT ![adv] = <<"looking-for-quest", "">>]
+ /\ guildsState' = [guildsState EXCEPT ![guild] = <<"completed", "">>]
+
+Next ==
+ \/ AdventurerConsidersAQuest
+ \/ GuildCommitsToAnAdventurer
+ \/ AdventurerCommitsToAGuild
+ \/ AdventurerFinishesTheQuest
+ \/ AdventurerDropsTakenQuest
+
+Spec ==
+ Init /\ [][Next]_<>
+
+Consistent ==
+ /\ \A <> \in GUILDS \X ADVENTURERS :
+ /\ GuildIsCommittedWithAdventurer(guild, adv) => ( AdventurerIsCommittedWithGuild(guild, adv) \/ AdventurerIsConsideringGuild(guild, adv) )
+ /\ AdventurerIsCommittedWithGuild(guild, adv) => GuildIsCommittedWithAdventurer(guild, adv)
+ /\ \A <> \in ADVENTURERS \X ADVENTURERS \X GUILDS :
+ ~ AreCommitted(guild, adv1) \/ ~ AreCommitted(guild, adv2) \/ adv1 = adv2
+
+----------------------------------------------------------------------------
+
+THEOREM Spec => [](TypeOk /\ Consistent)
+
+=============================================================================
+\* Modification History
+\* Last modified Mon Sep 09 16:41:00 CEST 2019 by atfm0
+\* Created Thu Sep 05 16:24:49 CEST 2019 by atfm0
diff --git a/examples/baas-client-example/src/main/resources/application.conf b/examples/baas-client-example/src/main/resources/application.conf
new file mode 100644
index 000000000..64b47302c
--- /dev/null
+++ b/examples/baas-client-example/src/main/resources/application.conf
@@ -0,0 +1,5 @@
+baas.hostname = "http://baker-haproxy:8080"
+baas.hostname = ${?BAAS_HOSTNAME}
+
+service.httpServerPort = 8080
+service.httpServerPort = ${?HTTP_PORT}
\ No newline at end of file
diff --git a/examples/src/main/resources/logback.xml b/examples/baas-client-example/src/main/resources/logback.xml
similarity index 100%
rename from examples/src/main/resources/logback.xml
rename to examples/baas-client-example/src/main/resources/logback.xml
diff --git a/examples/baas-client-example/src/main/scala/webshop/webservice/CheckoutFlowRecipe.scala b/examples/baas-client-example/src/main/scala/webshop/webservice/CheckoutFlowRecipe.scala
new file mode 100644
index 000000000..4f75e8d80
--- /dev/null
+++ b/examples/baas-client-example/src/main/scala/webshop/webservice/CheckoutFlowRecipe.scala
@@ -0,0 +1,122 @@
+package webshop.webservice
+
+import com.ing.baker.recipe.common.InteractionFailureStrategy.RetryWithIncrementalBackoff
+import com.ing.baker.recipe.scaladsl.{Event, Ingredient, Interaction, Recipe}
+import CheckoutFlowIngredients._
+import CheckoutFlowEvents._
+import CheckoutFlowInteractions._
+import com.ing.baker.recipe.common.InteractionFailureStrategy.RetryWithIncrementalBackoff.UntilMaximumRetries
+
+import scala.concurrent.Future
+import scala.concurrent.duration._
+
+object CheckoutFlowIngredients {
+
+ case class OrderId(orderId: String)
+
+ case class Item(itemId: String)
+
+ case class ReservedItems(items: List[Item], data: Array[Byte])
+
+ case class ShippingAddress(address: String)
+
+ case class PaymentInformation(info: String)
+
+ case class ShippingOrder(items: List[Item], data: Array[Byte], address: ShippingAddress)
+}
+
+object CheckoutFlowEvents {
+
+ case class OrderPlaced(orderId: OrderId, items: List[Item])
+
+ case class PaymentInformationReceived(paymentInformation: PaymentInformation)
+
+ case class ShippingAddressReceived(shippingAddress: ShippingAddress)
+
+ sealed trait ReserveItemsOutput
+
+ case class OrderHadUnavailableItems(unavailableItems: List[Item]) extends ReserveItemsOutput
+
+ case class ItemsReserved(reservedItems: ReservedItems) extends ReserveItemsOutput
+
+ sealed trait MakePaymentOutput
+
+ case class PaymentSuccessful(shippingOrder: ShippingOrder) extends MakePaymentOutput
+
+ case class PaymentFailed() extends MakePaymentOutput
+
+ case class ShippingConfirmed()
+}
+
+object CheckoutFlowInteractions {
+
+ trait ReserveItems {
+
+ def apply(orderId: OrderId, items: List[Item]): Future[ReserveItemsOutput]
+ }
+
+ def ReserveItemsInteraction = Interaction(
+ name = "ReserveItems",
+ inputIngredients = Seq(
+ Ingredient[OrderId]("orderId"),
+ Ingredient[List[Item]]("items")
+ ),
+ output = Seq(
+ Event[OrderHadUnavailableItems],
+ Event[ItemsReserved]
+ )
+ )
+
+ trait MakePayment {
+
+ def apply(processId: String, items: ReservedItems, address: ShippingAddress, payment: PaymentInformation): Future[MakePaymentOutput]
+ }
+
+ def MakePaymentInteraction = Interaction(
+ name = "MakePayment",
+ inputIngredients = Seq(
+ com.ing.baker.recipe.scaladsl.recipeInstanceId,
+ Ingredient[ReservedItems]("reservedItems"),
+ Ingredient[ShippingAddress]("shippingAddress"),
+ Ingredient[PaymentInformation]("paymentInformation")
+ ),
+ output = Seq(
+ Event[PaymentSuccessful],
+ Event[PaymentFailed]
+ )
+ )
+
+ trait ShipItems {
+
+ def apply(order: ShippingOrder): Future[ShippingConfirmed]
+ }
+
+ def ShipItemsInteraction = Interaction(
+ name = "ShipItems",
+ inputIngredients = Seq(
+ Ingredient[ShippingOrder]("shippingOrder")
+ ),
+ output = Seq(
+ Event[ShippingConfirmed]
+ )
+ )
+}
+
+object CheckoutFlowRecipe {
+
+ def recipe: Recipe = Recipe("Webshop")
+ .withSensoryEvents(
+ Event[OrderPlaced],
+ Event[PaymentInformationReceived],
+ Event[ShippingAddressReceived])
+ .withInteractions(
+ ReserveItemsInteraction,
+ MakePaymentInteraction,
+ ShipItemsInteraction)
+ .withDefaultFailureStrategy(
+ RetryWithIncrementalBackoff
+ .builder()
+ .withInitialDelay(1.second)
+ .withUntil(Some(UntilMaximumRetries(5)))
+ .build())
+}
diff --git a/examples/baas-client-example/src/main/scala/webshop/webservice/Main.scala b/examples/baas-client-example/src/main/scala/webshop/webservice/Main.scala
new file mode 100644
index 000000000..ab66742c8
--- /dev/null
+++ b/examples/baas-client-example/src/main/scala/webshop/webservice/Main.scala
@@ -0,0 +1,57 @@
+package webshop.webservice
+
+import akka.actor.ActorSystem
+import akka.http.scaladsl.model.Uri
+import akka.stream.ActorMaterializer
+import cats.effect.concurrent.Ref
+import cats.effect.{ExitCode, IO, IOApp, Resource}
+import cats.implicits._
+import com.ing.baker.baas.scaladsl.BakerClient
+import com.ing.baker.runtime.scaladsl._
+import com.typesafe.config.ConfigFactory
+import org.http4s.server.blaze.BlazeServerBuilder
+import org.log4s.Logger
+
+object Main extends IOApp {
+
+ case class SystemResources(actorSystem: ActorSystem, baker: Baker, app: WebShopService, port: Int, shuttingDown: Ref[IO, Boolean])
+
+ val logger: Logger = org.log4s.getLogger
+
+ val system: Resource[IO, SystemResources] =
+ Resource.make(
+ for {
+ actorSystem <- IO { ActorSystem("CheckoutService") }
+ config <- IO { ConfigFactory.load() }
+ materializer = ActorMaterializer()(actorSystem)
+ baasHostname = config.getString("baas.hostname")
+ baker <- IO { BakerClient(Uri.parseAbsolute(baasHostname))(actorSystem, materializer) }
+ checkoutRecipeId <- WebShopBaker.initRecipes(baker)(timer, actorSystem.dispatcher)
+ sd <- Ref.of[IO, Boolean](false)
+ webShopBaker = new WebShopBaker(baker, checkoutRecipeId)(actorSystem.dispatcher)
+ httpPort = config.getInt("service.httpServerPort")
+ app = new WebShopService(webShopBaker)
+ resources = SystemResources(actorSystem, baker, app, httpPort, sd)
+ } yield resources
+ )(resources =>
+ IO(logger.info("Shutting down the Checkout Service...")) *>
+ terminateActorSystem(resources)
+ )
+
+ def terminateActorSystem(resources: SystemResources): IO[Unit] =
+ IO.fromFuture(IO { resources.actorSystem.terminate() }).void
+
+ override def run(args: List[String]): IO[ExitCode] = {
+ system.flatMap { r =>
+
+ println(Console.GREEN + "Example client app started..." + Console.RESET)
+ sys.addShutdownHook(r.baker.gracefulShutdown())
+
+ BlazeServerBuilder[IO]
+ .bindHttp(r.port, "0.0.0.0")
+ .withHttpApp(r.app.buildHttpService(r.shuttingDown))
+ .resource
+ }.use(_ => IO.never).as(ExitCode.Success)
+ }
+
+}
diff --git a/examples/src/main/scala/webshop/webservice/OrderStatus.scala b/examples/baas-client-example/src/main/scala/webshop/webservice/OrderStatus.scala
similarity index 100%
rename from examples/src/main/scala/webshop/webservice/OrderStatus.scala
rename to examples/baas-client-example/src/main/scala/webshop/webservice/OrderStatus.scala
diff --git a/examples/src/main/scala/webshop/webservice/WebShop.scala b/examples/baas-client-example/src/main/scala/webshop/webservice/WebShop.scala
similarity index 100%
rename from examples/src/main/scala/webshop/webservice/WebShop.scala
rename to examples/baas-client-example/src/main/scala/webshop/webservice/WebShop.scala
diff --git a/examples/baas-client-example/src/main/scala/webshop/webservice/WebShopBaker.scala b/examples/baas-client-example/src/main/scala/webshop/webservice/WebShopBaker.scala
new file mode 100644
index 000000000..48acb8f2e
--- /dev/null
+++ b/examples/baas-client-example/src/main/scala/webshop/webservice/WebShopBaker.scala
@@ -0,0 +1,90 @@
+package webshop.webservice
+
+import java.util.UUID
+
+import cats.effect.{IO, Timer}
+import com.ing.baker.compiler.RecipeCompiler
+import com.ing.baker.il.CompiledRecipe
+import com.ing.baker.runtime.scaladsl.{Baker, EventInstance}
+import com.typesafe.scalalogging.LazyLogging
+import webshop.webservice.CheckoutFlowIngredients.{Item, OrderId, PaymentInformation, ShippingAddress}
+
+import scala.concurrent.{ExecutionContext, Future}
+
+object WebShopBaker extends LazyLogging {
+
+ val checkoutFlowCompiledRecipe: CompiledRecipe =
+ RecipeCompiler.compileRecipe(CheckoutFlowRecipe.recipe)
+
+ def initRecipes(baker: Baker)(implicit time: Timer[IO], ec: ExecutionContext): IO[String] = {
+ IO.fromFuture(IO(for {
+ checkoutRecipeId <- baker.addRecipe(checkoutFlowCompiledRecipe)
+ _ = println(Console.GREEN + "V3 Checkout Recipe ID :: " + checkoutRecipeId + Console.RESET)
+ } yield checkoutRecipeId))
+ }
+}
+
+class WebShopBaker(baker: Baker, checkoutRecipeId: String)(implicit ec: ExecutionContext) extends WebShop {
+
+ import WebShopBaker.logger
+
+ override def createCheckoutOrder(items: List[String]): IO[String] =
+ IO.fromFuture(IO {
+ val orderId: String = UUID.randomUUID().toString
+ val event = EventInstance.unsafeFrom(
+ CheckoutFlowEvents.OrderPlaced(OrderId(orderId), items.map(Item)))
+ for {
+ _ <- baker.bake(checkoutRecipeId, orderId)
+ status <- baker.fireEventAndResolveWhenReceived(orderId, event)
+ _ = logger.info(s"${event.name}[$orderId]: $status")
+ } yield orderId
+ })
+
+ override def addCheckoutAddressInfo(orderId: String, address: String): IO[Option[String]] =
+ IO.fromFuture(IO {
+ fireAndInformEvent(orderId, EventInstance.unsafeFrom(
+ CheckoutFlowEvents.ShippingAddressReceived(ShippingAddress(address))))
+ })
+
+ override def addCheckoutPaymentInfo(orderId: String, paymentInfo: String): IO[Option[String]] =
+ IO.fromFuture(IO {
+ fireAndInformEvent(orderId, EventInstance.unsafeFrom(
+ CheckoutFlowEvents.PaymentInformationReceived(PaymentInformation(paymentInfo))))
+ })
+
+ private def fireAndInformEvent(orderId: String, event: EventInstance): Future[Option[String]] = {
+ for {
+ status <- baker.fireEventAndResolveWhenReceived(orderId, event)
+ _ = logger.info(s"${event.name}[$orderId]: $status")
+ } yield None
+ }
+
+ override def pollOrderStatus(orderId: String): IO[OrderStatus] =
+ IO.fromFuture(IO {
+ for {
+ state <- baker.getRecipeInstanceState(orderId)
+ eventNames = state.events.map(_.name)
+ status = {
+ if (eventNames.contains("ShippingConfirmed"))
+ OrderStatus.Complete
+ else if (eventNames.contains("PaymentFailed"))
+ OrderStatus.PaymentFailed
+ else if (eventNames.contains("OrderHadUnavailableItems"))
+ OrderStatus.UnavailableItems(state.ingredients("unavailableItems").as[List[Item]].map(_.itemId))
+ else if (eventNames.containsSlice(List("ShippingAddressReceived", "PaymentInformationReceived")))
+ OrderStatus.ProcessingPayment
+ else if (eventNames.contains("PaymentSuccessful"))
+ OrderStatus.ShippingItems
+ else
+ OrderStatus.InfoPending(List("ShippingAddressReceived", "PaymentInformationReceived")
+ .filterNot(eventNames.contains)
+ .map(_.replace("Received", "")))
+ }
+ } yield status
+ })
+
+ override def gracefulShutdown: IO[Unit] =
+ IO {
+ baker.gracefulShutdown()
+ }
+}
diff --git a/examples/baas-client-example/src/main/scala/webshop/webservice/WebShopService.scala b/examples/baas-client-example/src/main/scala/webshop/webservice/WebShopService.scala
new file mode 100644
index 000000000..6e03544f5
--- /dev/null
+++ b/examples/baas-client-example/src/main/scala/webshop/webservice/WebShopService.scala
@@ -0,0 +1,113 @@
+package webshop.webservice
+
+import java.io.File
+import java.util.concurrent.Executors
+
+import cats.data.Kleisli
+import cats.effect.concurrent.Ref
+import cats.effect.{ContextShift, IO, Timer}
+import cats.implicits._
+import io.circe.generic.auto._
+import io.circe.syntax._
+import org.http4s._
+import org.http4s.circe._
+import org.http4s.dsl.io._
+import org.http4s.implicits._
+import org.http4s.server.Router
+
+import scala.concurrent.ExecutionContext
+
+object WebShopService {
+
+ case class PlaceOrderRequest(items: List[String])
+
+ case class PlaceOrderResponse(orderId: String)
+
+ case class AddAddressRequest(address: String)
+
+ case class AddPaymentRequest(payment: String)
+
+ case class PollPaymentStatusResponse(status: String)
+
+}
+
+class WebShopService(webshop: WebShop)(implicit timer: Timer[IO], cs: ContextShift[IO]) {
+
+ import WebShopService._
+
+ implicit val placeOrderRequestDecoder: EntityDecoder[IO, PlaceOrderRequest] =
+ jsonOf[IO, PlaceOrderRequest]
+ implicit val addAddressRequestDecoder: EntityDecoder[IO, AddAddressRequest] =
+ jsonOf[IO, AddAddressRequest]
+ implicit val addPaymentRequestDecoder: EntityDecoder[IO, AddPaymentRequest] =
+ jsonOf[IO, AddPaymentRequest]
+
+ val blockingEc = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(4))
+
+ def buildHttpService(shuttingDown: Ref[IO, Boolean]): Kleisli[IO, Request[IO], Response[IO]] =
+ (Router("/" -> HttpRoutes.of[IO] {
+
+ case GET -> Root => Ok("Ok")
+
+ case HEAD -> Root =>
+ shuttingDown.get.flatMap {
+ case true => NotFound()
+ case false => Ok()
+ }
+
+ }) <+>
+ Router("/admin" -> HttpRoutes.of[IO] {
+
+ case GET -> Root / "shutdown" =>
+ for {
+ _ <- shuttingDown.modify(_ => (true, ()))
+ _ <- webshop.gracefulShutdown
+ response <- Ok("down")
+ } yield response
+ }) <+>
+ Router("/api" -> HttpRoutes.of[IO] {
+
+ case GET -> Root =>
+ Ok("Ok")
+
+ case req@POST -> Root / "order" =>
+ for {
+ request <- req.as[PlaceOrderRequest]
+ orderId <- webshop.createCheckoutOrder(request.items)
+ response <- Ok(PlaceOrderResponse(orderId).asJson)
+ } yield response
+
+ case req@PUT -> Root / "order" / orderId / "address" =>
+ for {
+ request <- req.as[AddAddressRequest]
+ _ <- webshop.addCheckoutAddressInfo(orderId, request.address)
+ response <- Ok()
+ } yield response
+
+ case req@PUT -> Root / "order" / orderId / "payment" =>
+ for {
+ request <- req.as[AddPaymentRequest]
+ _ <- webshop.addCheckoutPaymentInfo(orderId, request.payment)
+ response <- Ok()
+ } yield response
+
+ case GET -> Root / "order" / orderId =>
+ for {
+ status <- webshop.pollOrderStatus(orderId)
+ response <- Ok(PollPaymentStatusResponse(status.toString).asJson)
+ } yield response
+
+ })).orNotFound
+
+ import java.lang.management.ManagementFactory
+
+ import com.sun.management.HotSpotDiagnosticMXBean
+
+ def dumpHeap(filePath: String, live: Boolean): IO[Unit] = IO {
+ val file = new File(filePath)
+ if (file.exists()) file.delete()
+ val server = ManagementFactory.getPlatformMBeanServer
+ val mxBean = ManagementFactory.newPlatformMXBeanProxy(server, "com.sun.management:type=HotSpotDiagnostic", classOf[HotSpotDiagnosticMXBean])
+ mxBean.dumpHeap(filePath, live)
+ }
+}
diff --git a/examples/baas-event-listener-example/src/main/resources/application.conf b/examples/baas-event-listener-example/src/main/resources/application.conf
new file mode 100644
index 000000000..790ddda09
--- /dev/null
+++ b/examples/baas-event-listener-example/src/main/resources/application.conf
@@ -0,0 +1,47 @@
+
+service {
+
+ actorSystemName = "BaaS"
+ actorSystemName = ${?ACTOR_SYSTEM_NAME}
+
+ clusterHost = "127.0.0.1"
+ clusterHost = ${?CLUSTER_HOST}
+
+ clusterPort = 2551
+ clusterPort = ${?CLUSTER_PORT}
+
+ seedHost = "127.0.0.1"
+ seedHost = ${?CLUSTER_SEED_HOST}
+
+ seedPort = 2551
+ seedPort = ${?CLUSTER_SEED_PORT}
+}
+
+akka.actor.allow-java-serialization = on
+akka.cluster.configuration-compatibility-check.enforce-on-join = off
+
+akka {
+
+ actor {
+ provider = "cluster"
+ }
+
+ remote {
+ log-remote-lifecycle-events = off
+ netty.tcp {
+ hostname = ${service.clusterHost}
+ port = ${service.clusterPort}
+ }
+ }
+
+ cluster {
+
+ seed-nodes = [
+ "akka.tcp://"${service.actorSystemName}"@"${service.seedHost}":"${service.seedPort}]
+
+ # auto downing is NOT safe for production deployments.
+ # you may want to use it during development, read more about it in the docs.
+ #
+ # auto-down-unreachable-after = 10s
+ }
+}
diff --git a/examples/baas-event-listener-example/src/main/scala/webshop/webservice/Main.scala b/examples/baas-event-listener-example/src/main/scala/webshop/webservice/Main.scala
new file mode 100644
index 000000000..ae3815f3c
--- /dev/null
+++ b/examples/baas-event-listener-example/src/main/scala/webshop/webservice/Main.scala
@@ -0,0 +1,15 @@
+package webshop.webservice
+
+import akka.actor.ActorSystem
+import com.ing.baker.baas.scaladsl.BaaSEventListener
+import com.typesafe.scalalogging.LazyLogging
+
+object Main extends App with LazyLogging {
+
+ val actorSystem = ActorSystem("BaaS") // TODO: This should be done by the BaaSInteractionInstance ecosystem to ease the configuration and improve the UX
+ val ecosystem = BaaSEventListener(actorSystem)
+
+ ecosystem.registerEventListener("Webshop", (metadata, event) => {
+ logger.info("%s [%s] %s", metadata.recipeName, metadata.recipeInstanceId, event.name)
+ })
+}
diff --git a/examples/baas-interactions-example/src/main/resources/application.conf b/examples/baas-interactions-example/src/main/resources/application.conf
new file mode 100644
index 000000000..790ddda09
--- /dev/null
+++ b/examples/baas-interactions-example/src/main/resources/application.conf
@@ -0,0 +1,47 @@
+
+service {
+
+ actorSystemName = "BaaS"
+ actorSystemName = ${?ACTOR_SYSTEM_NAME}
+
+ clusterHost = "127.0.0.1"
+ clusterHost = ${?CLUSTER_HOST}
+
+ clusterPort = 2551
+ clusterPort = ${?CLUSTER_PORT}
+
+ seedHost = "127.0.0.1"
+ seedHost = ${?CLUSTER_SEED_HOST}
+
+ seedPort = 2551
+ seedPort = ${?CLUSTER_SEED_PORT}
+}
+
+akka.actor.allow-java-serialization = on
+akka.cluster.configuration-compatibility-check.enforce-on-join = off
+
+akka {
+
+ actor {
+ provider = "cluster"
+ }
+
+ remote {
+ log-remote-lifecycle-events = off
+ netty.tcp {
+ hostname = ${service.clusterHost}
+ port = ${service.clusterPort}
+ }
+ }
+
+ cluster {
+
+ seed-nodes = [
+ "akka.tcp://"${service.actorSystemName}"@"${service.seedHost}":"${service.seedPort}]
+
+ # auto downing is NOT safe for production deployments.
+ # you may want to use it during development, read more about it in the docs.
+ #
+ # auto-down-unreachable-after = 10s
+ }
+}
diff --git a/examples/baas-interactions-example/src/main/scala/webshop/webservice/CheckoutFlowRecipe.scala b/examples/baas-interactions-example/src/main/scala/webshop/webservice/CheckoutFlowRecipe.scala
new file mode 100644
index 000000000..c2df108fa
--- /dev/null
+++ b/examples/baas-interactions-example/src/main/scala/webshop/webservice/CheckoutFlowRecipe.scala
@@ -0,0 +1,62 @@
+package webshop.webservice
+
+import CheckoutFlowIngredients._
+import CheckoutFlowEvents._
+
+import scala.concurrent.Future
+
+object CheckoutFlowIngredients {
+
+ case class OrderId(orderId: String)
+
+ case class Item(itemId: String)
+
+ case class ReservedItems(items: List[Item], data: Array[Byte])
+
+ case class ShippingAddress(address: String)
+
+ case class PaymentInformation(info: String)
+
+ case class ShippingOrder(items: List[Item], data: Array[Byte], address: ShippingAddress)
+}
+
+object CheckoutFlowEvents {
+
+ case class OrderPlaced(orderId: OrderId, items: List[Item])
+
+ case class PaymentInformationReceived(paymentInformation: PaymentInformation)
+
+ case class ShippingAddressReceived(shippingAddress: ShippingAddress)
+
+ sealed trait ReserveItemsOutput
+
+ case class OrderHadUnavailableItems(unavailableItems: List[Item]) extends ReserveItemsOutput
+
+ case class ItemsReserved(reservedItems: ReservedItems) extends ReserveItemsOutput
+
+ sealed trait MakePaymentOutput
+
+ case class PaymentSuccessful(shippingOrder: ShippingOrder) extends MakePaymentOutput
+
+ case class PaymentFailed() extends MakePaymentOutput
+
+ case class ShippingConfirmed()
+}
+
+object CheckoutFlowInteractions {
+
+ trait ReserveItems {
+
+ def apply(orderId: OrderId, items: List[Item]): Future[ReserveItemsOutput]
+ }
+
+ trait MakePayment {
+
+ def apply(processId: String, items: ReservedItems, address: ShippingAddress, payment: PaymentInformation): Future[MakePaymentOutput]
+ }
+
+ trait ShipItems {
+
+ def apply(order: ShippingOrder): Future[ShippingConfirmed]
+ }
+}
diff --git a/examples/baas-interactions-example/src/main/scala/webshop/webservice/Main.scala b/examples/baas-interactions-example/src/main/scala/webshop/webservice/Main.scala
new file mode 100644
index 000000000..a08b8d447
--- /dev/null
+++ b/examples/baas-interactions-example/src/main/scala/webshop/webservice/Main.scala
@@ -0,0 +1,23 @@
+package webshop.webservice
+
+import akka.actor.ActorSystem
+import cats.effect.IO
+import com.ing.baker.baas.scaladsl.BaaSInteractionInstance
+import com.ing.baker.runtime.scaladsl.InteractionInstance
+
+object Main extends App {
+
+ val actorSystem = ActorSystem("BaaS") // This should be done by the BaaSInteractionInstance ecosystem to ease the configuration and improve the UX
+ val ecosystem = BaaSInteractionInstance(actorSystem)
+ val timer = IO.timer(actorSystem.dispatcher)
+
+ import actorSystem.dispatcher
+
+ val instances = InteractionInstance.unsafeFromList(List(
+ new MakePaymentInstance()(timer),
+ new ReserveItemsInstance()(timer),
+ new ShipItemsInstance()(timer)
+ ))
+
+ ecosystem.load(instances: _*)
+}
diff --git a/examples/baas-interactions-example/src/main/scala/webshop/webservice/MakePaymentInstance.scala b/examples/baas-interactions-example/src/main/scala/webshop/webservice/MakePaymentInstance.scala
new file mode 100644
index 000000000..a78c49088
--- /dev/null
+++ b/examples/baas-interactions-example/src/main/scala/webshop/webservice/MakePaymentInstance.scala
@@ -0,0 +1,20 @@
+package webshop.webservice
+
+import cats.effect.{IO, Timer}
+import webshop.webservice.CheckoutFlowEvents.MakePaymentOutput
+import webshop.webservice.CheckoutFlowIngredients.{PaymentInformation, ReservedItems, ShippingAddress, ShippingOrder}
+import webshop.webservice.CheckoutFlowInteractions.MakePayment
+
+import scala.concurrent.Future
+import scala.concurrent.duration._
+
+class MakePaymentInstance(implicit timer: Timer[IO]) extends MakePayment {
+
+ override def apply(processId: String, items: ReservedItems, address: ShippingAddress, payment: PaymentInformation): Future[MakePaymentOutput] = {
+ IO.sleep(5.second)
+ .map(_ => println(Console.GREEN + processId + Console.RESET))
+ .map(_ => CheckoutFlowEvents.PaymentSuccessful(ShippingOrder(items.items, items.data, address)))
+ .unsafeToFuture()
+ }
+}
+
diff --git a/examples/src/main/scala/webshop/webservice/ReserveItemsInstance.scala b/examples/baas-interactions-example/src/main/scala/webshop/webservice/ReserveItemsInstance.scala
similarity index 96%
rename from examples/src/main/scala/webshop/webservice/ReserveItemsInstance.scala
rename to examples/baas-interactions-example/src/main/scala/webshop/webservice/ReserveItemsInstance.scala
index 140f6e003..b6d1634ac 100644
--- a/examples/src/main/scala/webshop/webservice/ReserveItemsInstance.scala
+++ b/examples/baas-interactions-example/src/main/scala/webshop/webservice/ReserveItemsInstance.scala
@@ -1,7 +1,7 @@
package webshop.webservice
-import cats.implicits._
import cats.effect.{IO, Timer}
+import cats.implicits._
import webshop.webservice.CheckoutFlowEvents.ReserveItemsOutput
import webshop.webservice.CheckoutFlowIngredients.{Item, OrderId, ReservedItems}
import webshop.webservice.CheckoutFlowInteractions.ReserveItems
@@ -12,7 +12,7 @@ import scala.concurrent.duration._
class ReserveItemsInstance(implicit timer: Timer[IO]) extends ReserveItems {
override def apply(orderId: OrderId, items: List[Item]): Future[ReserveItemsOutput] = {
- IO.sleep(1 second)
+ IO.sleep(1.second)
.as(CheckoutFlowEvents.ItemsReserved(ReservedItems(items, Array.fill(1000)(Byte.MaxValue))))
.unsafeToFuture()
}
diff --git a/examples/src/main/scala/webshop/webservice/ShipItemsInstance.scala b/examples/baas-interactions-example/src/main/scala/webshop/webservice/ShipItemsInstance.scala
similarity index 95%
rename from examples/src/main/scala/webshop/webservice/ShipItemsInstance.scala
rename to examples/baas-interactions-example/src/main/scala/webshop/webservice/ShipItemsInstance.scala
index 3dea936ad..c9424a151 100644
--- a/examples/src/main/scala/webshop/webservice/ShipItemsInstance.scala
+++ b/examples/baas-interactions-example/src/main/scala/webshop/webservice/ShipItemsInstance.scala
@@ -1,7 +1,7 @@
package webshop.webservice
-import cats.implicits._
import cats.effect.{IO, Timer}
+import cats.implicits._
import webshop.webservice.CheckoutFlowEvents.ShippingConfirmed
import webshop.webservice.CheckoutFlowIngredients.ShippingOrder
import webshop.webservice.CheckoutFlowInteractions.ShipItems
@@ -12,7 +12,7 @@ import scala.concurrent.duration._
class ShipItemsInstance(implicit timer: Timer[IO]) extends ShipItems {
override def apply(order: ShippingOrder): Future[ShippingConfirmed] = {
- IO.sleep(500 millis)
+ IO.sleep(500.millis)
.as(ShippingConfirmed())
.unsafeToFuture()
}
diff --git a/examples/baas-minikube-setup/README.md b/examples/baas-minikube-setup/README.md
new file mode 100644
index 000000000..0e4e20b90
--- /dev/null
+++ b/examples/baas-minikube-setup/README.md
@@ -0,0 +1,22 @@
+# Running minikube locally
+
+## Install docker
+https://docs.docker.com/install/
+
+##Install VirtualBox
+https://www.virtualbox.org/wiki/Downloads
+
+##Install Minikube
+https://kubernetes.io/docs/tasks/tools/install-minikube/
+
+##Create and start minikube cluster via VirtualBox
+Execute `/baas-openshift-scripts/minikube/createMinikubeNamespace.sh`
+
+##[Optional] Run minikube dashboard
+Execute `minikube dashboard`
+
+## Build example Docker images
+`/examples/baas-minikube-setup/build-and-publish-images.sh`
+
+##Deploy PODs to minikube
+`kubectl apply -f /examples/baas-minikube-setup/baas-kubernetes-example.yml`
\ No newline at end of file
diff --git a/examples/baas-minikube-setup/baas-kubernetes-example.yml b/examples/baas-minikube-setup/baas-kubernetes-example.yml
new file mode 100644
index 000000000..6f1388dc7
--- /dev/null
+++ b/examples/baas-minikube-setup/baas-kubernetes-example.yml
@@ -0,0 +1,233 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ labels:
+ app: baas-state
+ name: baas-state
+spec:
+ replicas: 2
+ selector:
+ matchLabels:
+ app: baas-state
+ template:
+ metadata:
+ labels:
+ app: baas-state
+ actorSystemName: BaaS
+ spec:
+ containers:
+ - name: baas-state
+ image: baas-minikube-state:3.0.2-SNAPSHOT
+ imagePullPolicy: Never
+ readinessProbe:
+ httpGet:
+ path: /health/ready
+ port: 8558
+ livenessProbe:
+ httpGet:
+ path: /health/alive
+ port: 8558
+ ports:
+ # akka remoting
+ - name: remoting
+ containerPort: 2552
+ protocol: TCP
+ # akka-management and bootstrap
+ - name: management
+ containerPort: 8558
+ protocol: TCP
+ - name: webaccess
+ containerPort: 8080
+ protocol: TCP
+ #namespace
+ env:
+ - name: NAMESPACE
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.namespace
+---
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ labels:
+ app: baas-interactions
+ name: baas-interactions
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: baas-interactions
+ template:
+ metadata:
+ labels:
+ app: baas-interactions
+ actorSystemName: BaaS
+ spec:
+ containers:
+ - name: baas-interactions
+ image: baas-minikube-interactions:3.0.2-SNAPSHOT
+ imagePullPolicy: Never
+ readinessProbe:
+ httpGet:
+ path: /health/ready
+ port: 8558
+ livenessProbe:
+ httpGet:
+ path: /health/alive
+ port: 8558
+ ports:
+ # akka remoting
+ - name: remoting
+ containerPort: 2552
+ protocol: TCP
+ # akka-management and bootstrap
+ - name: management
+ containerPort: 8558
+ protocol: TCP
+ #namespace
+ env:
+ - name: NAMESPACE
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.namespace
+---
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ labels:
+ app: baas-event-listener
+ name: baas-event-listener
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: baas-event-listener
+ template:
+ metadata:
+ labels:
+ app: baas-event-listener
+ actorSystemName: BaaS
+ spec:
+ containers:
+ - name: baas-event-listener
+ image: baas-minikube-event-listener:3.0.2-SNAPSHOT
+ imagePullPolicy: Never
+ readinessProbe:
+ httpGet:
+ path: /health/ready
+ port: 8558
+ livenessProbe:
+ httpGet:
+ path: /health/alive
+ port: 8558
+ ports:
+ # akka remoting
+ - name: remoting
+ containerPort: 2552
+ protocol: TCP
+ # akka-management and bootstrap
+ - name: management
+ containerPort: 8558
+ protocol: TCP
+ #namespace
+ env:
+ - name: NAMESPACE
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.namespace
+---
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ labels:
+ app: client-app
+ name: client-app
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: client-app
+ template:
+ metadata:
+ labels:
+ app: client-app
+ spec:
+ containers:
+ - name: client-app
+ image: baas-client-example:3.0.2-SNAPSHOT
+ imagePullPolicy: Never
+ readinessProbe:
+ httpGet:
+ path: /api
+ port: 8080
+ livenessProbe:
+ httpGet:
+ path: /api
+ port: 8080
+ ports:
+ - name: http
+ containerPort: 8080
+ protocol: TCP
+ env:
+ - name: BAAS_HOSTNAME
+ value: http://baas-state-service:8080/
+---
+
+kind: Role
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: pod-reader
+rules:
+ - apiGroups: [""] # "" indicates the core API group
+ resources: ["pods"]
+ verbs: ["get", "watch", "list"]
+---
+kind: RoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+ name: read-pods
+subjects:
+ # Note the `name` line below. The first default refers to the namespace. The second refers to the service account name.
+ # For instance, `name: system:serviceaccount:myns:default` would refer to the default service account in namespace `myns`
+ - kind: User
+ name: system:serviceaccount:default:default
+roleRef:
+ kind: Role
+ name: pod-reader
+ apiGroup: rbac.authorization.k8s.io
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: baas-state-service
+ labels:
+ run: baas-state-service
+spec:
+ selector:
+ app: baas-state
+ ports:
+ - port: 8080
+ protocol: TCP
+ type: LoadBalancer
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: client-app-service
+ labels:
+ run: client-app-service
+spec:
+ selector:
+ app: client-app
+ ports:
+ - port: 8080
+ protocol: TCP
+ type: LoadBalancer
+
+# Run this command to expose the service to minikube
+# minikube service baas-state-service
diff --git a/examples/baas-minikube-setup/baas-minikube-event-listener/src/main/resources/application.conf b/examples/baas-minikube-setup/baas-minikube-event-listener/src/main/resources/application.conf
new file mode 100644
index 000000000..d8fa215b6
--- /dev/null
+++ b/examples/baas-minikube-setup/baas-minikube-event-listener/src/main/resources/application.conf
@@ -0,0 +1,46 @@
+
+akka {
+
+ actor {
+ provider = "cluster"
+ }
+
+ cluster {
+
+ roles = ["event-listener-node"]
+
+ configuration-compatibility-check.enforce-on-join = off
+ }
+
+ discovery {
+ kubernetes-api {
+ pod-label-selector = "actorSystemName=%s"
+ }
+ }
+
+ management {
+
+ http.routes {
+ cluster-management = ""
+ }
+
+ cluster.bootstrap {
+ contact-point-discovery {
+ # For the kubernetes API this value is substituted in the %s in pod-label-selector
+ service-name = "BaaS"
+
+ # pick the discovery method you'd like to use:
+ discovery-method = kubernetes-api
+ }
+ }
+
+ health-checks {
+ readiness-path = "health/ready"
+ liveness-path = "health/alive"
+
+ liveness-checks {
+ cluster-health = "webshop.webservice.ClusterHealthCheck"
+ }
+ }
+ }
+}
diff --git a/examples/baas-minikube-setup/baas-minikube-event-listener/src/main/scala/webshop/webservice/ClusterHealthCheck.scala b/examples/baas-minikube-setup/baas-minikube-event-listener/src/main/scala/webshop/webservice/ClusterHealthCheck.scala
new file mode 100644
index 000000000..a6ae41f89
--- /dev/null
+++ b/examples/baas-minikube-setup/baas-minikube-event-listener/src/main/scala/webshop/webservice/ClusterHealthCheck.scala
@@ -0,0 +1,13 @@
+package webshop.webservice
+
+import akka.actor.ActorSystem
+import akka.cluster.{Cluster, MemberStatus}
+
+import scala.concurrent.Future
+
+class ClusterHealthCheck(system: ActorSystem) extends (() => Future[Boolean]) {
+ private val cluster = Cluster(system)
+ override def apply(): Future[Boolean] = {
+ Future.successful(cluster.selfMember.status == MemberStatus.Up)
+ }
+}
diff --git a/examples/baas-minikube-setup/baas-minikube-event-listener/src/main/scala/webshop/webservice/Main.scala b/examples/baas-minikube-setup/baas-minikube-event-listener/src/main/scala/webshop/webservice/Main.scala
new file mode 100644
index 000000000..b70b4a782
--- /dev/null
+++ b/examples/baas-minikube-setup/baas-minikube-event-listener/src/main/scala/webshop/webservice/Main.scala
@@ -0,0 +1,19 @@
+package webshop.webservice
+
+import akka.actor.ActorSystem
+import akka.management.cluster.bootstrap.ClusterBootstrap
+import akka.management.scaladsl.AkkaManagement
+import com.ing.baker.baas.scaladsl.BaaSEventListener
+import com.typesafe.scalalogging.LazyLogging
+
+object Main extends App with LazyLogging {
+
+ val actorSystem = ActorSystem("BaaS") // This should be done by the BaaSInteractionInstance ecosystem to ease the configuration and improve the UX
+ AkkaManagement(actorSystem).start()
+ ClusterBootstrap(actorSystem).start()
+ val ecosystem = BaaSEventListener(actorSystem)
+
+ ecosystem.registerEventListener("Webshop", (metadata, event) => {
+ logger.info(metadata.recipeName + " [" + metadata.recipeInstanceId + "] " + event.name)
+ })
+}
diff --git a/examples/baas-minikube-setup/baas-minikube-interactions/src/main/resources/application.conf b/examples/baas-minikube-setup/baas-minikube-interactions/src/main/resources/application.conf
new file mode 100644
index 000000000..ffe992895
--- /dev/null
+++ b/examples/baas-minikube-setup/baas-minikube-interactions/src/main/resources/application.conf
@@ -0,0 +1,46 @@
+
+akka {
+
+ actor {
+ provider = "cluster"
+ }
+
+ cluster {
+
+ roles = ["interactions-node"]
+
+ configuration-compatibility-check.enforce-on-join = off
+ }
+
+ discovery {
+ kubernetes-api {
+ pod-label-selector = "actorSystemName=%s"
+ }
+ }
+
+ management {
+
+ http.routes {
+ cluster-management = ""
+ }
+
+ cluster.bootstrap {
+ contact-point-discovery {
+ # For the kubernetes API this value is substituted in the %s in pod-label-selector
+ service-name = "BaaS"
+
+ # pick the discovery method you'd like to use:
+ discovery-method = kubernetes-api
+ }
+ }
+
+ health-checks {
+ readiness-path = "health/ready"
+ liveness-path = "health/alive"
+
+ liveness-checks {
+ cluster-health = "webshop.webservice.ClusterHealthCheck"
+ }
+ }
+ }
+}
diff --git a/examples/baas-minikube-setup/baas-minikube-interactions/src/main/scala/webshop/webservice/CheckoutFlowRecipe.scala b/examples/baas-minikube-setup/baas-minikube-interactions/src/main/scala/webshop/webservice/CheckoutFlowRecipe.scala
new file mode 100644
index 000000000..c2df108fa
--- /dev/null
+++ b/examples/baas-minikube-setup/baas-minikube-interactions/src/main/scala/webshop/webservice/CheckoutFlowRecipe.scala
@@ -0,0 +1,62 @@
+package webshop.webservice
+
+import CheckoutFlowIngredients._
+import CheckoutFlowEvents._
+
+import scala.concurrent.Future
+
+object CheckoutFlowIngredients {
+
+ case class OrderId(orderId: String)
+
+ case class Item(itemId: String)
+
+ case class ReservedItems(items: List[Item], data: Array[Byte])
+
+ case class ShippingAddress(address: String)
+
+ case class PaymentInformation(info: String)
+
+ case class ShippingOrder(items: List[Item], data: Array[Byte], address: ShippingAddress)
+}
+
+object CheckoutFlowEvents {
+
+ case class OrderPlaced(orderId: OrderId, items: List[Item])
+
+ case class PaymentInformationReceived(paymentInformation: PaymentInformation)
+
+ case class ShippingAddressReceived(shippingAddress: ShippingAddress)
+
+ sealed trait ReserveItemsOutput
+
+ case class OrderHadUnavailableItems(unavailableItems: List[Item]) extends ReserveItemsOutput
+
+ case class ItemsReserved(reservedItems: ReservedItems) extends ReserveItemsOutput
+
+ sealed trait MakePaymentOutput
+
+ case class PaymentSuccessful(shippingOrder: ShippingOrder) extends MakePaymentOutput
+
+ case class PaymentFailed() extends MakePaymentOutput
+
+ case class ShippingConfirmed()
+}
+
+object CheckoutFlowInteractions {
+
+ trait ReserveItems {
+
+ def apply(orderId: OrderId, items: List[Item]): Future[ReserveItemsOutput]
+ }
+
+ trait MakePayment {
+
+ def apply(processId: String, items: ReservedItems, address: ShippingAddress, payment: PaymentInformation): Future[MakePaymentOutput]
+ }
+
+ trait ShipItems {
+
+ def apply(order: ShippingOrder): Future[ShippingConfirmed]
+ }
+}
diff --git a/examples/baas-minikube-setup/baas-minikube-interactions/src/main/scala/webshop/webservice/ClusterHealthCheck.scala b/examples/baas-minikube-setup/baas-minikube-interactions/src/main/scala/webshop/webservice/ClusterHealthCheck.scala
new file mode 100644
index 000000000..a6ae41f89
--- /dev/null
+++ b/examples/baas-minikube-setup/baas-minikube-interactions/src/main/scala/webshop/webservice/ClusterHealthCheck.scala
@@ -0,0 +1,13 @@
+package webshop.webservice
+
+import akka.actor.ActorSystem
+import akka.cluster.{Cluster, MemberStatus}
+
+import scala.concurrent.Future
+
+class ClusterHealthCheck(system: ActorSystem) extends (() => Future[Boolean]) {
+ private val cluster = Cluster(system)
+ override def apply(): Future[Boolean] = {
+ Future.successful(cluster.selfMember.status == MemberStatus.Up)
+ }
+}
diff --git a/examples/baas-minikube-setup/baas-minikube-interactions/src/main/scala/webshop/webservice/Main.scala b/examples/baas-minikube-setup/baas-minikube-interactions/src/main/scala/webshop/webservice/Main.scala
new file mode 100644
index 000000000..1a597bc56
--- /dev/null
+++ b/examples/baas-minikube-setup/baas-minikube-interactions/src/main/scala/webshop/webservice/Main.scala
@@ -0,0 +1,27 @@
+package webshop.webservice
+
+import akka.actor.ActorSystem
+import akka.management.cluster.bootstrap.ClusterBootstrap
+import akka.management.scaladsl.AkkaManagement
+import cats.effect.IO
+import com.ing.baker.baas.scaladsl.BaaSInteractionInstance
+import com.ing.baker.runtime.scaladsl.InteractionInstance
+
+object Main extends App {
+
+ val actorSystem = ActorSystem("BaaS") // This should be done by the BaaSInteractionInstance ecosystem to ease the configuration and improve the UX
+ AkkaManagement(actorSystem).start()
+ ClusterBootstrap(actorSystem).start()
+ val ecosystem = BaaSInteractionInstance(actorSystem)
+ val timer = IO.timer(actorSystem.dispatcher)
+
+ import actorSystem.dispatcher
+
+ val instances = InteractionInstance.unsafeFromList(List(
+ new MakePaymentInstance()(timer),
+ new ReserveItemsInstance()(timer),
+ new ShipItemsInstance()(timer)
+ ))
+
+ ecosystem.load(instances: _*)
+}
diff --git a/examples/baas-minikube-setup/baas-minikube-interactions/src/main/scala/webshop/webservice/MakePaymentInstance.scala b/examples/baas-minikube-setup/baas-minikube-interactions/src/main/scala/webshop/webservice/MakePaymentInstance.scala
new file mode 100644
index 000000000..a78c49088
--- /dev/null
+++ b/examples/baas-minikube-setup/baas-minikube-interactions/src/main/scala/webshop/webservice/MakePaymentInstance.scala
@@ -0,0 +1,20 @@
+package webshop.webservice
+
+import cats.effect.{IO, Timer}
+import webshop.webservice.CheckoutFlowEvents.MakePaymentOutput
+import webshop.webservice.CheckoutFlowIngredients.{PaymentInformation, ReservedItems, ShippingAddress, ShippingOrder}
+import webshop.webservice.CheckoutFlowInteractions.MakePayment
+
+import scala.concurrent.Future
+import scala.concurrent.duration._
+
+class MakePaymentInstance(implicit timer: Timer[IO]) extends MakePayment {
+
+ override def apply(processId: String, items: ReservedItems, address: ShippingAddress, payment: PaymentInformation): Future[MakePaymentOutput] = {
+ IO.sleep(5.second)
+ .map(_ => println(Console.GREEN + processId + Console.RESET))
+ .map(_ => CheckoutFlowEvents.PaymentSuccessful(ShippingOrder(items.items, items.data, address)))
+ .unsafeToFuture()
+ }
+}
+
diff --git a/examples/baas-minikube-setup/baas-minikube-interactions/src/main/scala/webshop/webservice/ReserveItemsInstance.scala b/examples/baas-minikube-setup/baas-minikube-interactions/src/main/scala/webshop/webservice/ReserveItemsInstance.scala
new file mode 100644
index 000000000..b6d1634ac
--- /dev/null
+++ b/examples/baas-minikube-setup/baas-minikube-interactions/src/main/scala/webshop/webservice/ReserveItemsInstance.scala
@@ -0,0 +1,19 @@
+package webshop.webservice
+
+import cats.effect.{IO, Timer}
+import cats.implicits._
+import webshop.webservice.CheckoutFlowEvents.ReserveItemsOutput
+import webshop.webservice.CheckoutFlowIngredients.{Item, OrderId, ReservedItems}
+import webshop.webservice.CheckoutFlowInteractions.ReserveItems
+
+import scala.concurrent.Future
+import scala.concurrent.duration._
+
+class ReserveItemsInstance(implicit timer: Timer[IO]) extends ReserveItems {
+
+ override def apply(orderId: OrderId, items: List[Item]): Future[ReserveItemsOutput] = {
+ IO.sleep(1.second)
+ .as(CheckoutFlowEvents.ItemsReserved(ReservedItems(items, Array.fill(1000)(Byte.MaxValue))))
+ .unsafeToFuture()
+ }
+}
diff --git a/examples/baas-minikube-setup/baas-minikube-interactions/src/main/scala/webshop/webservice/ShipItemsInstance.scala b/examples/baas-minikube-setup/baas-minikube-interactions/src/main/scala/webshop/webservice/ShipItemsInstance.scala
new file mode 100644
index 000000000..c9424a151
--- /dev/null
+++ b/examples/baas-minikube-setup/baas-minikube-interactions/src/main/scala/webshop/webservice/ShipItemsInstance.scala
@@ -0,0 +1,20 @@
+package webshop.webservice
+
+import cats.effect.{IO, Timer}
+import cats.implicits._
+import webshop.webservice.CheckoutFlowEvents.ShippingConfirmed
+import webshop.webservice.CheckoutFlowIngredients.ShippingOrder
+import webshop.webservice.CheckoutFlowInteractions.ShipItems
+
+import scala.concurrent.Future
+import scala.concurrent.duration._
+
+class ShipItemsInstance(implicit timer: Timer[IO]) extends ShipItems {
+
+ override def apply(order: ShippingOrder): Future[ShippingConfirmed] = {
+ IO.sleep(500.millis)
+ .as(ShippingConfirmed())
+ .unsafeToFuture()
+ }
+}
+
diff --git a/examples/baas-minikube-setup/baas-minikube-state/src/main/resources/kubernetes.conf b/examples/baas-minikube-setup/baas-minikube-state/src/main/resources/kubernetes.conf
new file mode 100644
index 000000000..acf0cdcc1
--- /dev/null
+++ b/examples/baas-minikube-setup/baas-minikube-state/src/main/resources/kubernetes.conf
@@ -0,0 +1,82 @@
+include "baker.conf"
+
+service {
+
+ actorSystemName = "BaaS"
+ actorSystemName = ${?ACTOR_SYSTEM_NAME}
+
+ httpServerPort = 8080
+ httpServerPort = ${?HTTP_SERVER_PORT}
+}
+
+
+baker {
+
+ interaction-manager = "remote"
+
+ actor {
+ provider = "cluster-sharded"
+ idle-timeout = 1 minute
+ }
+}
+
+#cassandra-journal.contact-points.0 = "127.0.0.1"
+#cassandra-journal.contact-points.0 = ${?CASSANDRA_CONTACT_POINTS_0}
+
+#cassandra-snapshot-store.contact-points.0 = "127.0.0.1"
+#cassandra-snapshot-store.contact-points.0 = ${?CASSANDRA_CONTACT_POINTS_0}
+
+#akka.actor.allow-java-serialization = on
+
+akka {
+
+ actor {
+ provider = "cluster"
+ }
+
+ cluster {
+
+ roles = ["state-node"]
+
+ configuration-compatibility-check.enforce-on-join = off
+ }
+
+ #persistence {
+ # See https://doc.akka.io/docs/akka-persistence-cassandra/current/journal.html#configuration
+ #journal.plugin = "cassandra-journal"
+ # See https://doc.akka.io/docs/akka-persistence-cassandra/current/snapshots.html#configuration
+ #snapshot-store.plugin = "cassandra-snapshot-store"
+ #}
+
+ discovery {
+ kubernetes-api {
+ pod-label-selector = "actorSystemName=%s"
+ }
+ }
+
+ management {
+
+ http.routes {
+ cluster-management = ""
+ }
+
+ cluster.bootstrap {
+ contact-point-discovery {
+ # For the kubernetes API this value is substituted into the %s in pod-label-selector
+ service-name = "BaaS"
+
+ # pick the discovery method you'd like to use:
+ discovery-method = kubernetes-api
+ }
+ }
+
+ health-checks {
+ readiness-path = "health/ready"
+ liveness-path = "health/alive"
+
+ liveness-checks {
+ cluster-health = "webshop.webservice.ClusterHealthCheck"
+ }
+ }
+ }
+}
diff --git a/examples/baas-minikube-setup/baas-minikube-state/src/main/scala/webshop/webservice/ClusterHealthCheck.scala b/examples/baas-minikube-setup/baas-minikube-state/src/main/scala/webshop/webservice/ClusterHealthCheck.scala
new file mode 100644
index 000000000..a6ae41f89
--- /dev/null
+++ b/examples/baas-minikube-setup/baas-minikube-state/src/main/scala/webshop/webservice/ClusterHealthCheck.scala
@@ -0,0 +1,13 @@
+package webshop.webservice
+
+import akka.actor.ActorSystem
+import akka.cluster.{Cluster, MemberStatus}
+
+import scala.concurrent.Future
+
+class ClusterHealthCheck(system: ActorSystem) extends (() => Future[Boolean]) {
+ private val cluster = Cluster(system)
+ override def apply(): Future[Boolean] = {
+ Future.successful(cluster.selfMember.status == MemberStatus.Up)
+ }
+}
diff --git a/examples/baas-minikube-setup/build-and-publish-images.sh b/examples/baas-minikube-setup/build-and-publish-images.sh
new file mode 100755
index 000000000..66ea56a82
--- /dev/null
+++ b/examples/baas-minikube-setup/build-and-publish-images.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+echo "Run this command from the baker root"
+
+sbt baas-minikube-state/docker:publish
+sbt baas-minikube-interactions/docker:publish
+sbt baas-minikube-event-listener/docker:publish
+sbt baas-client-example/docker:publish
diff --git a/examples/baas-minikube-setup/build-and-publish-local-images.sh b/examples/baas-minikube-setup/build-and-publish-local-images.sh
new file mode 100755
index 000000000..03f78fe79
--- /dev/null
+++ b/examples/baas-minikube-setup/build-and-publish-local-images.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+echo "Run this command from the baker root"
+
+sbt baas-minikube-state/docker:publishLocal
+sbt baas-minikube-interactions/docker:publishLocal
+sbt baas-minikube-event-listener/docker:publishLocal
+sbt baas-client-example/docker:publishLocal
diff --git a/examples/baas-minikube-setup/create-minikube-namespace.sh b/examples/baas-minikube-setup/create-minikube-namespace.sh
new file mode 100755
index 000000000..57403d082
--- /dev/null
+++ b/examples/baas-minikube-setup/create-minikube-namespace.sh
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+
+###########################################################################
+#Script Name : create-minikube-example.sh
+#Description : Creates and runs new minikube instance using preproxy
+#Args : Not supported
+#Bash Version : GNU bash, version 3.x.XX
+###########################################################################
+
+set -o errexit
+set -eo pipefail
+set -o nounset
+#set -o xtrace
+
+RED='\033[0;31m'
+NC='\033[0m' # No Color
+
+echo -e "Creating minikube cluster locally ${RED}(takes up to 10 minutes)${NC}"
+minikube delete || echo "Ignoring delete for non existed minikube cluster"
+
+minikube --vm-driver virtualbox --memory 8192 --cpus 4 start
+
+kubectl api-resources
\ No newline at end of file
diff --git a/examples/src/main/java/webshop/simple/JMain.java b/examples/baker-example/src/main/java/webshop/simple/JMain.java
similarity index 93%
rename from examples/src/main/java/webshop/simple/JMain.java
rename to examples/baker-example/src/main/java/webshop/simple/JMain.java
index 58ca3859a..8c8f1143f 100644
--- a/examples/src/main/java/webshop/simple/JMain.java
+++ b/examples/baker-example/src/main/java/webshop/simple/JMain.java
@@ -3,7 +3,9 @@
import akka.actor.ActorSystem;
import com.ing.baker.compiler.RecipeCompiler;
import com.ing.baker.il.CompiledRecipe;
+import com.ing.baker.runtime.akka.AkkaBaker;
import com.ing.baker.runtime.javadsl.*;
+import com.typesafe.config.ConfigFactory;
import java.util.ArrayList;
import java.util.List;
@@ -16,7 +18,7 @@ public class JMain {
static public void main_ignore(String[] args) {
ActorSystem actorSystem = ActorSystem.create("WebshopSystem");
- Baker baker = Baker.akkaLocalDefault(actorSystem);
+ Baker baker = AkkaBaker.java(ConfigFactory.load(), actorSystem);
List items = new ArrayList<>(2);
items.add("item1");
diff --git a/examples/src/main/java/webshop/simple/JWebshopRecipe.java b/examples/baker-example/src/main/java/webshop/simple/JWebshopRecipe.java
similarity index 100%
rename from examples/src/main/java/webshop/simple/JWebshopRecipe.java
rename to examples/baker-example/src/main/java/webshop/simple/JWebshopRecipe.java
diff --git a/examples/src/main/java/webshop/simple/ReserveItemsInstance.java b/examples/baker-example/src/main/java/webshop/simple/ReserveItemsInstance.java
similarity index 100%
rename from examples/src/main/java/webshop/simple/ReserveItemsInstance.java
rename to examples/baker-example/src/main/java/webshop/simple/ReserveItemsInstance.java
diff --git a/examples/src/main/resources/application.conf b/examples/baker-example/src/main/resources/application.conf
similarity index 96%
rename from examples/src/main/resources/application.conf
rename to examples/baker-example/src/main/resources/application.conf
index 873a3c06b..60aab476d 100644
--- a/examples/src/main/resources/application.conf
+++ b/examples/baker-example/src/main/resources/application.conf
@@ -25,6 +25,9 @@ service {
}
baker {
+
+ interaction-manager = "remote"
+
actor {
provider = "cluster-sharded"
idle-timeout = 1 minute
@@ -43,6 +46,8 @@ cassandra-journal.contact-points.0 = ${?CASSANDRA_CONTACT_POINTS_0}
cassandra-snapshot-store.contact-points.0 = "127.0.0.1"
cassandra-snapshot-store.contact-points.0 = ${?CASSANDRA_CONTACT_POINTS_0}
+akka.actor.allow-java-serialization = on
+
akka {
actor {
diff --git a/examples/src/main/resources/docker-compose.yaml b/examples/baker-example/src/main/resources/docker-compose.yaml
similarity index 83%
rename from examples/src/main/resources/docker-compose.yaml
rename to examples/baker-example/src/main/resources/docker-compose.yaml
index 674ae8b65..e42c4dc89 100644
--- a/examples/src/main/resources/docker-compose.yaml
+++ b/examples/baker-example/src/main/resources/docker-compose.yaml
@@ -1,7 +1,7 @@
version: '3'
services:
node1:
- image: "checkout-service-baker-example:3.0.0-SNAPSHOT"
+ image: "checkout-service-baker-example:3.0.1-SNAPSHOT"
ports:
- "8081:8080"
- "5261:5266"
@@ -14,26 +14,26 @@ services:
CLUSTER_SEED_HOST: node1
CLUSTER_SEED_PORT: 2551
node2:
- image: "checkout-service-baker-example:3.0.0-SNAPSHOT"
+ image: "checkout-service-baker-example:3.0.1-SNAPSHOT"
ports:
- "8082:8080"
- "5262:5266"
- "9092:9095"
- logging:
- driver: none
+ #logging:
+ # driver: none
environment:
CLUSTER_HOST: node2
CLUSTER_PORT: 2551
CLUSTER_SEED_HOST: node1
CLUSTER_SEED_PORT: 2551
node3:
- image: "checkout-service-baker-example:3.0.0-SNAPSHOT"
+ image: "checkout-service-baker-example:3.0.1-SNAPSHOT"
ports:
- "8083:8080"
- "5263:526"
- "9093:9095"
- logging:
- driver: none
+ #logging:
+ # driver: none
environment:
CLUSTER_HOST: node3
CLUSTER_PORT: 2551
diff --git a/examples/src/main/resources/gatling/webshop/webservice/CheckoutFlowSimulation.scala b/examples/baker-example/src/main/resources/gatling/webshop/webservice/CheckoutFlowSimulation.scala
similarity index 100%
rename from examples/src/main/resources/gatling/webshop/webservice/CheckoutFlowSimulation.scala
rename to examples/baker-example/src/main/resources/gatling/webshop/webservice/CheckoutFlowSimulation.scala
diff --git a/examples/src/main/resources/grafana/Dockerfile b/examples/baker-example/src/main/resources/grafana/Dockerfile
similarity index 100%
rename from examples/src/main/resources/grafana/Dockerfile
rename to examples/baker-example/src/main/resources/grafana/Dockerfile
diff --git a/examples/src/main/resources/grafana/config.ini b/examples/baker-example/src/main/resources/grafana/config.ini
similarity index 100%
rename from examples/src/main/resources/grafana/config.ini
rename to examples/baker-example/src/main/resources/grafana/config.ini
diff --git a/examples/src/main/resources/grafana/dashboards/akka_metrics.json b/examples/baker-example/src/main/resources/grafana/dashboards/akka_metrics.json
similarity index 100%
rename from examples/src/main/resources/grafana/dashboards/akka_metrics.json
rename to examples/baker-example/src/main/resources/grafana/dashboards/akka_metrics.json
diff --git a/examples/src/main/resources/grafana/provisioning/dashboards/all.yaml b/examples/baker-example/src/main/resources/grafana/provisioning/dashboards/all.yaml
similarity index 100%
rename from examples/src/main/resources/grafana/provisioning/dashboards/all.yaml
rename to examples/baker-example/src/main/resources/grafana/provisioning/dashboards/all.yaml
diff --git a/examples/src/main/resources/grafana/provisioning/datasources/all.yaml b/examples/baker-example/src/main/resources/grafana/provisioning/datasources/all.yaml
similarity index 100%
rename from examples/src/main/resources/grafana/provisioning/datasources/all.yaml
rename to examples/baker-example/src/main/resources/grafana/provisioning/datasources/all.yaml
diff --git a/examples/src/main/resources/haproxy/Dockerfile b/examples/baker-example/src/main/resources/haproxy/Dockerfile
similarity index 100%
rename from examples/src/main/resources/haproxy/Dockerfile
rename to examples/baker-example/src/main/resources/haproxy/Dockerfile
diff --git a/examples/src/main/resources/haproxy/haproxy.cfg b/examples/baker-example/src/main/resources/haproxy/haproxy.cfg
similarity index 85%
rename from examples/src/main/resources/haproxy/haproxy.cfg
rename to examples/baker-example/src/main/resources/haproxy/haproxy.cfg
index cbe29a7df..70a1b0d7b 100644
--- a/examples/src/main/resources/haproxy/haproxy.cfg
+++ b/examples/baker-example/src/main/resources/haproxy/haproxy.cfg
@@ -36,7 +36,7 @@ backend nodes
option forwardfor
http-request set-header X-Forwarded-Port %[dst_port]
http-request add-header X-Forwarded-Proto https if { ssl_fc }
- option httpchk HEAD / HTTP/1.1
- server web01 host.docker.internal:8081 check
- server web02 host.docker.internal:8082 check
- server web03 host.docker.internal:8083 check
+ option httpchk GET / HTTP/1.1\r\nHost:localhost
+ server web01 state-node-1:8080 check
+ server web02 state-node-2:8080 check
+ server web03 state-node-3:8080 check
diff --git a/examples/baker-example/src/main/resources/logback.xml b/examples/baker-example/src/main/resources/logback.xml
new file mode 100644
index 000000000..cee31bf6b
--- /dev/null
+++ b/examples/baker-example/src/main/resources/logback.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/src/main/resources/prometheus/Dockerfile b/examples/baker-example/src/main/resources/prometheus/Dockerfile
similarity index 100%
rename from examples/src/main/resources/prometheus/Dockerfile
rename to examples/baker-example/src/main/resources/prometheus/Dockerfile
diff --git a/examples/src/main/resources/prometheus/prometheus.yaml b/examples/baker-example/src/main/resources/prometheus/prometheus.yaml
similarity index 100%
rename from examples/src/main/resources/prometheus/prometheus.yaml
rename to examples/baker-example/src/main/resources/prometheus/prometheus.yaml
diff --git a/examples/src/main/scala/webshop/simple/SimpleWebshopInstances.scala b/examples/baker-example/src/main/scala/webshop/simple/SimpleWebshopInstances.scala
similarity index 100%
rename from examples/src/main/scala/webshop/simple/SimpleWebshopInstances.scala
rename to examples/baker-example/src/main/scala/webshop/simple/SimpleWebshopInstances.scala
diff --git a/examples/src/main/scala/webshop/simple/SimpleWebshopInstancesReflection.scala b/examples/baker-example/src/main/scala/webshop/simple/SimpleWebshopInstancesReflection.scala
similarity index 100%
rename from examples/src/main/scala/webshop/simple/SimpleWebshopInstancesReflection.scala
rename to examples/baker-example/src/main/scala/webshop/simple/SimpleWebshopInstancesReflection.scala
diff --git a/examples/src/main/scala/webshop/simple/SimpleWebshopRecipe.scala b/examples/baker-example/src/main/scala/webshop/simple/SimpleWebshopRecipe.scala
similarity index 100%
rename from examples/src/main/scala/webshop/simple/SimpleWebshopRecipe.scala
rename to examples/baker-example/src/main/scala/webshop/simple/SimpleWebshopRecipe.scala
diff --git a/examples/src/main/scala/webshop/simple/SimpleWebshopRecipeReflection.scala b/examples/baker-example/src/main/scala/webshop/simple/SimpleWebshopRecipeReflection.scala
similarity index 100%
rename from examples/src/main/scala/webshop/simple/SimpleWebshopRecipeReflection.scala
rename to examples/baker-example/src/main/scala/webshop/simple/SimpleWebshopRecipeReflection.scala
diff --git a/examples/src/main/scala/webshop/webservice/CheckoutFlowRecipe.scala b/examples/baker-example/src/main/scala/webshop/webservice/CheckoutFlowRecipe.scala
similarity index 100%
rename from examples/src/main/scala/webshop/webservice/CheckoutFlowRecipe.scala
rename to examples/baker-example/src/main/scala/webshop/webservice/CheckoutFlowRecipe.scala
diff --git a/examples/src/main/scala/webshop/webservice/Main.scala b/examples/baker-example/src/main/scala/webshop/webservice/Main.scala
similarity index 95%
rename from examples/src/main/scala/webshop/webservice/Main.scala
rename to examples/baker-example/src/main/scala/webshop/webservice/Main.scala
index 0b4455ce1..be79ed900 100644
--- a/examples/src/main/scala/webshop/webservice/Main.scala
+++ b/examples/baker-example/src/main/scala/webshop/webservice/Main.scala
@@ -5,6 +5,7 @@ import akka.cluster.Cluster
import cats.effect.concurrent.Ref
import cats.effect.{ExitCode, IO, IOApp, Resource}
import cats.implicits._
+import com.ing.baker.runtime.akka.AkkaBaker
import com.ing.baker.runtime.scaladsl._
import com.typesafe.config.ConfigFactory
import kamon.Kamon
@@ -24,7 +25,7 @@ object Main extends IOApp {
for {
actorSystem <- IO { ActorSystem("CheckoutService") }
config <- IO { ConfigFactory.load() }
- baker <- IO { Baker.akka(config, actorSystem) }
+ baker <- IO { AkkaBaker(config, actorSystem) }
checkoutRecipeId <- WebShopBaker.initRecipes(baker)(timer, actorSystem.dispatcher)
sd <- Ref.of[IO, Boolean](false)
webShopBaker = new WebShopBaker(baker, checkoutRecipeId)(actorSystem.dispatcher)
diff --git a/examples/src/main/scala/webshop/webservice/MakePaymentInstance.scala b/examples/baker-example/src/main/scala/webshop/webservice/MakePaymentInstance.scala
similarity index 96%
rename from examples/src/main/scala/webshop/webservice/MakePaymentInstance.scala
rename to examples/baker-example/src/main/scala/webshop/webservice/MakePaymentInstance.scala
index 81ca19cb8..9206f9280 100644
--- a/examples/src/main/scala/webshop/webservice/MakePaymentInstance.scala
+++ b/examples/baker-example/src/main/scala/webshop/webservice/MakePaymentInstance.scala
@@ -11,7 +11,7 @@ import scala.concurrent.duration._
class MakePaymentInstance(implicit timer: Timer[IO]) extends MakePayment {
override def apply(processId: String, items: ReservedItems, address: ShippingAddress, payment: PaymentInformation): Future[MakePaymentOutput] = {
- IO.sleep(5 second)
+ IO.sleep(5.second)
.map(_ => println(Console.GREEN + processId + Console.RESET))
.map(_ => CheckoutFlowEvents.PaymentSuccessful(ShippingOrder(items.items, items.data, address)))
.unsafeToFuture()
diff --git a/examples/baker-example/src/main/scala/webshop/webservice/OrderStatus.scala b/examples/baker-example/src/main/scala/webshop/webservice/OrderStatus.scala
new file mode 100644
index 000000000..6a89e4bef
--- /dev/null
+++ b/examples/baker-example/src/main/scala/webshop/webservice/OrderStatus.scala
@@ -0,0 +1,30 @@
+package webshop.webservice
+
+import webshop.webservice.OrderStatus._
+
+trait OrderStatus {
+
+ override def toString: String = this match {
+ case InfoPending(pending) => "info-pending:" + pending.mkString(",")
+ case UnavailableItems(items) => "unavailable-items:" + items.length
+ case PaymentFailed => "payment-failed"
+ case ShippingItems => "shipping-items"
+ case ProcessingPayment => "processing-payment"
+ case Complete => "complete"
+ }
+}
+
+object OrderStatus {
+
+ case class InfoPending(pending: List[String]) extends OrderStatus
+
+ case class UnavailableItems(items: List[String]) extends OrderStatus
+
+ case object PaymentFailed extends OrderStatus
+
+ case object ShippingItems extends OrderStatus
+
+ case object ProcessingPayment extends OrderStatus
+
+ case object Complete extends OrderStatus
+}
diff --git a/examples/baker-example/src/main/scala/webshop/webservice/ReserveItemsInstance.scala b/examples/baker-example/src/main/scala/webshop/webservice/ReserveItemsInstance.scala
new file mode 100644
index 000000000..84001a0b4
--- /dev/null
+++ b/examples/baker-example/src/main/scala/webshop/webservice/ReserveItemsInstance.scala
@@ -0,0 +1,19 @@
+package webshop.webservice
+
+import cats.implicits._
+import cats.effect.{IO, Timer}
+import webshop.webservice.CheckoutFlowEvents.ReserveItemsOutput
+import webshop.webservice.CheckoutFlowIngredients.{Item, OrderId, ReservedItems}
+import webshop.webservice.CheckoutFlowInteractions.ReserveItems
+
+import scala.concurrent.Future
+import scala.concurrent.duration._
+
+class ReserveItemsInstance(implicit timer: Timer[IO]) extends ReserveItems {
+
+ override def apply(orderId: OrderId, items: List[Item]): Future[ReserveItemsOutput] = {
+ IO.sleep(1.second)
+ .as(CheckoutFlowEvents.ItemsReserved(ReservedItems(items, Array.fill(1000)(Byte.MaxValue))))
+ .unsafeToFuture()
+ }
+}
diff --git a/examples/baker-example/src/main/scala/webshop/webservice/ShipItemsInstance.scala b/examples/baker-example/src/main/scala/webshop/webservice/ShipItemsInstance.scala
new file mode 100644
index 000000000..d4951eaed
--- /dev/null
+++ b/examples/baker-example/src/main/scala/webshop/webservice/ShipItemsInstance.scala
@@ -0,0 +1,20 @@
+package webshop.webservice
+
+import cats.implicits._
+import cats.effect.{IO, Timer}
+import webshop.webservice.CheckoutFlowEvents.ShippingConfirmed
+import webshop.webservice.CheckoutFlowIngredients.ShippingOrder
+import webshop.webservice.CheckoutFlowInteractions.ShipItems
+
+import scala.concurrent.Future
+import scala.concurrent.duration._
+
+class ShipItemsInstance(implicit timer: Timer[IO]) extends ShipItems {
+
+ override def apply(order: ShippingOrder): Future[ShippingConfirmed] = {
+ IO.sleep(500.millis)
+ .as(ShippingConfirmed())
+ .unsafeToFuture()
+ }
+}
+
diff --git a/examples/baker-example/src/main/scala/webshop/webservice/WebShop.scala b/examples/baker-example/src/main/scala/webshop/webservice/WebShop.scala
new file mode 100644
index 000000000..aa2d4b459
--- /dev/null
+++ b/examples/baker-example/src/main/scala/webshop/webservice/WebShop.scala
@@ -0,0 +1,17 @@
+package webshop.webservice
+
+import cats.effect.IO
+
+trait WebShop {
+
+ def createCheckoutOrder(items: List[String]): IO[String]
+
+ def addCheckoutAddressInfo(orderId: String, address: String): IO[Option[String]]
+
+ def addCheckoutPaymentInfo(orderId: String, paymentInfo: String): IO[Option[String]]
+
+ def pollOrderStatus(orderId: String): IO[OrderStatus]
+
+ def gracefulShutdown: IO[Unit]
+}
+
diff --git a/examples/src/main/scala/webshop/webservice/WebShopBaker.scala b/examples/baker-example/src/main/scala/webshop/webservice/WebShopBaker.scala
similarity index 100%
rename from examples/src/main/scala/webshop/webservice/WebShopBaker.scala
rename to examples/baker-example/src/main/scala/webshop/webservice/WebShopBaker.scala
diff --git a/examples/src/main/scala/webshop/webservice/WebShopService.scala b/examples/baker-example/src/main/scala/webshop/webservice/WebShopService.scala
similarity index 100%
rename from examples/src/main/scala/webshop/webservice/WebShopService.scala
rename to examples/baker-example/src/main/scala/webshop/webservice/WebShopService.scala
diff --git a/examples/src/test/java/webshop/JWebshopRecipeTests.java b/examples/baker-example/src/test/java/webshop/JWebshopRecipeTests.java
similarity index 100%
rename from examples/src/test/java/webshop/JWebshopRecipeTests.java
rename to examples/baker-example/src/test/java/webshop/JWebshopRecipeTests.java
diff --git a/examples/src/test/scala/webshop/simple/WebshopRecipeSpec.scala b/examples/baker-example/src/test/scala/webshop/simple/WebshopRecipeSpec.scala
similarity index 100%
rename from examples/src/test/scala/webshop/simple/WebshopRecipeSpec.scala
rename to examples/baker-example/src/test/scala/webshop/simple/WebshopRecipeSpec.scala
diff --git a/integration/src/multi-jvm/scala/com/ing/baker/HappyPathSpec.scala b/integration/src/multi-jvm/scala/com/ing/baker/HappyPathSpec.scala
index 5e0ab024a..e2e7a74a6 100644
--- a/integration/src/multi-jvm/scala/com/ing/baker/HappyPathSpec.scala
+++ b/integration/src/multi-jvm/scala/com/ing/baker/HappyPathSpec.scala
@@ -123,7 +123,7 @@ object HappyPath extends MockitoSugar {
def seedNodeConfig(path: ActorPath): Config =
ConfigFactory.parseString(s"""baker.cluster.seed-nodes = ["$path"]""")
- def implementations(implicit ec: ExecutionContext): Seq[InteractionInstance] = Seq(
+ def implementations: Seq[InteractionInstance] = Seq(
ValidateOrder,
ManufactureGoods,
SendInvoice,
diff --git a/playground/src/main/resources/haproxy-state-nodes/Dockerfile b/playground/src/main/resources/haproxy-state-nodes/Dockerfile
new file mode 100644
index 000000000..ebf71cf99
--- /dev/null
+++ b/playground/src/main/resources/haproxy-state-nodes/Dockerfile
@@ -0,0 +1,14 @@
+FROM haproxy:1.7
+
+ENV HAPROXY_USER haproxy
+
+RUN groupadd --system ${HAPROXY_USER} && \
+ useradd --system --gid ${HAPROXY_USER} ${HAPROXY_USER} && \
+ mkdir --parents /var/lib/${HAPROXY_USER} && \
+ chown -R ${HAPROXY_USER}:${HAPROXY_USER} /var/lib/${HAPROXY_USER}
+
+RUN mkdir /run/haproxy/
+
+COPY haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg
+
+CMD ["haproxy", "-db", "-f", "/usr/local/etc/haproxy/haproxy.cfg"]
\ No newline at end of file
diff --git a/playground/src/main/resources/haproxy-state-nodes/haproxy.cfg b/playground/src/main/resources/haproxy-state-nodes/haproxy.cfg
new file mode 100644
index 000000000..42e31d398
--- /dev/null
+++ b/playground/src/main/resources/haproxy-state-nodes/haproxy.cfg
@@ -0,0 +1,42 @@
+global
+ log /dev/log local0
+ log /dev/log local1 notice
+ chroot /var/lib/haproxy
+ stats socket /run/haproxy/admin.sock mode 660 level admin
+ stats timeout 30s
+ user haproxy
+ group haproxy
+ daemon
+
+ # Default SSL material locations
+ ca-base /etc/ssl/certs
+ crt-base /etc/ssl/private
+
+ # Default ciphers to use on SSL-enabled listening sockets.
+ # For more information, see ciphers(1SSL).
+ ssl-default-bind-ciphers kEECDH+aRSA+AES:kRSA+AES:+AES256:RC4-SHA:!kEDH:!LOW:!EXP:!MD5:!aNULL:!eNULL
+
+defaults
+ log global
+ mode http
+ option httplog
+ option dontlognull
+ timeout connect 5000
+ timeout client 50000
+ timeout server 50000
+
+frontend localnodes
+ bind *:8080
+ mode http
+ default_backend nodes
+
+backend nodes
+ mode http
+ balance roundrobin
+ option forwardfor
+ http-request set-header X-Forwarded-Port %[dst_port]
+ http-request add-header X-Forwarded-Proto https if { ssl_fc }
+ option httpchk GET / HTTP/1.1\r\nHost:localhost
+ server web01 state-node-1:8080 check
+ #server web02 state-node-2:8080 check
+ #server web03 state-node-3:8080 check
diff --git a/playground/src/main/scala/com/ing/baker/playground/AppUtils.scala b/playground/src/main/scala/com/ing/baker/playground/AppUtils.scala
new file mode 100644
index 000000000..0335fdf7f
--- /dev/null
+++ b/playground/src/main/scala/com/ing/baker/playground/AppUtils.scala
@@ -0,0 +1,104 @@
+package com.ing.baker.playground
+
+import cats.Show
+import cats.data.StateT
+import cats.effect.IO
+import cats.implicits._
+import cats.effect.Console.{io => console}
+
+import scala.util.Random
+
+object AppUtils {
+
+ case class Environment(runningImages: List[String], bakerLocation: Option[String])
+
+ object Environment {
+
+ def empty: Environment = Environment(List.empty, None)
+ }
+
+ type App[A] = StateT[IO, Environment, A]
+
+ implicit class AppIO[A](io: IO[A]) {
+
+ def app: App[A] = StateT.liftF(io)
+ }
+
+ implicit class AppOps[A](app: App[A]) {
+
+ def tryForget: App[Unit] =
+ AppUtils.tryForget(app)
+ }
+
+ def pure[A](a: A): App[A] = StateT.pure(a)
+
+ def fail[A](e: Throwable): App[A] = IO.raiseError(e).app
+
+ def fail[A](e: String): App[A] = IO.raiseError(new Exception(e)).app
+
+ def tryForget[A](program: App[A]): App[Unit] =
+ StateT { state => program.run(state).attempt.map(_ => (state, ())) }
+
+ def modify(f: Environment => Environment): App[Unit] =
+ StateT.modify[IO, Environment](f)
+
+ def getState: App[Environment] =
+ StateT.get[IO, Environment]
+
+ def addRunningImage(imageName: String): App[Unit] =
+ modify(state => state.copy(runningImages = imageName :: state.runningImages))
+
+ def addBakerLocation(location: String): App[Unit] =
+ modify(state => state.copy(bakerLocation = Some(location)))
+
+ def doNothing: App[Unit] =
+ StateT.pure[IO, Environment, Unit](())
+
+ def print(message: String): App[Unit] =
+ console.putStr(message).app
+
+ def printLn(message: String): App[Unit] =
+ console.putStrLn(message).app
+
+ def printLnA[A: Show](a: A): App[Unit] =
+ print(a.show)
+
+ def readLn: App[String] =
+ console.readLn.app
+
+ private val colors: Array[String] = Array(
+ Console.MAGENTA,
+ Console.RED,
+ Console.YELLOW,
+ Console.GREEN,
+ Console.CYAN,
+ Console.BLUE
+ )
+
+ implicit class PrettyColorPrint[A](a: A) {
+
+ def print: IO[Unit] =
+ IO { println(a.toString) }
+
+ def magenta: String =
+ Console.MAGENTA + a.toString + Console.RESET
+
+ def green: String =
+ Console.GREEN + a.toString + Console.RESET
+
+ def red: String =
+ Console.RED + a.toString + Console.RESET
+
+ def yellow: String =
+ Console.YELLOW + a.toString + Console.RESET
+
+ def randomColor: String =
+ colors(Random.nextInt(colors.length)) + a.toString + Console.RESET
+
+ def prompt(prepend: String): String =
+ a.toString.lines.map(prepend + _).mkString("\n")
+
+ def notice: String =
+ " [>>>] " + a.toString + " [<<<] "
+ }
+}
diff --git a/playground/src/main/scala/com/ing/baker/playground/Command.scala b/playground/src/main/scala/com/ing/baker/playground/Command.scala
new file mode 100644
index 000000000..93da53268
--- /dev/null
+++ b/playground/src/main/scala/com/ing/baker/playground/Command.scala
@@ -0,0 +1,61 @@
+package com.ing.baker.playground
+
+import cats.implicits._
+import com.ing.baker.playground.AppUtils._
+import com.ing.baker.playground.Command.RunCommand
+import com.ing.baker.playground.commands.{BaaS, Terminal}
+
+trait Command {
+ def name: String
+ def help: String = "No help for this command"
+ def run: RunCommand
+}
+
+object Command {
+
+ type RunCommand = PartialFunction[String, App[Unit]]
+
+ val commands: List[Command] =
+ List(
+ Help,
+ StartBaaS,
+ BuildImage
+ )
+
+ case object Help extends Command {
+
+ override def name: String = "help"
+
+ override def help: String = "Displays this help menu"
+
+ override def run: RunCommand = {
+ case "help" =>
+ printLn("") *>
+ commands.traverse { command =>
+ val spaces = List.fill(20 - command.name.length)(".").mkString
+ printLn(command.name + " " + spaces + " " + command.help)
+ } *>
+ printLn("")
+ }
+ }
+
+ case object StartBaaS extends Command {
+
+ override def name: String = "start-baas"
+
+ override def help: String = "Starts Cassandra, Haproxy and a cluster of 3 baas state nodes"
+
+ override def run: RunCommand = { case "start-baas" => BaaS.startBaaS }
+ }
+
+ case object BuildImage extends Command {
+
+ override def name: String = "build"
+
+ override def help: String = "Builds all playground required images from the baker repository"
+
+ override def run: RunCommand = {
+ case "build" => BaaS.buildStateNodesHAProxyImage
+ }
+ }
+}
diff --git a/playground/src/main/scala/com/ing/baker/playground/Main.scala b/playground/src/main/scala/com/ing/baker/playground/Main.scala
new file mode 100644
index 000000000..1244091a2
--- /dev/null
+++ b/playground/src/main/scala/com/ing/baker/playground/Main.scala
@@ -0,0 +1,16 @@
+package com.ing.baker.playground
+
+import cats.effect.{ExitCode, IO, IOApp}
+import com.typesafe.scalalogging.LazyLogging
+
+object Main extends IOApp with LazyLogging {
+
+ override def run(args: List[String]): IO[ExitCode] = {
+ PlaygroundApp.loop
+ .run(AppUtils.Environment.empty)
+ .map { case (finalState, _) =>
+ logger.info(s"Finishing with final state $finalState")
+ ExitCode.Success
+ }
+ }
+}
diff --git a/playground/src/main/scala/com/ing/baker/playground/PlaygroundApp.scala b/playground/src/main/scala/com/ing/baker/playground/PlaygroundApp.scala
new file mode 100644
index 000000000..9f372f52e
--- /dev/null
+++ b/playground/src/main/scala/com/ing/baker/playground/PlaygroundApp.scala
@@ -0,0 +1,40 @@
+package com.ing.baker.playground
+
+import cats.implicits._
+import com.ing.baker.playground.AppUtils._
+import com.ing.baker.playground.Command.RunCommand
+import com.ing.baker.playground.commands.Docker
+
+object PlaygroundApp {
+
+ def loop: App[Unit] =
+ for {
+ _ <- print("playground> ")
+ line <- readLn
+ _ <- exec(line)
+ _ <- if (line == "exit") doNothing else loop
+ } yield ()
+
+ def exec(raw: String): App[Unit] =
+ tryOneCommand
+ .applyOrElse(raw, (other: String) => printLn(s"Unknown command '$other'"))
+ .attempt
+ .flatMap {
+ case Left(e) => printLn(e.getMessage)
+ case Right(_) => doNothing
+ }
+
+ def tryOneCommand: RunCommand =
+ Command.commands.foldRight[RunCommand]({
+ case "exit" =>
+ cleanup *> printLn("Bye bye! I hope you had fun :D")
+ case "clean" =>
+ cleanup *> printLn("Clean")
+ case "" =>
+ doNothing
+ })(_.run.orElse(_))
+
+ def cleanup: App[Unit] =
+ Docker.terminateAllImages *>
+ Docker.deleteDockerNetwork
+}
diff --git a/playground/src/main/scala/com/ing/baker/playground/commands/BaaS.scala b/playground/src/main/scala/com/ing/baker/playground/commands/BaaS.scala
new file mode 100644
index 000000000..6a8d14426
--- /dev/null
+++ b/playground/src/main/scala/com/ing/baker/playground/commands/BaaS.scala
@@ -0,0 +1,109 @@
+package com.ing.baker.playground.commands
+
+import cats.implicits._
+import com.ing.baker.playground.AppUtils._
+import Docker.{createDockerNetwork, networkName}
+
+object BaaS {
+
+ val baasVersion = "3.0.2-SNAPSHOT"
+
+ val haproxyStateNodesImage = "playground-haproxy-state-nodes:latest"
+
+ def startBaaS: App[Unit] =
+ for {
+ _ <- createDockerNetwork
+ _ <- EnvSystems.runCassandra
+ node1 <- runStateNode(baasVersion, 1, "self")
+ _ <- EnvSystems.runHaproxy
+ _ <- runInteractionNode(baasVersion, 1, node1)
+ _ <- runEventListenerNode(baasVersion, 1, node1)
+ _ <- runClientApp(baasVersion, 1, "http://" + EnvSystems.haproxyName + ":8080")
+ } yield ()
+
+ def runStateNode(version: String, node: Int, seedHost: String): App[String] = {
+ val containerName: String = s"state-node-$node"
+ val seedHostname: String = if(seedHost == "self") containerName else seedHost
+ val envVars = Map(
+ "CLUSTER_HOST" -> containerName,
+ "CLUSTER_SEED_HOST" -> seedHostname,
+ "CASSANDRA_CONTACT_POINTS_0" -> "baker-cassandra"
+ )
+ .map { case (env, value) => s"-e $env=$value"}
+ .mkString(" ")
+ val cmd = s"docker run --name $containerName --network $networkName $envVars baas-node-state:$version"
+ for {
+ _ <- Terminal.execAndWait(
+ command = cmd,
+ prompt = s"state-node:$version:$node",
+ condition = _.contains(s"State Node started...")
+ )
+ _ <- printLn(s"Node: $containerName successfully started")
+ _ <- addRunningImage(containerName)
+ } yield containerName
+ }
+
+ def runInteractionNode(version: String, node: Int, seedHost: String): App[String] = {
+ val containerName: String = s"interaction-node-$node"
+ val seedHostname: String = if(seedHost == "self") containerName else seedHost
+ val envVars = Map(
+ "CLUSTER_HOST" -> containerName,
+ "CLUSTER_SEED_HOST" -> seedHostname
+ )
+ .map { case (env, value) => s"-e $env=$value"}
+ .mkString(" ")
+ val cmd = s"docker run --name $containerName --network $networkName $envVars baas-interactions-example:$version"
+ for {
+ _ <- Terminal.execAndWait(
+ command = cmd,
+ prompt = s"interactions-node:$version:$node",
+ condition = _ => true
+ )
+ _ <- addRunningImage(containerName)
+ } yield containerName
+ }
+
+ def runEventListenerNode(version: String, node: Int, seedHost: String): App[String] = {
+ val containerName: String = s"event-listener-node-$node"
+ val seedHostname: String = if(seedHost == "self") containerName else seedHost
+ val envVars = Map(
+ "CLUSTER_HOST" -> containerName,
+ "CLUSTER_SEED_HOST" -> seedHostname
+ )
+ .map { case (env, value) => s"-e $env=$value"}
+ .mkString(" ")
+ val cmd = s"docker run --name $containerName --network $networkName $envVars baas-event-listener-example:$version"
+ for {
+ _ <- Terminal.execAndWait(
+ command = cmd,
+ prompt = s"event-listener-node:$version:$node",
+ condition = _ => true
+ )
+ _ <- addRunningImage(containerName)
+ } yield containerName
+ }
+
+ def runClientApp(version: String, node: Int, baasHostname: String): App[String] = {
+ val containerName: String = s"client-app-$node"
+ val envVars = Map(
+ "BAAS_HOSTNAME" -> baasHostname
+ )
+ .map { case (env, value) => s"-e $env=$value"}
+ .mkString(" ")
+ val cmd = s"docker run --name $containerName --network $networkName $envVars -p 8080:8080 baas-client-example:$version"
+ for {
+ _ <- Terminal.execAndWait(
+ command = cmd,
+ prompt = s"client-app:$version:$node",
+ condition = _ => true
+ )
+ _ <- addRunningImage(containerName)
+ } yield containerName
+ }
+
+ def buildStateNodesHAProxyImage: App[Unit] =
+ Terminal.moveToBakerLocation *> Docker.buildImage(
+ "./playground/src/main/resources/haproxy-state-nodes",
+ haproxyStateNodesImage
+ )
+}
diff --git a/playground/src/main/scala/com/ing/baker/playground/commands/Docker.scala b/playground/src/main/scala/com/ing/baker/playground/commands/Docker.scala
new file mode 100644
index 000000000..6165816db
--- /dev/null
+++ b/playground/src/main/scala/com/ing/baker/playground/commands/Docker.scala
@@ -0,0 +1,46 @@
+package com.ing.baker.playground.commands
+
+import cats.implicits._
+import com.ing.baker.playground.AppUtils._
+
+import scala.util.matching.Regex
+
+object Docker {
+
+ def networkName: String = "baker-playground-network"
+
+ def buildImage(path: String, tag: String): App[Unit] =
+ Terminal.exec(s"docker build $path -t $tag", s"Build $tag")
+
+ def checkForDockerVersion: App[Unit] = {
+ val DockerVersionReg: Regex = """Docker version (\d\d).*, build .+""".r
+ val requiredVersion: Int = 19
+ Terminal.execBlock("docker --version").flatMap {
+ case DockerVersionReg(version) =>
+ if (version.toInt >= requiredVersion) doNothing
+ else fail(s"Docker version is $version but $requiredVersion or greater is required.")
+ case _ =>
+ fail("Bad input for function isRequiredVersion")
+ }
+ }
+
+ def terminateAllImages: App[Unit] =
+ for {
+ env <- getState
+ _ <- env.runningImages.traverse(terminate)
+ _ <- modify(_.copy(runningImages = List.empty))
+ } yield ()
+
+ def terminate(name: String): App[Unit] =
+ Terminal.exec(s"docker kill $name", s"Terminate $name").tryForget *>
+ Terminal.execBlock(s"docker rm $name").tryForget
+
+ def createDockerNetwork: App[Unit] =
+ Terminal.exec(s"docker network create $networkName", "Docker Network").tryForget
+
+ def deleteDockerNetwork: App[Unit] =
+ Terminal.exec(s"docker network rm $networkName", "Remove Docker Network").tryForget
+
+ def dockerPull(image: String): App[Unit] =
+ Terminal.exec(s"docker pull $image", s"Pull $image Image").void
+}
diff --git a/playground/src/main/scala/com/ing/baker/playground/commands/EnvSystems.scala b/playground/src/main/scala/com/ing/baker/playground/commands/EnvSystems.scala
new file mode 100644
index 000000000..d1df706c2
--- /dev/null
+++ b/playground/src/main/scala/com/ing/baker/playground/commands/EnvSystems.scala
@@ -0,0 +1,28 @@
+package com.ing.baker.playground.commands
+
+import cats.implicits._
+import com.ing.baker.playground.AppUtils.{App, addRunningImage}
+import com.ing.baker.playground.commands.Docker.networkName
+
+object EnvSystems {
+
+ def cassandraName: String = "baker-cassandra"
+
+ def haproxyName: String = "baker-haproxy"
+
+ def runCassandra: App[Unit] =
+ Terminal.execAndWait(
+ command = s"docker run --name $cassandraName --network $networkName -p 9042:9042 -p 9160:9160 cassandra:latest",
+ prompt = "Cassandra",
+ condition = _.matches("""INFO \[OptionalTasks:1\] (.+) CassandraRoleManager\.java:372 - Created default superuser role 'cassandra'""")
+ ) *>
+ addRunningImage(cassandraName)
+
+ def runHaproxy: App[Unit] =
+ Terminal.execAndWait(
+ command = s"docker run --name $haproxyName --network $networkName ${BaaS.haproxyStateNodesImage}",
+ prompt = "HAProxy",
+ condition = _ => true
+ ) *>
+ addRunningImage(haproxyName)
+}
diff --git a/playground/src/main/scala/com/ing/baker/playground/commands/Terminal.scala b/playground/src/main/scala/com/ing/baker/playground/commands/Terminal.scala
new file mode 100644
index 000000000..1db6e7673
--- /dev/null
+++ b/playground/src/main/scala/com/ing/baker/playground/commands/Terminal.scala
@@ -0,0 +1,92 @@
+package com.ing.baker.playground.commands
+
+import cats.implicits._
+import cats.effect.IO
+
+import scala.sys.process._
+import com.ing.baker.playground.AppUtils._
+
+object Terminal {
+
+ def moveToBakerLocation: App[Unit] = {
+ for {
+ state <- getState
+ location <- state.bakerLocation match {
+ case None => confirmBakerProjectLocation
+ case Some(location0) => pure(location0)
+ }
+ _ <- cd(location)
+ } yield ()
+ }
+
+ private def confirmBakerProjectLocation: App[String] = {
+ def confirm(path: String): App[String] =
+ for {
+ answer <- query(s"Is $path the baker project location? input yes or the correct absolute path")
+ realPath <- answer match {
+ case "yes" | "y" | "ye" =>
+ pure(path)
+ case path0 =>
+ confirm(path0)
+ }
+ } yield realPath
+ pwd >>= confirm
+ }
+
+ def pwd: App[String] =
+ execBlock("pwd")
+
+ def cd(location: String): App[Unit] =
+ execBlock(s"cd $location").attempt.flatMap {
+ case Left(e) =>
+ fail(s"Could not move to directory $location... reason: ${e.getMessage}")
+ case Right(_) =>
+ doNothing
+ }
+
+ def query(question: String): App[String] =
+ printLn(question + ": ") *> readLn
+
+ def exec(command: String, prompt: String): App[Unit] = {
+ val p = prompt.randomColor
+ execWithLogger(command, ProcessLogger(
+ _.prompt(p + " | ").print.unsafeRunSync(),
+ _.prompt((prompt + " [ERROR]").red + " | ").print.unsafeRunSync()
+ )).flatMap { running =>
+ val exitValue = running.exitValue()
+ if (exitValue == 0) doNothing
+ else fail(new Exception(s"Command $command exited with non zero value $exitValue"))
+ }
+ }
+
+ def execAndWait(command: String, prompt: String, condition: String => Boolean): App[Process] = {
+ val process = Process(command)
+ IO.async[Process] { callback =>
+ val p = prompt.randomColor
+ var running: Process = null
+ var matched: Boolean = false
+ running = process.run(ProcessLogger(
+ { line =>
+ line.prompt(p + " | ").print.unsafeRunSync()
+ if(condition(line) && !matched) {
+ matched = true
+ callback(Right(running))
+ }
+ },
+ { line =>
+ line.prompt((prompt + " [ERROR]").red + " | ").print.unsafeRunSync()
+ if(condition(line) && !matched) {
+ matched = true
+ callback(Right(running))
+ }
+ }
+ ))
+ }
+ }.app
+
+ def execBlock(command: String): App[String] =
+ IO { Process(command).!!<.trim }.app
+
+ def execWithLogger(command: String, logger: ProcessLogger): App[Process] =
+ IO { Process(command).run(logger) }.app
+}
diff --git a/project/Dependencies.scala b/project/Dependencies.scala
index e495c85ec..8923b939d 100644
--- a/project/Dependencies.scala
+++ b/project/Dependencies.scala
@@ -16,6 +16,7 @@ object Dependencies {
.exclude("com.typesafe.akka", "akka-persistence-query")
.exclude("com.typesafe.akka", "akka-stream")
+ val scalaJava8Compat = "org.scala-lang.modules" %% "scala-java8-compat" % "0.8.0"
val scalaTest = "org.scalatest" %% "scalatest" % "3.0.8"
val mockito = "org.mockito" % "mockito-all" % "1.10.19"
val junitInterface = "com.novocode" % "junit-interface" % "0.11"
@@ -28,12 +29,16 @@ object Dependencies {
val akkaPersistenceCassandra = "com.typesafe.akka" %% "akka-persistence-cassandra" % "0.101"
val akkaCluster = "com.typesafe.akka" %% "akka-cluster" % akkaVersion
val akkaClusterSharding = "com.typesafe.akka" %% "akka-cluster-sharding" % akkaVersion
+ val akkaDistributedData = "com.typesafe.akka" %% "akka-distributed-data" % akkaVersion
+ val akkaClusterTools = "com.typesafe.akka" %% "akka-cluster-tools" % akkaVersion
val akkaSlf4j = "com.typesafe.akka" %% "akka-slf4j" % akkaVersion
val akkaTestKit = "com.typesafe.akka" %% "akka-testkit" % akkaVersion
val akkaStreamTestKit = "com.typesafe.akka" %% "akka-stream-testkit" % akkaVersion
val akkaMultiNodeTestkit = "com.typesafe.akka" %% "akka-multi-node-testkit" % akkaVersion
-
- val akkaHttp = "com.typesafe.akka" %% "akka-http" % "10.0.15"
+ val akkaManagementHttp = "com.lightbend.akka.management" %% "akka-management-cluster-http" % "1.0.5"
+ val akkaClusterBoostrap = "com.lightbend.akka.management" %% "akka-management-cluster-bootstrap" % "1.0.5"
+ val akkaDiscoveryKube = "com.lightbend.akka.discovery" %% "akka-discovery-kubernetes-api" % "1.0.5"
+ val akkaHttp = "com.typesafe.akka" %% "akka-http" % "10.1.11"
val akkaBoostrap = "com.lightbend.akka.management" %% "akka-management-cluster-bootstrap" % "1.0.5"
val levelDB = "org.iq80.leveldb" % "leveldb" % "0.12"
@@ -60,6 +65,9 @@ object Dependencies {
val catsEffect = "org.typelevel" %% "cats-effect" % "2.0.0"
val catsCore = "org.typelevel" %% "cats-core" % "2.0.0"
+ val console4Cats = "dev.profunktor" %% "console4cats" % "0.8.0"
+
+ val jnrConstants = "com.github.jnr" % "jnr-constants" % "0.9.9"
def scalaReflect(scalaV: String): ModuleID = "org.scala-lang"% "scala-reflect" % scalaV
val javaxInject = "javax.inject" % "javax.inject" % "1"
diff --git a/project/plugins.sbt b/project/plugins.sbt
index d44dc3ec0..9ccb8769c 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -14,6 +14,4 @@ addSbtPlugin("com.typesafe.sbt" % "sbt-multi-jvm" % "0.4.0")
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.5.1")
-libraryDependencies += "org.slf4j" % "slf4j-nop" % "1.7.29"
-
-addSbtPlugin("io.kamon" % "sbt-kanela-runner" % "2.0.3")
\ No newline at end of file
+libraryDependencies += "org.slf4j" % "slf4j-nop" % "1.7.29"
\ No newline at end of file
diff --git a/recipe-dsl/src/test/scala/com/ing/baker/recipe/common/InteractionFailureStrategySpec.scala b/recipe-dsl/src/test/scala/com/ing/baker/recipe/common/InteractionFailureStrategySpec.scala
index 43939c3e5..d87e89ad0 100644
--- a/recipe-dsl/src/test/scala/com/ing/baker/recipe/common/InteractionFailureStrategySpec.scala
+++ b/recipe-dsl/src/test/scala/com/ing/baker/recipe/common/InteractionFailureStrategySpec.scala
@@ -34,7 +34,7 @@ class InteractionFailureStrategySpec extends WordSpecLike with Matchers {
"derive the correct parameters when deadline is specified2" in {
val deadline = 16 seconds
- val initialDelay = 1 seconds
+ val initialDelay = 1.seconds
val backoffFactor: Double = 2.0
val actual = RetryWithIncrementalBackoff.builder()
@@ -55,7 +55,7 @@ class InteractionFailureStrategySpec extends WordSpecLike with Matchers {
"derive the correct parameters when deadline is specified and max time between retries set" in {
val deadline = 22 seconds
- val initialDelay = 1 seconds
+ val initialDelay = 1.seconds
val backoffFactor: Double = 2.0
val maxDurationBetweenRetries = 4 seconds
@@ -78,7 +78,7 @@ class InteractionFailureStrategySpec extends WordSpecLike with Matchers {
"verify that deadline is greater than initial delay" in {
- val deadline = 1 seconds
+ val deadline = 1.seconds
val initialDelay = 2 seconds
intercept[IllegalArgumentException] {
diff --git a/runtime/src/main/protobuf/process_instance.proto b/runtime/src/main/protobuf/process_instance.proto
index 81576e04d..886a8e670 100644
--- a/runtime/src/main/protobuf/process_instance.proto
+++ b/runtime/src/main/protobuf/process_instance.proto
@@ -18,14 +18,14 @@ message ConsumedToken {
message Initialized {
- option (scalapb.message).extends = "com.ing.baker.runtime.akka.actor.serialization.BakerSerializable";
+ option (scalapb.message).extends = "com.ing.baker.runtime.serialization.BakerSerializable";
repeated ProducedToken initial_marking = 1;
optional SerializedData initial_state = 2;
}
message TransitionFired {
- option (scalapb.message).extends = "com.ing.baker.runtime.akka.actor.serialization.BakerSerializable";
+ option (scalapb.message).extends = "com.ing.baker.runtime.serialization.BakerSerializable";
optional int64 job_id = 1;
optional string correlation_id = 9;
@@ -50,7 +50,7 @@ message FailureStrategy {
message TransitionFailed {
- option (scalapb.message).extends = "com.ing.baker.runtime.akka.actor.serialization.BakerSerializable";
+ option (scalapb.message).extends = "com.ing.baker.runtime.serialization.BakerSerializable";
optional int64 job_id = 1;
optional string correlation_id = 10;
diff --git a/runtime/src/main/resources/reference.conf b/runtime/src/main/resources/reference.conf
index 9b18cd939..a51a4dcf2 100644
--- a/runtime/src/main/resources/reference.conf
+++ b/runtime/src/main/resources/reference.conf
@@ -52,6 +52,18 @@ baker {
# if enabled = on, a secret should be set
# secret = ???
}
+
+ # use "local" unless you are configuring a BaaS environment, then you will need "remote"
+ interaction-manager = "local"
+
+ remote-interaction-manager {
+
+ # amount of time to wait before failing an interaction when the remote interaction manager can't find an interaction node to run on
+ post-timeout = 10 seconds
+
+ # amount of time to wait before failing an interaction when the interaction node is not responding with the computation result
+ computation-timeout = 60 seconds
+ }
}
akka {
@@ -70,13 +82,14 @@ akka {
serialization-bindings {
- "com.ing.baker.runtime.akka.actor.serialization.BakerSerializable" = baker-typed-protobuf
+ "com.ing.baker.runtime.serialization.BakerSerializable" = baker-typed-protobuf
"com.ing.baker.types.Value" = baker-typed-protobuf
"com.ing.baker.types.Type" = baker-typed-protobuf
"com.ing.baker.il.CompiledRecipe" = baker-typed-protobuf
"com.ing.baker.runtime.scaladsl.EventInstance" = baker-typed-protobuf
"com.ing.baker.runtime.scaladsl.RecipeInstanceState" = baker-typed-protobuf
+ "com.ing.baker.runtime.scaladsl.RecipeEventMetadata" = baker-typed-protobuf
}
}
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/AkkaBaker.scala b/runtime/src/main/scala/com/ing/baker/runtime/akka/AkkaBaker.scala
index 50b407519..f6892d39c 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/AkkaBaker.scala
+++ b/runtime/src/main/scala/com/ing/baker/runtime/akka/AkkaBaker.scala
@@ -1,29 +1,60 @@
package com.ing.baker.runtime.akka
-import akka.actor.{ Actor, ActorRef, Props }
-import akka.pattern.{ FutureRef, ask }
+import akka.actor.{Actor, ActorRef, ActorSystem, Address, Props}
+import akka.pattern.{FutureRef, ask}
import akka.util.Timeout
+import cats.data.NonEmptyList
import com.ing.baker.il._
import com.ing.baker.il.failurestrategy.ExceptionStrategyOutcome
import com.ing.baker.runtime.akka.actor._
import com.ing.baker.runtime.akka.actor.process_index.ProcessIndexProtocol._
-import com.ing.baker.runtime.akka.actor.process_instance.ProcessInstanceProtocol.{ Initialized, InstanceState, Uninitialized }
+import com.ing.baker.runtime.akka.actor.process_instance.ProcessInstanceProtocol.{Initialized, InstanceState, Uninitialized}
import com.ing.baker.runtime.akka.actor.recipe_manager.RecipeManagerProtocol
import com.ing.baker.runtime.common.BakerException._
import com.ing.baker.runtime.common.SensoryEventStatus
+import com.ing.baker.runtime.{javadsl, scaladsl}
import com.ing.baker.runtime.scaladsl._
import com.ing.baker.types.Value
+import com.typesafe.config.Config
import com.typesafe.scalalogging.LazyLogging
+
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.language.postfixOps
import scala.util.Try
+object AkkaBaker {
+
+ def apply(config: Config, actorSystem: ActorSystem): scaladsl.Baker =
+ new AkkaBaker(AkkaBakerConfig.from(config, actorSystem))
+
+ def withConfig(config: AkkaBakerConfig): scaladsl.Baker =
+ new AkkaBaker(config)
+
+ def localDefault(actorSystem: ActorSystem): scaladsl.Baker =
+ new AkkaBaker(AkkaBakerConfig.localDefault(actorSystem))
+
+ def clusterDefault(seedNodes: NonEmptyList[Address], actorSystem: ActorSystem): scaladsl.Baker =
+ new AkkaBaker(AkkaBakerConfig.clusterDefault(seedNodes, actorSystem))
+
+ def javaWithConfig(config: AkkaBakerConfig): javadsl.Baker =
+ new javadsl.Baker(withConfig(config))
+
+ def java(config: Config, actorSystem: ActorSystem): javadsl.Baker =
+ new javadsl.Baker(apply(config, actorSystem))
+
+ def javaLocalDefault(actorSystem: ActorSystem): javadsl.Baker =
+ new javadsl.Baker(new AkkaBaker(AkkaBakerConfig.localDefault(actorSystem)))
+
+ def javaOther(baker: scaladsl.Baker): javadsl.Baker =
+ new javadsl.Baker(baker)
+}
+
/**
* The Baker is the component of the Baker library that runs one or multiples recipes.
* For each recipe a new instance can be baked, sensory events can be send and state can be inquired upon
*/
-class AkkaBaker private[runtime](config: AkkaBakerConfig) extends Baker with LazyLogging {
+class AkkaBaker private[runtime](config: AkkaBakerConfig) extends scaladsl.Baker with LazyLogging {
import config.system
@@ -47,10 +78,10 @@ class AkkaBaker private[runtime](config: AkkaBakerConfig) extends Baker with Laz
val implementationErrors = getImplementationErrors(compiledRecipe)
if (implementationErrors.nonEmpty)
- Future.failed(new ImplementationsException(implementationErrors.mkString(", ")))
+ Future.failed(ImplementationsException(implementationErrors.mkString(", ")))
else if (compiledRecipe.validationErrors.nonEmpty)
- Future.failed(new RecipeValidationException(compiledRecipe.validationErrors.mkString(", ")))
+ Future.failed(RecipeValidationException(compiledRecipe.validationErrors.mkString(", ")))
else recipeManager.ask(RecipeManagerProtocol.AddRecipe(compiledRecipe))(config.defaultAddRecipeTimeout) flatMap {
case RecipeManagerProtocol.AddRecipeResponse(recipeId) => Future.successful(recipeId)
@@ -58,7 +89,7 @@ class AkkaBaker private[runtime](config: AkkaBakerConfig) extends Baker with Laz
}
private def getImplementationErrors(compiledRecipe: CompiledRecipe): Set[String] = {
- compiledRecipe.interactionTransitions.filterNot(config.interactionManager.getImplementation(_).isDefined)
+ compiledRecipe.interactionTransitions.filterNot(config.interactionManager.hasImplementation)
.map(s => s"No implementation provided for interaction: ${s.originalInteractionName}")
}
@@ -74,7 +105,7 @@ class AkkaBaker private[runtime](config: AkkaBakerConfig) extends Baker with Laz
case RecipeManagerProtocol.RecipeFound(compiledRecipe, timestamp) =>
Future.successful(RecipeInformation(compiledRecipe, timestamp, getImplementationErrors(compiledRecipe)))
case RecipeManagerProtocol.NoRecipeFound(_) =>
- Future.failed(new IllegalArgumentException(s"No recipe found for recipe with id: $recipeId"))
+ Future.failed(NoSuchRecipeException(recipeId))
}
}
@@ -102,9 +133,9 @@ class AkkaBaker private[runtime](config: AkkaBakerConfig) extends Baker with Laz
case _: Initialized =>
Future.successful(())
case ProcessAlreadyExists(_) =>
- Future.failed(new IllegalArgumentException(s"Process with id '$recipeInstanceId' already exists."))
+ Future.failed(ProcessAlreadyExistsException(recipeInstanceId))
case RecipeManagerProtocol.NoRecipeFound(_) =>
- Future.failed(new IllegalArgumentException(s"Recipe with id '$recipeId' does not exist."))
+ Future.failed(NoSuchRecipeException(recipeId))
}
}
@@ -118,9 +149,9 @@ class AkkaBaker private[runtime](config: AkkaBakerConfig) extends Baker with Laz
))(config.defaultProcessEventTimeout).flatMap {
// TODO MOVE THIS TO A FUNCTION
case FireSensoryEventRejection.InvalidEvent(_, message) =>
- Future.failed(new IllegalArgumentException(message))
+ Future.failed(IllegalEventException(message))
case FireSensoryEventRejection.NoSuchRecipeInstance(recipeInstanceId0) =>
- Future.failed(new NoSuchProcessException(s"Process with id $recipeInstanceId0 does not exist in the index"))
+ Future.failed(NoSuchProcessException(recipeInstanceId0))
case _: FireSensoryEventRejection.FiringLimitMet =>
Future.successful(SensoryEventStatus.FiringLimitMet)
case _: FireSensoryEventRejection.AlreadyReceived =>
@@ -142,9 +173,9 @@ class AkkaBaker private[runtime](config: AkkaBakerConfig) extends Baker with Laz
reaction = FireSensoryEventReaction.NotifyWhenCompleted(waitForRetries = true)
))(config.defaultProcessEventTimeout).flatMap {
case FireSensoryEventRejection.InvalidEvent(_, message) =>
- Future.failed(new IllegalArgumentException(message))
+ Future.failed(IllegalEventException(message))
case FireSensoryEventRejection.NoSuchRecipeInstance(recipeInstanceId0) =>
- Future.failed(new NoSuchProcessException(s"Process with id $recipeInstanceId0 does not exist in the index"))
+ Future.failed(NoSuchProcessException(recipeInstanceId0))
case _: FireSensoryEventRejection.FiringLimitMet =>
Future.successful(SensoryEventResult(SensoryEventStatus.FiringLimitMet, Seq.empty, Map.empty))
case _: FireSensoryEventRejection.AlreadyReceived =>
@@ -166,9 +197,9 @@ class AkkaBaker private[runtime](config: AkkaBakerConfig) extends Baker with Laz
reaction = FireSensoryEventReaction.NotifyOnEvent(waitForRetries = true, onEvent)
))(config.defaultProcessEventTimeout).flatMap {
case FireSensoryEventRejection.InvalidEvent(_, message) =>
- Future.failed(new IllegalArgumentException(message))
+ Future.failed(IllegalEventException(message))
case FireSensoryEventRejection.NoSuchRecipeInstance(recipeInstanceId0) =>
- Future.failed(new NoSuchProcessException(s"Process with id $recipeInstanceId0 does not exist in the index"))
+ Future.failed(NoSuchProcessException(recipeInstanceId0))
case _: FireSensoryEventRejection.FiringLimitMet =>
Future.successful(SensoryEventResult(SensoryEventStatus.FiringLimitMet, Seq.empty, Map.empty))
case _: FireSensoryEventRejection.AlreadyReceived =>
@@ -194,9 +225,9 @@ class AkkaBaker private[runtime](config: AkkaBakerConfig) extends Baker with Laz
completeReceiver = futureRef.ref)
))(config.defaultProcessEventTimeout).flatMap {
case FireSensoryEventRejection.InvalidEvent(_, message) =>
- Future.failed(new IllegalArgumentException(message))
+ Future.failed(IllegalEventException(message))
case FireSensoryEventRejection.NoSuchRecipeInstance(recipeInstanceId0) =>
- Future.failed(new NoSuchProcessException(s"Process with id $recipeInstanceId0 does not exist in the index"))
+ Future.failed(NoSuchProcessException(recipeInstanceId0))
case _: FireSensoryEventRejection.FiringLimitMet =>
Future.successful(SensoryEventStatus.FiringLimitMet)
case _: FireSensoryEventRejection.AlreadyReceived =>
@@ -211,9 +242,9 @@ class AkkaBaker private[runtime](config: AkkaBakerConfig) extends Baker with Laz
val futureCompleted =
futureRef.future.flatMap {
case FireSensoryEventRejection.InvalidEvent(_, message) =>
- Future.failed(new IllegalArgumentException(message))
+ Future.failed(IllegalEventException(message))
case FireSensoryEventRejection.NoSuchRecipeInstance(recipeInstanceId0) =>
- Future.failed(new NoSuchProcessException(s"Process with id $recipeInstanceId0 does not exist in the index"))
+ Future.failed(NoSuchProcessException(recipeInstanceId0))
case _: FireSensoryEventRejection.FiringLimitMet =>
Future.successful(SensoryEventResult(SensoryEventStatus.FiringLimitMet, Seq.empty, Map.empty))
case _: FireSensoryEventRejection.AlreadyReceived =>
@@ -284,8 +315,8 @@ class AkkaBaker private[runtime](config: AkkaBakerConfig) extends Baker with Laz
.ask(GetProcessState(recipeInstanceId))(Timeout.durationToTimeout(config.defaultInquireTimeout))
.flatMap {
case instance: InstanceState => Future.successful(instance.state.asInstanceOf[RecipeInstanceState])
- case NoSuchProcess(id) => Future.failed(new NoSuchProcessException(s"No such process with: $id"))
- case ProcessDeleted(id) => Future.failed(new ProcessDeletedException(s"Process $id is deleted"))
+ case NoSuchProcess(id) => Future.failed(NoSuchProcessException(id))
+ case ProcessDeleted(id) => Future.failed(ProcessDeletedException(id))
}
/**
@@ -335,21 +366,21 @@ class AkkaBaker private[runtime](config: AkkaBakerConfig) extends Baker with Laz
eventNames = processState.eventNames.toSet,
ingredientNames = processState.ingredients.keySet))
case ProcessDeleted(_) =>
- Future.failed(new ProcessDeletedException(s"Process $recipeInstanceId is deleted"))
+ Future.failed(ProcessDeletedException(recipeInstanceId))
case Uninitialized(_) =>
- Future.failed(new NoSuchProcessException(s"Process $recipeInstanceId is not found"))
+ Future.failed(NoSuchProcessException(recipeInstanceId))
}
} yield response
}
- private def doRegisterEventListener(listenerFunction: (String, EventInstance) => Unit, processFilter: String => Boolean): Future[Unit] = {
+ private def doRegisterEventListener(listenerFunction: (RecipeEventMetadata, EventInstance) => Unit, processFilter: String => Boolean): Future[Unit] = {
registerBakerEventListener {
- case EventReceived(_, recipeName, _, recipeInstanceId, _, event) if processFilter(recipeName) =>
- listenerFunction.apply(recipeInstanceId, event)
- case InteractionCompleted(_, _, recipeName, _, recipeInstanceId, _, Some(event)) if processFilter(recipeName) =>
- listenerFunction.apply(recipeInstanceId, event)
- case InteractionFailed(_, _, recipeName, _, recipeInstanceId, _, _, _, ExceptionStrategyOutcome.Continue(eventName)) if processFilter(recipeName) =>
- listenerFunction.apply(recipeInstanceId, EventInstance(eventName, Map.empty))
+ case EventReceived(_, recipeName, recipeId, recipeInstanceId, _, event) if processFilter(recipeName) =>
+ listenerFunction.apply(RecipeEventMetadata(recipeId = recipeId, recipeName = recipeName, recipeInstanceId = recipeInstanceId), event)
+ case InteractionCompleted(_, _, recipeName, recipeId, recipeInstanceId, _, Some(event)) if processFilter(recipeName) =>
+ listenerFunction.apply(RecipeEventMetadata(recipeId = recipeId, recipeName = recipeName, recipeInstanceId = recipeInstanceId), event)
+ case InteractionFailed(_, _, recipeName, recipeId, recipeInstanceId, _, _, _, ExceptionStrategyOutcome.Continue(eventName)) if processFilter(recipeName) =>
+ listenerFunction.apply(RecipeEventMetadata(recipeId = recipeId, recipeName = recipeName, recipeInstanceId = recipeInstanceId), EventInstance(eventName, Map.empty))
case _ => ()
}
}
@@ -359,7 +390,7 @@ class AkkaBaker private[runtime](config: AkkaBakerConfig) extends Baker with Laz
*
* Note that the delivery guarantee is *AT MOST ONCE*. Do not use it for critical functionality
*/
- override def registerEventListener(recipeName: String, listenerFunction: (String, EventInstance) => Unit): Future[Unit] =
+ override def registerEventListener(recipeName: String, listenerFunction: (RecipeEventMetadata, EventInstance) => Unit): Future[Unit] =
doRegisterEventListener(listenerFunction, _ == recipeName)
/**
@@ -368,7 +399,7 @@ class AkkaBaker private[runtime](config: AkkaBakerConfig) extends Baker with Laz
* Note that the delivery guarantee is *AT MOST ONCE*. Do not use it for critical functionality
*/
// @deprecated("Use event bus instead", "1.4.0")
- override def registerEventListener(listenerFunction: (String, EventInstance) => Unit): Future[Unit] =
+ override def registerEventListener(listenerFunction: (RecipeEventMetadata, EventInstance) => Unit): Future[Unit] =
doRegisterEventListener(listenerFunction, _ => true)
/**
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/AkkaBakerConfig.scala b/runtime/src/main/scala/com/ing/baker/runtime/akka/AkkaBakerConfig.scala
index b904bddaa..e2dd6e562 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/AkkaBakerConfig.scala
+++ b/runtime/src/main/scala/com/ing/baker/runtime/akka/AkkaBakerConfig.scala
@@ -1,15 +1,16 @@
package com.ing.baker.runtime.akka
-import akka.actor.{ ActorSystem, Address, AddressFromURIString }
+import akka.actor.{ActorSystem, Address, AddressFromURIString}
import akka.persistence.query.PersistenceQuery
-import akka.persistence.query.scaladsl.{ CurrentEventsByPersistenceIdQuery, CurrentPersistenceIdsQuery, PersistenceIdsQuery }
+import akka.persistence.query.scaladsl.{CurrentEventsByPersistenceIdQuery, CurrentPersistenceIdsQuery, PersistenceIdsQuery}
import cats.data.NonEmptyList
import com.ing.baker.runtime.akka.AkkaBakerConfig.BakerPersistenceQuery
-import com.ing.baker.runtime.akka.actor.serialization.Encryption
-import com.ing.baker.runtime.akka.actor.{ BakerActorProvider, ClusterBakerActorProvider, LocalBakerActorProvider }
-import com.ing.baker.runtime.akka.internal.InteractionManager
+import com.ing.baker.runtime.akka.actor.{BakerActorProvider, ClusterBakerActorProvider, LocalBakerActorProvider}
+import com.ing.baker.runtime.akka.internal.{InteractionManager, InteractionManagerDis, InteractionManagerLocal}
+import com.ing.baker.runtime.serialization.Encryption
import com.typesafe.config.Config
import net.ceedubs.ficus.Ficus._
+
import scala.concurrent.duration._
case class AkkaBakerConfig(
@@ -58,7 +59,7 @@ object AkkaBakerConfig {
defaultShutdownTimeout = 30.seconds,
defaultAddRecipeTimeout = 10.seconds,
bakerActorProvider = provider,
- interactionManager = new InteractionManager(),
+ interactionManager = new InteractionManagerLocal(),
readJournal = PersistenceQuery(actorSystem)
.readJournalFor[BakerPersistenceQuery]("inmemory-read-journal")
)(actorSystem)
@@ -106,7 +107,14 @@ object AkkaBakerConfig {
case Some(other) => throw new IllegalArgumentException(s"Unsupported actor provider: $other")
}
},
- interactionManager = new InteractionManager,
+ interactionManager = config.as[Option[String]]("baker.interaction-manager") match {
+ case Some("remote") =>
+ val postTimeout = config.as[FiniteDuration]("baker.remote-interaction-manager.post-timeout")
+ val computationTimeout = config.as[FiniteDuration]("baker.remote-interaction-manager.computation-timeout")
+ new InteractionManagerDis(actorSystem, postTimeout, computationTimeout)
+ case _ =>
+ new InteractionManagerLocal()
+ },
readJournal = PersistenceQuery(actorSystem)
.readJournalFor[BakerPersistenceQuery](config.as[String]("baker.actor.read-journal-plugin"))
)(actorSystem)
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/ClusterBakerActorProvider.scala b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/ClusterBakerActorProvider.scala
index 7e9b4d3c0..004eff171 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/ClusterBakerActorProvider.scala
+++ b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/ClusterBakerActorProvider.scala
@@ -15,8 +15,8 @@ import com.ing.baker.runtime.akka.actor.process_index.ProcessIndex.ActorMetadata
import com.ing.baker.runtime.akka.actor.process_index.ProcessIndexProtocol._
import com.ing.baker.runtime.akka.actor.process_index._
import com.ing.baker.runtime.akka.actor.recipe_manager.RecipeManager
-import com.ing.baker.runtime.akka.actor.serialization.{BakerSerializable, Encryption}
import com.ing.baker.runtime.akka.internal.InteractionManager
+import com.ing.baker.runtime.serialization.{BakerSerializable, Encryption}
import com.typesafe.scalalogging.LazyLogging
import scala.concurrent.duration._
import scala.concurrent.{Await, TimeoutException}
@@ -91,10 +91,16 @@ class ClusterBakerActorProvider(
override def createProcessIndexActor(interactionManager: InteractionManager, recipeManager: ActorRef)(implicit actorSystem: ActorSystem): ActorRef = {
+ val roles = Cluster(actorSystem).selfRoles
ClusterSharding(actorSystem).start(
typeName = "ProcessIndexActor",
entityProps = ProcessIndex.props(actorIdleTimeout, Some(retentionCheckInterval), configuredEncryption, interactionManager, recipeManager, ingredientsFilter),
- settings = ClusterShardingSettings.create(actorSystem),
+ settings = {
+ if(roles.contains("state-node"))
+ ClusterShardingSettings(actorSystem).withRole("state-node")
+ else
+ ClusterShardingSettings(actorSystem)
+ },
extractEntityId = ClusterBakerActorProvider.entityIdExtractor(nrOfShards),
extractShardId = ClusterBakerActorProvider.shardIdExtractor(nrOfShards)
)
@@ -108,12 +114,18 @@ class ClusterBakerActorProvider(
RecipeManager.props(),
terminationMessage = PoisonPill,
settings = ClusterSingletonManagerSettings(actorSystem))
+ val roles = Cluster(actorSystem).selfRoles
actorSystem.actorOf(props = singletonManagerProps, name = recipeManagerName)
val singletonProxyProps = ClusterSingletonProxy.props(
singletonManagerPath = s"/user/$recipeManagerName",
- settings = ClusterSingletonProxySettings(actorSystem))
+ settings = {
+ if (roles.contains("state-node"))
+ ClusterSingletonProxySettings(actorSystem).withRole("state-node")
+ else
+ ClusterSingletonProxySettings(actorSystem)
+ })
actorSystem.actorOf(props = singletonProxyProps, name = "RecipeManagerProxy")
}
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/LocalBakerActorProvider.scala b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/LocalBakerActorProvider.scala
index 9e6967fcd..04c446f52 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/LocalBakerActorProvider.scala
+++ b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/LocalBakerActorProvider.scala
@@ -1,12 +1,13 @@
package com.ing.baker.runtime.akka.actor
-import akka.actor.{ ActorRef, ActorSystem }
+import akka.actor.{ActorRef, ActorSystem}
import com.ing.baker.runtime.akka.actor.process_index.ProcessIndex
import com.ing.baker.runtime.akka.actor.process_index.ProcessIndex.ActorMetadata
-import com.ing.baker.runtime.akka.actor.process_index.ProcessIndexProtocol.{ GetIndex, Index }
+import com.ing.baker.runtime.akka.actor.process_index.ProcessIndexProtocol.{GetIndex, Index}
import com.ing.baker.runtime.akka.actor.recipe_manager.RecipeManager
-import com.ing.baker.runtime.akka.actor.serialization.Encryption
import com.ing.baker.runtime.akka.internal.InteractionManager
+import com.ing.baker.runtime.serialization.Encryption
+
import scala.concurrent.Await
import scala.concurrent.duration._
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/interaction_scheduling/QuestMandated.scala b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/interaction_scheduling/QuestMandated.scala
new file mode 100644
index 000000000..4c68d2814
--- /dev/null
+++ b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/interaction_scheduling/QuestMandated.scala
@@ -0,0 +1,92 @@
+package com.ing.baker.runtime.akka.actor.interaction_scheduling
+
+import java.util.UUID
+
+import akka.actor.{Actor, ActorRef, PoisonPill, Props}
+import akka.cluster.pubsub.{DistributedPubSub, DistributedPubSubMediator}
+import akka.util.Timeout
+import com.ing.baker.runtime.akka.actor.interaction_scheduling.QuestMandated.{ComputationTimeout, PostTimeout, Start}
+import com.ing.baker.runtime.scaladsl.IngredientInstance
+import org.slf4j.LoggerFactory
+import QuestMandated._
+import com.ing.baker.baas.protocol.{ProtocolInteractionExecution, ProtocolPushPullMatching, ProtocolQuestCommit}
+
+object QuestMandated {
+
+ case object Start
+
+ case object PostTimeout
+
+ case object ComputationTimeout
+
+ def apply(ingredients: Seq[IngredientInstance], interactionName: String, postTimeout: Timeout, computationTimeout: Timeout): Props =
+ Props(new QuestMandated(UUID.randomUUID(), ingredients, interactionName, postTimeout, computationTimeout))
+
+ private val log = LoggerFactory.getLogger(classOf[QuestMandated])
+}
+
+class QuestMandated(uuid: UUID, ingredients: Seq[IngredientInstance], interactionName: String, postTimeout: Timeout, computationTimeout: Timeout) extends Actor {
+
+ val mediator: ActorRef = DistributedPubSub(context.system).mediator
+
+ val pullTopic: String =
+ ProtocolPushPullMatching.pullTopic(interactionName)
+
+ val pushTopic: String =
+ ProtocolPushPullMatching.pushTopic(interactionName)
+
+ def push(): Unit =
+ mediator ! DistributedPubSubMediator.Publish(pushTopic, ProtocolPushPullMatching.Push(self, uuid))
+
+ def start(): Unit = {
+ mediator ! DistributedPubSubMediator.Subscribe(pullTopic, self)
+ push()
+ context.system.scheduler.scheduleOnce(postTimeout.duration, self, PostTimeout)(context.dispatcher, self)
+ }
+
+
+ def receive: Receive = {
+ case Start =>
+ log.info(s"$interactionName:$uuid: Starting Quest for interaction")
+ start()
+ context.become(running(sender))
+ }
+
+ def running(manager: ActorRef): Receive = {
+ case ProtocolPushPullMatching.Pull(agent) =>
+ // respond with available quest
+ log.info(s"$interactionName:$uuid: responding to pull of available agent")
+ agent ! ProtocolPushPullMatching.AvailableQuest(self, uuid)
+
+ case ProtocolQuestCommit.Considering(agent) =>
+ log.info(s"$interactionName:$uuid: Mandate Quest for agent: $agent")
+ // start the interaction execution protocol by responding with a commit message
+ agent ! ProtocolQuestCommit.Commit(self, ProtocolInteractionExecution.ExecuteInstance(ingredients))
+ context.system.scheduler.scheduleOnce(computationTimeout.duration, self, ComputationTimeout)(context.dispatcher, self)
+ context.become(committed(manager))
+
+ case PostTimeout =>
+ log.info(s"$interactionName:$uuid: Timed out on waiting for response when trying to find agent")
+ manager ! ProtocolInteractionExecution.NoInstanceFound
+ self ! PoisonPill
+ }
+
+ def committed(manager: ActorRef): Receive = {
+
+ case message: ProtocolInteractionExecution =>
+ log.info(s"$interactionName:$uuid: Quest executed")
+ // report and kill himself
+ manager ! message
+ self ! PoisonPill
+
+ case ProtocolQuestCommit.Considering(agent) =>
+ log.info(s"$interactionName:$uuid: rejecting other agent: $agent")
+ agent ! ProtocolQuestCommit.QuestTaken
+
+ case ComputationTimeout =>
+ log.info(s"$interactionName:$uuid: Timed out on waiting for response of agent after commited")
+ manager ! ProtocolInteractionExecution.InstanceExecutionTimedOut
+ self ! PoisonPill
+ }
+
+}
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_index/ProcessIndex.scala b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_index/ProcessIndex.scala
index 2f47a9b15..eb18e9f36 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_index/ProcessIndex.scala
+++ b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_index/ProcessIndex.scala
@@ -1,31 +1,32 @@
package com.ing.baker.runtime.akka.actor.process_index
-import akka.actor.{ ActorRef, NoSerializationVerificationNeeded, Props, Terminated }
-import akka.event.{ DiagnosticLoggingAdapter, Logging }
+import akka.actor.{ActorRef, NoSerializationVerificationNeeded, Props, Terminated}
+import akka.event.{DiagnosticLoggingAdapter, Logging}
import akka.pattern.ask
-import akka.persistence.{ PersistentActor, RecoveryCompleted }
-import cats.data.{ EitherT, OptionT }
+import akka.persistence.{PersistentActor, RecoveryCompleted}
+import cats.data.{EitherT, OptionT}
import cats.effect.IO
import cats.instances.future._
-import com.ing.baker.il.petrinet.{ InteractionTransition, Place, Transition }
-import com.ing.baker.il.{ CompiledRecipe, EventDescriptor }
+import com.ing.baker.il.petrinet.{InteractionTransition, Place, Transition}
+import com.ing.baker.il.{CompiledRecipe, EventDescriptor}
import com.ing.baker.petrinet.api._
import com.ing.baker.runtime.akka.actor.Util.logging._
import com.ing.baker.runtime.akka.actor.process_index.ProcessIndex._
import com.ing.baker.runtime.akka.actor.process_index.ProcessIndexProtocol._
-import com.ing.baker.runtime.akka.actor.process_instance.ProcessInstanceProtocol.ExceptionStrategy.{ BlockTransition, Continue, RetryWithDelay }
+import com.ing.baker.runtime.akka.actor.process_instance.ProcessInstanceProtocol.ExceptionStrategy.{BlockTransition, Continue, RetryWithDelay}
import com.ing.baker.runtime.akka.actor.process_instance.ProcessInstanceProtocol._
-import com.ing.baker.runtime.akka.actor.process_instance.{ ProcessInstance, ProcessInstanceRuntime }
+import com.ing.baker.runtime.akka.actor.process_instance.{ProcessInstance, ProcessInstanceRuntime}
import com.ing.baker.runtime.akka.actor.recipe_manager.RecipeManagerProtocol._
-import com.ing.baker.runtime.akka.actor.serialization.{ BakerSerializable, Encryption }
-import com.ing.baker.runtime.akka.internal.{ InteractionManager, RecipeRuntime }
-import com.ing.baker.runtime.akka.{ namedCachedThreadPool, _ }
-import com.ing.baker.runtime.scaladsl.{ EventInstance, RecipeInstanceCreated, RecipeInstanceState }
+import com.ing.baker.runtime.akka.internal.{InteractionManager, RecipeRuntime}
+import com.ing.baker.runtime.akka.{namedCachedThreadPool, _}
+import com.ing.baker.runtime.scaladsl.{EventInstance, RecipeInstanceCreated, RecipeInstanceState}
+import com.ing.baker.runtime.serialization.{BakerSerializable, Encryption}
import com.ing.baker.types.Value
+
import scala.collection.mutable
import scala.concurrent.duration._
-import scala.concurrent.{ Await, ExecutionContext, Future }
-import scala.util.{ Failure, Success }
+import scala.concurrent.{Await, ExecutionContext, Future}
+import scala.util.{Failure, Success}
object ProcessIndex {
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_index/ProcessIndexProto.scala b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_index/ProcessIndexProto.scala
index f2595d70c..65ebfe316 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_index/ProcessIndexProto.scala
+++ b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_index/ProcessIndexProto.scala
@@ -9,9 +9,10 @@ import com.ing.baker.runtime.akka.actor.ClusterBakerActorProvider.GetShardIndex
import com.ing.baker.runtime.akka.actor.process_index.ProcessIndex._
import com.ing.baker.runtime.akka.actor.process_index.ProcessIndexProtocol.FireSensoryEventReaction.{NotifyBoth, NotifyOnEvent, NotifyWhenCompleted, NotifyWhenReceived}
import com.ing.baker.runtime.akka.actor.process_index.ProcessIndexProtocol.{ProcessEventReceivedResponse, _}
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap.{ctxFromProto, ctxToProto, versioned}
-import com.ing.baker.runtime.akka.actor.serialization.protomappings.SensoryEventStatusMappingHelper
-import com.ing.baker.runtime.akka.actor.serialization.{ProtoMap, SerializersProvider}
+import com.ing.baker.runtime.serialization.ProtoMap.{ctxFromProto, ctxToProto, versioned}
+import com.ing.baker.runtime.serialization.protomappings.SensoryEventStatusMappingHelper
+import com.ing.baker.runtime.serialization.SerializersProvider
+import com.ing.baker.runtime.serialization.{ProtoMap, SerializersProvider}
import scala.concurrent.duration.FiniteDuration
import scala.util.{Failure, Success, Try}
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_index/ProcessIndexProtocol.scala b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_index/ProcessIndexProtocol.scala
index ff1f70537..73494b2ed 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_index/ProcessIndexProtocol.scala
+++ b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_index/ProcessIndexProtocol.scala
@@ -2,9 +2,9 @@ package com.ing.baker.runtime.akka.actor.process_index
import akka.actor.ActorRef
import com.ing.baker.runtime.akka.actor.process_index.ProcessIndex.ActorMetadata
-import com.ing.baker.runtime.akka.actor.serialization.BakerSerializable
import com.ing.baker.runtime.scaladsl.{EventInstance, SensoryEventResult}
import com.ing.baker.runtime.common.{RejectReason, SensoryEventStatus}
+import com.ing.baker.runtime.serialization.BakerSerializable
import scala.concurrent.duration.FiniteDuration
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstance.scala b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstance.scala
index d4fe81db4..17d7d217f 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstance.scala
+++ b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstance.scala
@@ -15,8 +15,8 @@ import com.ing.baker.runtime.akka.actor.process_instance.ProcessInstanceProtocol
import com.ing.baker.runtime.akka.actor.process_instance.internal.ExceptionStrategy.{Continue, RetryWithDelay}
import com.ing.baker.runtime.akka.actor.process_instance.internal._
import com.ing.baker.runtime.akka.actor.process_instance.{ProcessInstanceProtocol => protocol}
-import com.ing.baker.runtime.akka.actor.serialization.Encryption
import com.ing.baker.runtime.scaladsl.RecipeInstanceState
+import com.ing.baker.runtime.serialization.Encryption
import com.ing.baker.types.PrimitiveValue
import scala.concurrent.ExecutionContext
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceEventSourcing.scala b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceEventSourcing.scala
index adc432c23..4fa383530 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceEventSourcing.scala
+++ b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceEventSourcing.scala
@@ -8,8 +8,8 @@ import akka.NotUsed
import akka.actor.{ActorSystem, NoSerializationVerificationNeeded}
import akka.persistence.query.scaladsl.CurrentEventsByPersistenceIdQuery
import akka.stream.scaladsl.Source
-import com.ing.baker.runtime.akka.actor.serialization.Encryption
-import com.ing.baker.runtime.akka.actor.serialization.SerializersProvider
+import com.ing.baker.runtime.serialization.SerializersProvider
+import com.ing.baker.runtime.serialization.Encryption
object ProcessInstanceEventSourcing {
@@ -92,12 +92,13 @@ object ProcessInstanceEventSourcing {
readJournal: CurrentEventsByPersistenceIdQuery,
eventSourceFn: T ⇒ (S ⇒ E ⇒ S))(implicit actorSystem: ActorSystem): Source[(Instance[P, T, S], Event), NotUsed] = {
- val serializer = new ProcessInstanceSerialization[P, T, S, E](SerializersProvider(actorSystem, null, encryption))
+ val serializer = new ProcessInstanceSerialization[P, T, S, E](SerializersProvider(actorSystem, encryption))
val persistentId = ProcessInstance.recipeInstanceId2PersistenceId(processTypeName, recipeInstanceId)
val src = readJournal.currentEventsByPersistenceId(persistentId, 0, Long.MaxValue)
val eventSource = ProcessInstanceEventSourcing.apply[P, T, S, E](eventSourceFn)
+ // TODO: remove null value
src.scan[(Instance[P, T, S], Event)]((Instance.uninitialized[P, T, S](topology), null.asInstanceOf[Event])) {
case ((instance, _), e) ⇒
val serializedEvent = e.event.asInstanceOf[AnyRef]
@@ -113,11 +114,12 @@ abstract class ProcessInstanceEventSourcing[P : Identifiable, T : Identifiable,
encryption: Encryption,
eventSourceFn: T => (S => E => S)) extends PersistentActor {
- implicit val system = context.system
+ protected implicit val system: ActorSystem = context.system
- val eventSource = ProcessInstanceEventSourcing.apply[P, T, S, E](eventSourceFn)
+ protected val eventSource: Instance[P, T, S] => Event => Instance[P, T, S] =
+ ProcessInstanceEventSourcing.apply[P, T, S, E](eventSourceFn)
- private val serializer = new ProcessInstanceSerialization[P, T, S, E](SerializersProvider(system, null, encryption))
+ private val serializer = new ProcessInstanceSerialization[P, T, S, E](SerializersProvider(system, encryption))
def onRecoveryCompleted(state: Instance[P, T, S])
@@ -128,7 +130,7 @@ abstract class ProcessInstanceEventSourcing[P : Identifiable, T : Identifiable,
private var recoveringState: Instance[P, T, S] = Instance.uninitialized[P, T, S](petriNet)
- private def applyToRecoveringState(e: AnyRef) = {
+ private def applyToRecoveringState(e: AnyRef): Unit = {
val deserializedEvent = serializer.deserializeEvent(e)(recoveringState)
recoveringState = eventSource(recoveringState)(deserializedEvent)
}
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceProto.scala b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceProto.scala
index e9c7700ec..be7ec4c52 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceProto.scala
+++ b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceProto.scala
@@ -7,9 +7,9 @@ import cats.syntax.traverse._
import com.ing.baker.petrinet.api.{Id, Marking, MultiSet}
import com.ing.baker.runtime.akka.actor.process_instance.ProcessInstanceProtocol._
import com.ing.baker.runtime.akka.actor.process_instance.protobuf.FailureStrategyMessage.StrategyTypeMessage
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap.{ctxFromProto, ctxToProto, versioned}
-import com.ing.baker.runtime.akka.actor.serialization.SerializersProvider
+import com.ing.baker.runtime.serialization.ProtoMap.{ctxFromProto, ctxToProto, versioned}
+import com.ing.baker.runtime.serialization.SerializersProvider
+import com.ing.baker.runtime.serialization.{ProtoMap, SerializersProvider}
import scalapb.GeneratedMessageCompanion
import scala.util.{Failure, Success, Try}
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceProtocol.scala b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceProtocol.scala
index 8d0376c38..0572b73fc 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceProtocol.scala
+++ b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceProtocol.scala
@@ -1,7 +1,7 @@
package com.ing.baker.runtime.akka.actor.process_instance
import com.ing.baker.petrinet.api._
-import com.ing.baker.runtime.akka.actor.serialization.BakerSerializable
+import com.ing.baker.runtime.serialization.BakerSerializable
/**
* Describes the messages to and from a PetriNetInstance actor.
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceSerialization.scala b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceSerialization.scala
index 07c9f664c..20c77d729 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceSerialization.scala
+++ b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceSerialization.scala
@@ -1,40 +1,17 @@
package com.ing.baker.runtime.akka.actor.process_instance
-import java.security.MessageDigest
-
import com.ing.baker.petrinet.api._
import com.ing.baker.runtime.akka.actor.process_instance.ProcessInstanceEventSourcing._
-import com.ing.baker.runtime.akka.actor.process_instance.ProcessInstanceSerialization._
import com.ing.baker.runtime.akka.actor.process_instance.internal.ExceptionStrategy.{BlockTransition, RetryWithDelay}
import com.ing.baker.runtime.akka.actor.process_instance.internal.Instance
import com.ing.baker.runtime.akka.actor.process_instance.protobuf.FailureStrategy.StrategyType
import com.ing.baker.runtime.akka.actor.process_instance.protobuf._
import com.ing.baker.runtime.akka.actor.protobuf.{ProducedToken, SerializedData}
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap.{ctxFromProto, ctxToProto}
-import com.ing.baker.runtime.akka.actor.serialization.SerializersProvider
+import com.ing.baker.runtime.serialization.ProtoMap.{ctxFromProto, ctxToProto}
+import com.ing.baker.runtime.serialization.{SerializersProvider, TokenIdentifier}
import scala.util.{Failure, Success}
-object ProcessInstanceSerialization {
-
- /**
- * TODO:
- *
- * This approach is fragile, the identifier function cannot change ever or recovery breaks
- * a more robust alternative is to generate the ids and persist them
- */
- def tokenIdentifier(tokenValue: Any): Long = tokenValue match {
- case null => -1
- case str: String => sha256(str)
- case obj => obj.hashCode()
- }
-
- def sha256(str: String) = {
- val sha256Digest: MessageDigest = MessageDigest.getInstance("SHA-256")
- BigInt(1, sha256Digest.digest(str.getBytes("UTF-8"))).toLong
- }
-}
-
/**
* This class is responsible for translating the EventSourcing.Event to and from the protobuf.Event
*
@@ -93,7 +70,7 @@ class ProcessInstanceSerialization[P : Identifiable, T : Identifiable, S, E](pro
case (placeId, tokens) ⇒ tokens.toSeq.map {
case (value, count) ⇒ ProducedToken(
placeId = Some(placeId),
- tokenId = Some(tokenIdentifier(value)),
+ tokenId = Some(TokenIdentifier(value)),
count = Some(count),
tokenData = serializeObject(value)
)
@@ -106,7 +83,7 @@ class ProcessInstanceSerialization[P : Identifiable, T : Identifiable, S, E](pro
case (placeId, tokens) ⇒ tokens.toSeq.map {
case (value, count) ⇒ protobuf.ConsumedToken(
placeId = Some(placeId),
- tokenId = Some(tokenIdentifier(value)),
+ tokenId = Some(TokenIdentifier(value)),
count = Some(count)
)
}
@@ -117,8 +94,8 @@ class ProcessInstanceSerialization[P : Identifiable, T : Identifiable, S, E](pro
case (accumulated, protobuf.ConsumedToken(Some(placeId), Some(tokenId), Some(count))) ⇒
val place = instance.petriNet.places.getById(placeId, "place in the petrinet")
val keySet = instance.marking(place).keySet
- val value = keySet.find(e ⇒ tokenIdentifier(e) == tokenId).getOrElse(
- throw new IllegalStateException(s"Missing token with id $tokenId, keySet = ${keySet.map(tokenIdentifier)}")
+ val value = keySet.find(e ⇒ TokenIdentifier(e) == tokenId).getOrElse(
+ throw new IllegalStateException(s"Missing token with id $tokenId, keySet = ${keySet.map(TokenIdentifier(_))}")
)
accumulated.add(placeId, value, count)
case _ ⇒ throw new IllegalStateException("Missing data in persisted ConsumedToken")
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/recipe_manager/RecipeManager.scala b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/recipe_manager/RecipeManager.scala
index da55a4ca8..b094687e2 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/recipe_manager/RecipeManager.scala
+++ b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/recipe_manager/RecipeManager.scala
@@ -5,7 +5,7 @@ import akka.persistence.PersistentActor
import com.ing.baker.il.CompiledRecipe
import com.ing.baker.runtime.akka.actor.recipe_manager.RecipeManager._
import com.ing.baker.runtime.akka.actor.recipe_manager.RecipeManagerProtocol._
-import com.ing.baker.runtime.akka.actor.serialization.BakerSerializable
+import com.ing.baker.runtime.serialization.BakerSerializable
import scala.collection.mutable
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/recipe_manager/RecipeManagerProto.scala b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/recipe_manager/RecipeManagerProto.scala
index 8ae106721..a5137d3d9 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/recipe_manager/RecipeManagerProto.scala
+++ b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/recipe_manager/RecipeManagerProto.scala
@@ -5,9 +5,9 @@ import cats.instances.try_._
import cats.syntax.traverse._
import com.ing.baker.runtime.akka.actor.recipe_manager.RecipeManager.RecipeAdded
import com.ing.baker.runtime.akka.actor.recipe_manager.RecipeManagerProtocol._
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap.{versioned, ctxFromProto, ctxToProto}
-import com.ing.baker.runtime.akka.actor.serialization.SerializersProvider
+import com.ing.baker.runtime.serialization.ProtoMap.{ctxFromProto, ctxToProto, versioned}
+import com.ing.baker.runtime.serialization.SerializersProvider
+import com.ing.baker.runtime.serialization.{ProtoMap, SerializersProvider}
import scala.util.Try
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/recipe_manager/RecipeManagerProtocol.scala b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/recipe_manager/RecipeManagerProtocol.scala
index f64fdfb73..0d84f1c65 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/recipe_manager/RecipeManagerProtocol.scala
+++ b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/recipe_manager/RecipeManagerProtocol.scala
@@ -1,7 +1,7 @@
package com.ing.baker.runtime.akka.actor.recipe_manager
import com.ing.baker.il.CompiledRecipe
-import com.ing.baker.runtime.akka.actor.serialization.BakerSerializable
+import com.ing.baker.runtime.serialization.BakerSerializable
sealed trait RecipeManagerProtocol extends BakerSerializable
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/BakerSerializable.scala b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/BakerSerializable.scala
deleted file mode 100644
index 1408c9119..000000000
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/BakerSerializable.scala
+++ /dev/null
@@ -1,3 +0,0 @@
-package com.ing.baker.runtime.akka.actor.serialization
-
-trait BakerSerializable
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/BakerTypedProtobufSerializer.scala b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/BakerTypedProtobufSerializer.scala
index ebbc293bd..abb8955d4 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/BakerTypedProtobufSerializer.scala
+++ b/runtime/src/main/scala/com/ing/baker/runtime/akka/actor/serialization/BakerTypedProtobufSerializer.scala
@@ -1,40 +1,42 @@
package com.ing.baker.runtime.akka.actor.serialization
import akka.actor.ExtendedActorSystem
-import akka.serialization.SerializerWithStringManifest
+import com.ing.baker.il
import com.ing.baker.runtime.akka.actor.ClusterBakerActorProvider
import com.ing.baker.runtime.akka.actor.process_index.ProcessIndexProto._
-import com.ing.baker.runtime.akka.actor.process_index.{ ProcessIndex, ProcessIndexProtocol }
+import com.ing.baker.runtime.akka.actor.process_index.{ProcessIndex, ProcessIndexProtocol}
import com.ing.baker.runtime.akka.actor.process_instance.ProcessInstanceProto._
import com.ing.baker.runtime.akka.actor.process_instance.ProcessInstanceProtocol
import com.ing.baker.runtime.akka.actor.recipe_manager.RecipeManagerProto._
-import com.ing.baker.runtime.akka.actor.recipe_manager.{ RecipeManager, RecipeManagerProtocol }
-import com.ing.baker.runtime.akka.actor.serialization.BakerTypedProtobufSerializer.BinarySerializable
-import com.ing.baker.{ il, runtime }
-import com.typesafe.scalalogging.LazyLogging
-import scala.reflect.ClassTag
-import scala.util.Try
+import com.ing.baker.runtime.akka.actor.recipe_manager.{RecipeManager, RecipeManagerProtocol}
+import com.ing.baker.runtime.scaladsl.{EventInstance, RecipeEventMetadata, RecipeInstanceState}
+import com.ing.baker.runtime.serialization.TypedProtobufSerializer.{BinarySerializable, forType}
+import com.ing.baker.runtime.serialization.{ProtoMap, SerializersProvider, TypedProtobufSerializer}
object BakerTypedProtobufSerializer {
+ def entries(ev0: SerializersProvider): List[BinarySerializable] = {
+ implicit val ev = ev0
+ commonEntries ++ processIndexEntries ++ processInstanceEntries ++ recipeManagerEntries
+ }
+
/** Hardcoded serializerId for this serializer. This should not conflict with other serializers.
* Values from 0 to 40 are reserved for Akka internal usage.
*/
val identifier = 101
- def entries(implicit ev0: SerializersProvider): List[BinarySerializable] =
- commonEntries ++ processIndexEntries ++ processInstanceEntries ++ recipeManagerEntries
-
def commonEntries(implicit ev0: SerializersProvider): List[BinarySerializable] =
List(
forType[com.ing.baker.types.Value]
.register("baker.types.Value"),
forType[com.ing.baker.types.Type]
.register("baker.types.Type"),
- forType[runtime.scaladsl.EventInstance]
+ forType[EventInstance]
.register("core.RuntimeEvent"),
- forType[runtime.scaladsl.RecipeInstanceState]
+ forType[RecipeInstanceState]
.register("core.ProcessState"),
+ forType[RecipeEventMetadata]
+ .register("core.RecipeEventMetadata"),
forType[il.CompiledRecipe]
.register("il.CompiledRecipe")
)
@@ -127,12 +129,12 @@ object BakerTypedProtobufSerializer {
.register("ProcessInstanceProtocol.TransitionFailed"),
forType[ProcessInstanceProtocol.TransitionFired]
.register("ProcessInstanceProtocol.TransitionFired"),
- forType[runtime.akka.actor.process_instance.protobuf.TransitionFired]
- .register("TransitionFired")(ProtoMap.identityProtoMap(runtime.akka.actor.process_instance.protobuf.TransitionFired)),
- forType[runtime.akka.actor.process_instance.protobuf.TransitionFailed]
- .register("TransitionFailed")(ProtoMap.identityProtoMap(runtime.akka.actor.process_instance.protobuf.TransitionFailed)),
- forType[runtime.akka.actor.process_instance.protobuf.Initialized]
- .register("Initialized")(ProtoMap.identityProtoMap(runtime.akka.actor.process_instance.protobuf.Initialized))
+ forType[com.ing.baker.runtime.akka.actor.process_instance.protobuf.TransitionFired]
+ .register("TransitionFired")(ProtoMap.identityProtoMap(com.ing.baker.runtime.akka.actor.process_instance.protobuf.TransitionFired)),
+ forType[com.ing.baker.runtime.akka.actor.process_instance.protobuf.TransitionFailed]
+ .register("TransitionFailed")(ProtoMap.identityProtoMap(com.ing.baker.runtime.akka.actor.process_instance.protobuf.TransitionFailed)),
+ forType[com.ing.baker.runtime.akka.actor.process_instance.protobuf.Initialized]
+ .register("Initialized")(ProtoMap.identityProtoMap(com.ing.baker.runtime.akka.actor.process_instance.protobuf.Initialized))
)
def recipeManagerEntries(implicit ev0: SerializersProvider): List[BinarySerializable] =
@@ -154,90 +156,6 @@ object BakerTypedProtobufSerializer {
forType[RecipeManager.RecipeAdded]
.register("RecipeManager.RecipeAdded")
)
-
- def forType[A <: AnyRef](implicit tag: ClassTag[A]): RegisterFor[A] = new RegisterFor[A](tag)
-
- class RegisterFor[A <: AnyRef](classTag: ClassTag[A]) {
-
- def register[P <: scalapb.GeneratedMessage with scalapb.Message[P]](implicit protoMap: ProtoMap[A, P]): BinarySerializable =
- register[P](None)
-
- def register[P <: scalapb.GeneratedMessage with scalapb.Message[P]](overrideName: String)(implicit protoMap: ProtoMap[A, P]): BinarySerializable =
- register[P](Some(overrideName))
-
- def register[P <: scalapb.GeneratedMessage with scalapb.Message[P]](overrideName: Option[String])(implicit protoMap: ProtoMap[A, P]): BinarySerializable = {
- new BinarySerializable {
-
- override type Type = A
-
- override val tag: Class[_] = classTag.runtimeClass
-
- override val manifest: String = overrideName.getOrElse(classTag.runtimeClass.getName)
-
- override def toBinary(a: Type): Array[Byte] = protoMap.toByteArray(a)
-
- override def fromBinary(binary: Array[Byte]): Try[Type] = protoMap.fromByteArray(binary)
- }
- }
- }
-
- trait BinarySerializable {
-
- type Type <: AnyRef
-
- val tag: Class[_]
-
- def manifest: String
-
- def toBinary(a: Type): Array[Byte]
-
- // The actor resolver is commented for future Akka Typed implementation
- def fromBinary(binary: Array[Byte] /*, resolver: ActorRefResolver*/): Try[Type]
-
- def isInstance(o: AnyRef): Boolean =
- tag.isInstance(o)
-
- def unsafeToBinary(a: AnyRef): Array[Byte] =
- toBinary(a.asInstanceOf[Type])
-
- // The actor resolver is commented for future Akka Typed implementation
- def fromBinaryAnyRef(binary: Array[Byte] /*, resolver: ActorRefResolver*/): Try[AnyRef] =
- fromBinary(binary)
-
- }
-
-}
-
-class BakerTypedProtobufSerializer(system: ExtendedActorSystem) extends SerializerWithStringManifest with LazyLogging {
-
- implicit def serializersProvider: SerializersProvider = SerializersProvider(system, system.provider)
-
- lazy val entriesMem: List[BinarySerializable] = BakerTypedProtobufSerializer.entries
-
- override def identifier: Int =
- BakerTypedProtobufSerializer.identifier
-
- override def manifest(o: AnyRef): String = {
- entriesMem
- .find(_.isInstance(o))
- .map(_.manifest)
- .getOrElse(throw new IllegalStateException(s"Unsupported object of type: ${o.getClass}"))
- }
-
- override def toBinary(o: AnyRef): Array[Byte] =
- entriesMem
- .find(_.isInstance(o))
- .map(_.unsafeToBinary(o))
- .getOrElse(throw new IllegalStateException(s"Unsupported object of type: ${o.getClass}"))
-
- override def fromBinary(bytes: Array[Byte], manifest: String): AnyRef =
- entriesMem
- .find(_.manifest == manifest)
- .map(_.fromBinaryAnyRef(bytes))
- .getOrElse(throw new IllegalStateException(s"Unsupported object with manifest $manifest"))
- .fold(
- {e => logger.error(s"Failed to deserialize bytes with manifest $manifest", e); throw e},
- identity
- )
}
+class BakerTypedProtobufSerializer(system: ExtendedActorSystem) extends TypedProtobufSerializer(system, BakerTypedProtobufSerializer.identifier, BakerTypedProtobufSerializer.entries)
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/internal/InteractionManager.scala b/runtime/src/main/scala/com/ing/baker/runtime/akka/internal/InteractionManager.scala
index 19a0c9a82..97b06ebc9 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/internal/InteractionManager.scala
+++ b/runtime/src/main/scala/com/ing/baker/runtime/akka/internal/InteractionManager.scala
@@ -2,10 +2,48 @@ package com.ing.baker.runtime.akka.internal
import java.util.concurrent.ConcurrentHashMap
+import akka.actor.ActorSystem
+import akka.pattern.ask
+import akka.util.Timeout
+import com.ing.baker.baas.protocol.ProtocolInteractionExecution
import com.ing.baker.il.petrinet.InteractionTransition
-import com.ing.baker.runtime.scaladsl.InteractionInstance
+import com.ing.baker.runtime.akka.actor.interaction_scheduling.QuestMandated.Start
+import com.ing.baker.runtime.akka.actor.interaction_scheduling.QuestMandated
+import com.ing.baker.runtime.scaladsl.{EventInstance, IngredientInstance, InteractionInstance}
import scala.compat.java8.FunctionConverters._
+import scala.concurrent.Future
+
+
+
+trait InteractionManager {
+ def hasImplementation(interaction: InteractionTransition): Boolean
+
+ def executeImplementation(interaction: InteractionTransition, input: Seq[IngredientInstance]): Future[Option[EventInstance]]
+
+ def addImplementation(interaction: InteractionInstance): Unit
+}
+
+class InteractionManagerDis(system: ActorSystem, postTimeout: Timeout, computationTimeout: Timeout) extends InteractionManager {
+
+ import system.dispatcher
+
+ override def executeImplementation(interaction: InteractionTransition, input: Seq[IngredientInstance]): Future[Option[EventInstance]] = {
+ val a = system.actorOf(QuestMandated(input, interaction.originalInteractionName, postTimeout, computationTimeout))
+ a.ask(Start)(Timeout.durationToTimeout(postTimeout.duration + computationTimeout.duration)).flatMap {
+ case ProtocolInteractionExecution.InstanceExecutedSuccessfully(result) => Future.successful(result)
+ case ProtocolInteractionExecution.InstanceExecutionFailed() => Future.failed(new RuntimeException("Remote execution of interaction failed"))
+ case ProtocolInteractionExecution.NoInstanceFound => executeImplementation(interaction, input)
+ case ProtocolInteractionExecution.InstanceExecutionTimedOut() => Future.failed(new RuntimeException("Execution of interaction timed out"))
+ case ProtocolInteractionExecution.InvalidExecution() => Future.failed(new RuntimeException("Execution of interaction failed because of invalid ingredient input"))
+ }
+ }
+
+ override def hasImplementation(interaction: InteractionTransition): Boolean = true
+
+ override def addImplementation(interaction: InteractionInstance): Unit =
+ throw new NotImplementedError("addImplementation is not implemented for the distributed interaction manager, please deploy interactions using the baas-node-interaction library")
+}
/**
* The InteractionManager is responsible for all implementation of interactions.
@@ -13,7 +51,7 @@ import scala.compat.java8.FunctionConverters._
*
* @param interactionImplementations All
*/
-class InteractionManager(private var interactionImplementations: Seq[InteractionInstance] = Seq.empty) {
+class InteractionManagerLocal(private var interactionImplementations: Seq[InteractionInstance] = Seq.empty) extends InteractionManager {
private val implementationCache: ConcurrentHashMap[InteractionTransition, InteractionInstance] =
new ConcurrentHashMap[InteractionTransition, InteractionInstance]
@@ -53,6 +91,16 @@ class InteractionManager(private var interactionImplementations: Seq[Interaction
* @param interaction The interaction to check
* @return An option containing the implementation if available
*/
- def getImplementation(interaction: InteractionTransition): Option[InteractionInstance] =
+ private[internal] def getImplementation(interaction: InteractionTransition): Option[InteractionInstance] =
Option(implementationCache.computeIfAbsent(interaction, (findInteractionImplementation _).asJava))
+
+ def hasImplementation(interaction: InteractionTransition): Boolean =
+ getImplementation(interaction).isDefined
+
+ override def executeImplementation(interaction: InteractionTransition, input: Seq[IngredientInstance]): Future[Option[EventInstance]] = {
+ this.getImplementation(interaction) match {
+ case Some(implementation) => implementation.run(input)
+ case None => Future.failed(new FatalInteractionException("No implementation available for interaction"))
+ }
+ }
}
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/internal/RecipeRuntime.scala b/runtime/src/main/scala/com/ing/baker/runtime/akka/internal/RecipeRuntime.scala
index 454f5c2c7..9e6f96aa5 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/internal/RecipeRuntime.scala
+++ b/runtime/src/main/scala/com/ing/baker/runtime/akka/internal/RecipeRuntime.scala
@@ -194,10 +194,6 @@ class RecipeRuntime(recipe: CompiledRecipe, interactionManager: InteractionManag
try {
- // obtain the interaction implementation
- val implementation = interactionManager.getImplementation(interaction).getOrElse {
- throw new FatalInteractionException("No implementation available for interaction")
- }
// create the interaction input
val input = createInteractionInput(interaction, processState)
@@ -208,7 +204,7 @@ class RecipeRuntime(recipe: CompiledRecipe, interactionManager: InteractionManag
eventStream.publish(InteractionStarted(timeStarted, recipe.name, recipe.recipeId, processState.recipeInstanceId, interaction.interactionName))
// executes the interaction and obtain the (optional) output event
- implementation.execute(input).map { interactionOutput =>
+ interactionManager.executeImplementation(interaction, input).map { interactionOutput =>
// validates the event, throws a FatalInteraction exception if invalid
RecipeRuntime.validateInteractionOutput(interaction, interactionOutput).foreach { validationError =>
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/akka/package.scala b/runtime/src/main/scala/com/ing/baker/runtime/akka/package.scala
index b0aa8889e..0a34163b6 100644
--- a/runtime/src/main/scala/com/ing/baker/runtime/akka/package.scala
+++ b/runtime/src/main/scala/com/ing/baker/runtime/akka/package.scala
@@ -31,29 +31,6 @@ package object akka {
def toScala: FiniteDuration = FiniteDuration(duration.toMillis, TimeUnit.MILLISECONDS)
}
- /**
- * Mockito breaks reflection when mocking classes, for example:
- *
- * interface A { }
- * class B extends A
- * val b = mock[B]
- *
- * When inspecting b, the fact that it extends from A can no longer be reflected.
- *
- * Here we obtain the original class that was mocked.
- *
- * @param clazz The (potentially mocked) class
- * @return The original class
- */
- def unmock(clazz: Class[_]) = {
-
- if (clazz.getName.contains("$$EnhancerByMockitoWithCGLIB$$")) {
- val originalName: String = clazz.getName.split("\\$\\$EnhancerByMockitoWithCGLIB\\$\\$")(0)
- clazz.getClassLoader.loadClass(originalName)
- } else
- clazz
- }
-
def namedCachedThreadPool(threadNamePrefix: String): ExecutionContext =
ExecutionContext.fromExecutorService(Executors.newCachedThreadPool(daemonThreadFactory(threadNamePrefix)))
diff --git a/runtime/src/main/scala/com/ing/baker/runtime/common/BakerException.scala b/runtime/src/main/scala/com/ing/baker/runtime/common/BakerException.scala
deleted file mode 100644
index 9a582d105..000000000
--- a/runtime/src/main/scala/com/ing/baker/runtime/common/BakerException.scala
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.ing.baker.runtime.common
-
-sealed abstract class BakerException(message: String = "An exception occurred at Baker", cause: Throwable = null)
- extends RuntimeException(message, cause)
-
-object BakerException {
-
- class NoSuchProcessException(message: String) extends BakerException(message)
-
- class ProcessDeletedException(message: String) extends BakerException(message)
-
- class RecipeValidationException(message: String) extends BakerException(message)
-
- class ImplementationsException(message: String) extends BakerException(message)
-}
diff --git a/runtime/src/test/java/com/ing/baker/BakerTest.java b/runtime/src/test/java/com/ing/baker/BakerTest.java
index eb69bafeb..d6eea421d 100644
--- a/runtime/src/test/java/com/ing/baker/BakerTest.java
+++ b/runtime/src/test/java/com/ing/baker/BakerTest.java
@@ -5,6 +5,7 @@
import com.ing.baker.compiler.JavaCompiledRecipeTest;
import com.ing.baker.compiler.RecipeCompiler;
import com.ing.baker.il.CompiledRecipe;
+import com.ing.baker.runtime.akka.AkkaBaker;
import com.ing.baker.runtime.common.BakerException;
import com.ing.baker.runtime.common.SensoryEventStatus;
import com.ing.baker.runtime.javadsl.*;
@@ -56,7 +57,7 @@ public void shouldSetupJBakerWithDefaultActorFramework() throws BakerException,
CompiledRecipe compiledRecipe = RecipeCompiler.compileRecipe(JavaCompiledRecipeTest.setupSimpleRecipe());
String recipeInstanceId = UUID.randomUUID().toString();
- Baker jBaker = Baker.akka(config, actorSystem);
+ Baker jBaker = AkkaBaker.java(config, actorSystem);
java.util.Map ingredients = jBaker.addInteractionInstances(implementationsList)
.thenCompose(x -> jBaker.addRecipe(compiledRecipe))
.thenCompose(recipeId -> {
@@ -80,7 +81,7 @@ public void shouldSetupJBakerWithGivenActorFramework() throws BakerException, Ex
assertEquals(compiledRecipe.getValidationErrors().size(), 0);
- Baker jBaker = Baker.akka(config, actorSystem);
+ Baker jBaker = AkkaBaker.java(config, actorSystem);
jBaker.addInteractionInstances(implementationsList);
String recipeId = jBaker.addRecipe(compiledRecipe).get();
@@ -100,7 +101,7 @@ public void shouldFailWhenMissingImplementations() throws BakerException, Execut
exception.expect(ExecutionException.class);
CompiledRecipe compiledRecipe = RecipeCompiler.compileRecipe(JavaCompiledRecipeTest.setupComplexRecipe());
- Baker jBaker = Baker.akka(config, actorSystem);
+ Baker jBaker = AkkaBaker.java(config, actorSystem);
jBaker.addRecipe(compiledRecipe).get();
}
@@ -108,7 +109,7 @@ public void shouldFailWhenMissingImplementations() throws BakerException, Execut
@Test
public void shouldExecuteCompleteFlow() throws BakerException, ExecutionException, InterruptedException {
- Baker jBaker = Baker.akka(config, actorSystem);
+ Baker jBaker = AkkaBaker.java(config, actorSystem);
List bakerEvents = new LinkedList<>();
jBaker.registerBakerEventListener(bakerEvents::add);
diff --git a/runtime/src/test/java/com/ing/baker/Webshop.java b/runtime/src/test/java/com/ing/baker/Webshop.java
index f67198caa..9ac3b2e70 100644
--- a/runtime/src/test/java/com/ing/baker/Webshop.java
+++ b/runtime/src/test/java/com/ing/baker/Webshop.java
@@ -10,6 +10,7 @@
import com.ing.baker.recipe.javadsl.Interaction;
import com.ing.baker.recipe.javadsl.InteractionFailureStrategy;
import com.ing.baker.recipe.javadsl.Recipe;
+import com.ing.baker.runtime.akka.AkkaBaker;
import com.ing.baker.runtime.javadsl.Baker;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
@@ -151,7 +152,7 @@ public void testWebshop() throws ExecutionException, InterruptedException {
when(validateOrderMock.apply(any(), any())).thenReturn(new ValidateOrder.Valid());
ActorSystem system = ActorSystem.create("webshop");
- Baker baker = Baker.akka(config, system);
+ Baker baker = AkkaBaker.java(config, system);
baker.addInteractionInstances(ImmutableList.of(shipGoodsMock, sendInvoiceMock, manufactureGoodsMock, validateOrderMock));
diff --git a/runtime/src/test/resources/application.conf b/runtime/src/test/resources/application.conf
index e2f6863b6..57233a150 100644
--- a/runtime/src/test/resources/application.conf
+++ b/runtime/src/test/resources/application.conf
@@ -27,6 +27,8 @@ akka {
logging-filter = "akka.event.slf4j.Slf4jLoggingFilter"
}
+baker.interaction-manager = local
+
inmemory-read-journal {
write-plugin = "inmemory-journal"
offset-mode = "sequence"
diff --git a/runtime/src/test/scala/com/ing/baker/BakerRuntimeTestBase.scala b/runtime/src/test/scala/com/ing/baker/BakerRuntimeTestBase.scala
index 0d42c5459..b219438df 100644
--- a/runtime/src/test/scala/com/ing/baker/BakerRuntimeTestBase.scala
+++ b/runtime/src/test/scala/com/ing/baker/BakerRuntimeTestBase.scala
@@ -12,11 +12,20 @@ import com.ing.baker.recipe.{CaseClassIngredient, common}
import com.ing.baker.runtime.scaladsl.{Baker, EventInstance, InteractionInstance}
import com.ing.baker.types.{Converters, Value}
import com.typesafe.config.{Config, ConfigFactory}
+import java.nio.file.Paths
+import java.util.UUID
+
+import com.ing.baker.recipe.common.Recipe
+import com.ing.baker.runtime.akka.AkkaBaker
+import com.ing.baker.recipe.TestRecipe.{fireTwoEventsInteraction, _}
+import com.ing.baker.recipe.{CaseClassIngredient, common}
+import com.ing.baker.runtime.scaladsl.{Baker, EventInstance, InteractionInstance}
+import com.ing.baker.types.{Converters, Value}
+import com.typesafe.config.{Config, ConfigFactory}
import org.mockito.Matchers._
import org.mockito.Mockito._
import org.scalatest._
import org.scalatestplus.mockito.MockitoSugar
-
import scala.concurrent.Future
import scala.concurrent.duration._
import scala.language.postfixOps
@@ -204,9 +213,9 @@ trait BakerRuntimeTestBase
setupBakerWithRecipe(recipe, mockImplementations)(actorSystem)
}
- protected def setupBakerWithRecipe(recipe: common.Recipe, implementations: Seq[InteractionInstance])
+ protected def setupBakerWithRecipe(recipe: Recipe, implementations: Seq[InteractionInstance])
(implicit actorSystem: ActorSystem): Future[(Baker, String)] = {
- val baker = Baker.akka(ConfigFactory.load(), actorSystem)
+ val baker = AkkaBaker(ConfigFactory.load(), actorSystem)
baker.addInteractionInstances(implementations).flatMap { _ =>
baker.addRecipe(RecipeCompiler.compileRecipe(recipe)).map(baker -> _)(actorSystem.dispatcher)
}
@@ -214,7 +223,7 @@ trait BakerRuntimeTestBase
protected def setupBakerWithNoRecipe()(implicit actorSystem: ActorSystem): Future[Baker] = {
setupMockResponse()
- val baker = Baker.akka(ConfigFactory.load(), actorSystem)
+ val baker = AkkaBaker(ConfigFactory.load(), actorSystem)
baker.addInteractionInstances(mockImplementations).map { _ => baker }
}
diff --git a/runtime/src/test/scala/com/ing/baker/runtime/ExamplesSpec.scala b/runtime/src/test/scala/com/ing/baker/runtime/ExamplesSpec.scala
index 060d995c3..8b3e90e51 100644
--- a/runtime/src/test/scala/com/ing/baker/runtime/ExamplesSpec.scala
+++ b/runtime/src/test/scala/com/ing/baker/runtime/ExamplesSpec.scala
@@ -7,6 +7,9 @@ import com.ing.baker.runtime.ScalaDSLRuntime._
import com.ing.baker.runtime.scaladsl.Baker
import com.typesafe.config.ConfigFactory
import java.util.UUID
+
+import com.ing.baker.runtime.akka.AkkaBaker
+
import scala.concurrent.Future
class ExamplesSpec extends BakerRuntimeTestBase {
@@ -63,7 +66,7 @@ class ExamplesSpec extends BakerRuntimeTestBase {
val implementations =
Seq(validateOrderImpl, manufactureGoodsImpl, sendInvoiceImpl, shipGoodsImpl)
- val baker = Baker.akka(ConfigFactory.load(), defaultActorSystem)
+ val baker = AkkaBaker(ConfigFactory.load(), defaultActorSystem)
for {
_ <- Future.traverse(implementations)(baker.addInteractionInstance)
diff --git a/runtime/src/test/scala/com/ing/baker/runtime/akka/BakerExecutionSpec.scala b/runtime/src/test/scala/com/ing/baker/runtime/akka/BakerExecutionSpec.scala
index 9fd1c1187..9f0b33271 100644
--- a/runtime/src/test/scala/com/ing/baker/runtime/akka/BakerExecutionSpec.scala
+++ b/runtime/src/test/scala/com/ing/baker/runtime/akka/BakerExecutionSpec.scala
@@ -16,9 +16,9 @@ import com.ing.baker.recipe.common.InteractionFailureStrategy.FireEventAfterFail
import com.ing.baker.recipe.scaladsl.{Event, Ingredient, Interaction, Recipe}
import com.ing.baker.runtime.common.BakerException._
import com.ing.baker.runtime.common._
-import com.ing.baker.runtime.scaladsl.{Baker, EventInstance, InteractionInstance}
+import com.ing.baker.runtime.scaladsl.{Baker, EventInstance, InteractionInstance, RecipeEventMetadata}
import com.ing.baker.types.{CharArray, Int32, PrimitiveValue}
-import com.typesafe.config.ConfigFactory
+import com.typesafe.config.{Config, ConfigFactory}
import org.mockito.Matchers.{eq => mockitoEq, _}
import org.mockito.Mockito._
import org.mockito.invocation.InvocationOnMock
@@ -70,7 +70,7 @@ class BakerExecutionSpec extends BakerRuntimeTestBase {
for {
exception <- Future.successful {
intercept[IllegalArgumentException] {
- Baker.akka(config, setupActorSystem)
+ AkkaBaker(config, setupActorSystem)
}
}
_ <- setupActorSystem.terminate()
@@ -92,7 +92,7 @@ class BakerExecutionSpec extends BakerRuntimeTestBase {
val setupActorSystem = ActorSystem("setup-actor-system", config)
for {
exception <- Future.successful {
- intercept[MalformedURLException](Baker.akka(config, setupActorSystem))
+ intercept[MalformedURLException](AkkaBaker(config, setupActorSystem))
}
_ <- setupActorSystem.terminate()
} yield assert(exception.getMessage contains "wrong-address")
@@ -111,7 +111,7 @@ class BakerExecutionSpec extends BakerRuntimeTestBase {
val setupActorSystem = ActorSystem("setup-actor-system", config)
for {
exception <- Future.successful {
- intercept[IllegalArgumentException](Baker.akka(config, setupActorSystem))
+ intercept[IllegalArgumentException](AkkaBaker(config, setupActorSystem))
}
_ <- setupActorSystem.terminate()
} yield assert(exception.getMessage contains "No default service discovery implementation configured in `akka.discovery.method`")
@@ -128,12 +128,12 @@ class BakerExecutionSpec extends BakerRuntimeTestBase {
} yield succeed
}
- "throw an IllegalArgumentException if baking a process with the same identifier twice" in {
+ "throw an ProcessAlreadyExistsException if baking a process with the same identifier twice" in {
for {
(baker, recipeId) <- setupBakerWithRecipe("DuplicateIdentifierRecipe")
id = UUID.randomUUID().toString
_ <- baker.bake(recipeId, id)
- _ <- recoverToSucceededIf[IllegalArgumentException] {
+ _ <- recoverToSucceededIf[ProcessAlreadyExistsException] {
baker.bake(recipeId, id)
}
} yield succeed
@@ -164,12 +164,12 @@ class BakerExecutionSpec extends BakerRuntimeTestBase {
}
}
- "throw a IllegalArgumentException if the event fired is not a valid sensory event" in {
+ "throw a IllegalEventException if the event fired is not a valid sensory event" in {
for {
(baker, recipeId) <- setupBakerWithRecipe("NonExistingProcessEventTest")
recipeInstanceId = UUID.randomUUID().toString
_ <- baker.bake(recipeId, recipeInstanceId)
- intercepted <- recoverToExceptionIf[IllegalArgumentException] {
+ intercepted <- recoverToExceptionIf[IllegalEventException] {
baker.fireEventAndResolveWhenCompleted(recipeInstanceId, EventInstance.unsafeFrom(SomeNotDefinedEvent("bla")))
}
_ = intercepted.getMessage should startWith("No event with name 'SomeNotDefinedEvent' found in recipe 'NonExistingProcessEventTest")
@@ -197,7 +197,55 @@ class BakerExecutionSpec extends BakerRuntimeTestBase {
"interactionOneOriginalIngredient" -> interactionOneIngredientValue)
}
- "correctly notify on event" in {
+ "execute an interaction when its ingredient is provided in cluster" in {
+ val recipe =
+ Recipe("IngredientProvidedRecipeCluster")
+ .withInteraction(interactionOne)
+ .withSensoryEvent(initialEvent)
+
+
+ val config: Config = ConfigFactory.parseString(
+ """
+ |include "baker.conf"
+ |
+ |akka {
+ | actor {
+ | provider = "cluster"
+ | }
+ | remote {
+ | log-remote-lifecycle-events = off
+ | netty.tcp {
+ | hostname = "127.0.0.1"
+ | port = 2555
+ | }
+ | }
+ |
+ | cluster {
+ | seed-nodes = ["akka.tcp://remoteTest@127.0.0.1:2555"]
+ | auto-down-unreachable-after = 10s
+ | }
+ |}
+ """.stripMargin).withFallback(ConfigFactory.load())
+
+ val baker = AkkaBaker(config, ActorSystem.apply("remoteTest", config))
+
+ for {
+ _ <- baker.addInteractionInstances(mockImplementations)
+ recipeId <- baker.addRecipe(RecipeCompiler.compileRecipe(recipe))
+ _ = when(testInteractionOneMock.apply(anyString(), anyString())).thenReturn(Future.successful(InteractionOneSuccessful(interactionOneIngredientValue)))
+ recipeInstanceId = UUID.randomUUID().toString
+ _ <- baker.bake(recipeId, recipeInstanceId)
+ _ <- baker.fireEventAndResolveWhenCompleted(recipeInstanceId, EventInstance.unsafeFrom(EventInstance.unsafeFrom(InitialEvent(initialIngredientValue))))
+ _ = verify(testInteractionOneMock).apply(recipeInstanceId.toString, "initialIngredient")
+ state <- baker.getRecipeInstanceState(recipeInstanceId)
+ } yield
+ state.ingredients shouldBe
+ ingredientMap(
+ "initialIngredient" -> initialIngredientValue,
+ "interactionOneOriginalIngredient" -> interactionOneIngredientValue)
+ }
+
+ "Correctly notify on event" in {
val sensoryEvent = Event(
name = "sensory-event",
@@ -511,7 +559,7 @@ class BakerExecutionSpec extends BakerRuntimeTestBase {
.withPredefinedIngredients(("missingJavaOptional", ingredientValue)))
.withSensoryEvent(initialEvent)
- val baker = Baker.akka(ConfigFactory.load(), defaultActorSystem)
+ val baker = AkkaBaker(ConfigFactory.load(), defaultActorSystem)
for {
_ <- baker.addInteractionInstances(mockImplementations)
@@ -550,7 +598,7 @@ class BakerExecutionSpec extends BakerRuntimeTestBase {
}
"notify a registered event listener of events" in {
- val listenerMock = mock[(String, EventInstance) => Unit]
+ val listenerMock = mock[(RecipeEventMetadata, EventInstance) => Unit]
when(testInteractionOneMock.apply(anyString(), anyString())).thenReturn(Future.successful(InteractionOneSuccessful(interactionOneIngredientValue)))
val recipe =
Recipe("EventListenerRecipe")
@@ -563,8 +611,8 @@ class BakerExecutionSpec extends BakerRuntimeTestBase {
recipeInstanceId = UUID.randomUUID().toString
_ <- baker.bake(recipeId, recipeInstanceId)
_ <- baker.fireEventAndResolveWhenCompleted(recipeInstanceId, EventInstance.unsafeFrom(InitialEvent(initialIngredientValue)))
- _ = verify(listenerMock).apply(mockitoEq(recipeInstanceId.toString), argThat(new RuntimeEventMatcher(EventInstance.unsafeFrom(InitialEvent(initialIngredientValue)))))
- _ = verify(listenerMock).apply(mockitoEq(recipeInstanceId.toString), argThat(new RuntimeEventMatcher(EventInstance.unsafeFrom(InteractionOneSuccessful(interactionOneIngredientValue)))))
+ _ = verify(listenerMock).apply(mockitoEq(RecipeEventMetadata(recipeId, recipe.name, recipeInstanceId.toString)), argThat(new RuntimeEventMatcher(EventInstance.unsafeFrom(InitialEvent(initialIngredientValue)))))
+ _ = verify(listenerMock).apply(mockitoEq(RecipeEventMetadata(recipeId, recipe.name, recipeInstanceId.toString)), argThat(new RuntimeEventMatcher(EventInstance.unsafeFrom(InteractionOneSuccessful(interactionOneIngredientValue)))))
} yield succeed
}
@@ -920,9 +968,6 @@ class BakerExecutionSpec extends BakerRuntimeTestBase {
_ <- baker.bake(recipeId, recipeInstanceId)
//Handle first event
_ <- baker.fireEventAndResolveWhenCompleted(recipeInstanceId, EventInstance.unsafeFrom(InitialEvent(initialIngredientValue)))
- _ <- Future {
- Thread.sleep(50)
- }
state <- baker.getRecipeInstanceState(recipeInstanceId)
} yield state.eventNames should contain(interactionOne.retryExhaustedEventName)
}
@@ -941,9 +986,6 @@ class BakerExecutionSpec extends BakerRuntimeTestBase {
_ <- baker.bake(recipeId, recipeInstanceId)
//Handle first event
_ <- baker.fireEventAndResolveWhenCompleted(recipeInstanceId, EventInstance.unsafeFrom(InitialEvent(initialIngredientValue)))
- _ <- Future {
- Thread.sleep(50)
- }
//Since the defaultEventExhaustedName is set the retryExhaustedEventName of interactionOne will be picked.
state <- baker.getRecipeInstanceState(recipeInstanceId)
} yield state.eventNames should not contain interactionOne.retryExhaustedEventName
@@ -960,7 +1002,7 @@ class BakerExecutionSpec extends BakerRuntimeTestBase {
for {
(baker, recipeId) <- setupBakerWithRecipe(recipe, mockImplementations)
- listenerMock = mock[(String, EventInstance) => Unit]
+ listenerMock = mock[(RecipeEventMetadata, EventInstance) => Unit]
_ <- baker.registerEventListener("ImmediateFailureEvent", listenerMock)
recipeInstanceId = UUID.randomUUID().toString
@@ -968,11 +1010,8 @@ class BakerExecutionSpec extends BakerRuntimeTestBase {
//Handle first event
_ <- baker.fireEventAndResolveWhenCompleted(recipeInstanceId, EventInstance.unsafeFrom(InitialEvent(initialIngredientValue)))
- _ <- Future {
- Thread.sleep(50)
- }
- _ = verify(listenerMock).apply(mockitoEq(recipeInstanceId.toString), argThat(new RuntimeEventMatcher(EventInstance.unsafeFrom(InitialEvent(initialIngredientValue)))))
- _ = verify(listenerMock).apply(mockitoEq(recipeInstanceId.toString), argThat(new RuntimeEventMatcher(EventInstance(interactionOne.retryExhaustedEventName, Map.empty))))
+ _ = verify(listenerMock).apply(mockitoEq(RecipeEventMetadata(recipeId, recipe.name, recipeInstanceId.toString)), argThat(new RuntimeEventMatcher(EventInstance.unsafeFrom(InitialEvent(initialIngredientValue)))))
+ _ = verify(listenerMock).apply(mockitoEq(RecipeEventMetadata(recipeId, recipe.name, recipeInstanceId.toString)), argThat(new RuntimeEventMatcher(EventInstance(interactionOne.retryExhaustedEventName, Map.empty))))
state <- baker.getRecipeInstanceState(recipeInstanceId)
} yield state.eventNames should contain(interactionOne.retryExhaustedEventName)
@@ -1113,7 +1152,7 @@ class BakerExecutionSpec extends BakerRuntimeTestBase {
def second(recipeId: String) = {
val system2 = ActorSystem("persistenceTest2", localLevelDBConfig("persistenceTest2"))
- val baker2 = Baker.akka(ConfigFactory.load(), system2)
+ val baker2 = AkkaBaker(ConfigFactory.load(), system2)
(for {
_ <- baker2.addInteractionInstances(mockImplementations)
state <- baker2.getRecipeInstanceState(recipeInstanceId)
diff --git a/runtime/src/test/scala/com/ing/baker/runtime/akka/BakerSetupSpec.scala b/runtime/src/test/scala/com/ing/baker/runtime/akka/BakerSetupSpec.scala
index 83edec81d..9c26b1dd3 100644
--- a/runtime/src/test/scala/com/ing/baker/runtime/akka/BakerSetupSpec.scala
+++ b/runtime/src/test/scala/com/ing/baker/runtime/akka/BakerSetupSpec.scala
@@ -33,7 +33,7 @@ class BakerSetupSpec extends BakerRuntimeTestBase {
.withInteraction(interactionOne)
.withSensoryEvent(initialEvent))
- val baker = Baker.akka(ConfigFactory.load(), defaultActorSystem)
+ val baker = AkkaBaker(ConfigFactory.load(), defaultActorSystem)
for {
_ <- baker.addInteractionInstances(mockImplementations)
@@ -46,12 +46,12 @@ class BakerSetupSpec extends BakerRuntimeTestBase {
}
"providing implementations in a sequence" in {
- val baker = Baker.akka(ConfigFactory.load(), defaultActorSystem)
+ val baker = AkkaBaker(ConfigFactory.load(), defaultActorSystem)
baker.addInteractionInstances(mockImplementations).map(_ => succeed)
}
"providing an implementation with the class simplename same as the interaction" in {
- val baker = Baker.akka(ConfigFactory.load(), defaultActorSystem)
+ val baker = AkkaBaker(ConfigFactory.load(), defaultActorSystem)
baker.addInteractionInstance(InteractionInstance.unsafeFrom(new implementations.InteractionOne())).map(_ => succeed)
}
@@ -61,7 +61,7 @@ class BakerSetupSpec extends BakerRuntimeTestBase {
.withInteraction(interactionOne.withName("interactionOneRenamed"))
.withSensoryEvent(initialEvent)
- val baker = Baker.akka(ConfigFactory.load(), defaultActorSystem)
+ val baker = AkkaBaker(ConfigFactory.load(), defaultActorSystem)
for {
_ <- baker.addInteractionInstance(InteractionInstance.unsafeFrom(new implementations.InteractionOne()))
@@ -75,7 +75,7 @@ class BakerSetupSpec extends BakerRuntimeTestBase {
.withInteraction(interactionOne)
.withSensoryEvent(initialEvent)
- val baker = Baker.akka(ConfigFactory.load(), defaultActorSystem)
+ val baker = AkkaBaker(ConfigFactory.load(), defaultActorSystem)
for {
_ <- baker.addInteractionInstance(InteractionInstance.unsafeFrom(new InteractionOneFieldName()))
@@ -89,7 +89,7 @@ class BakerSetupSpec extends BakerRuntimeTestBase {
.withInteraction(interactionOne)
.withSensoryEvent(initialEvent)
- val baker = Baker.akka(ConfigFactory.load(), defaultActorSystem)
+ val baker = AkkaBaker(ConfigFactory.load(), defaultActorSystem)
for {
_ <- baker.addInteractionInstance(InteractionInstance.unsafeFrom(new InteractionOneInterfaceImplementation()))
@@ -102,7 +102,7 @@ class BakerSetupSpec extends BakerRuntimeTestBase {
.withInteraction(interactionWithAComplexIngredient)
.withSensoryEvent(initialEvent)
- val baker = Baker.akka(ConfigFactory.load(), defaultActorSystem)
+ val baker = AkkaBaker(ConfigFactory.load(), defaultActorSystem)
for {
_ <- baker.addInteractionInstance(InteractionInstance.unsafeFrom(mock[ComplexIngredientInteraction]))
@@ -118,7 +118,7 @@ class BakerSetupSpec extends BakerRuntimeTestBase {
.withInteraction(interactionOne)
.withSensoryEvent(secondEvent)
- val baker = Baker.akka(ConfigFactory.load(), defaultActorSystem)
+ val baker = AkkaBaker(ConfigFactory.load(), defaultActorSystem)
baker.addInteractionInstances(mockImplementations)
@@ -133,7 +133,7 @@ class BakerSetupSpec extends BakerRuntimeTestBase {
.withInteraction(interactionOne)
.withSensoryEvent(initialEvent)
- val baker = Baker.akka(ConfigFactory.load(), defaultActorSystem)
+ val baker = AkkaBaker(ConfigFactory.load(), defaultActorSystem)
recoverToExceptionIf[ImplementationsException] {
baker.addRecipe(RecipeCompiler.compileRecipe(recipe))
@@ -146,7 +146,7 @@ class BakerSetupSpec extends BakerRuntimeTestBase {
.withInteraction(interactionOne)
.withSensoryEvent(initialEvent)
- val baker = Baker.akka(ConfigFactory.load(), defaultActorSystem)
+ val baker = AkkaBaker(ConfigFactory.load(), defaultActorSystem)
baker.addInteractionInstance(InteractionInstance.unsafeFrom(new InteractionOneWrongApply()))
diff --git a/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/UtilSpec.scala b/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/UtilSpec.scala
index c25d890e7..314380ad3 100644
--- a/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/UtilSpec.scala
+++ b/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/UtilSpec.scala
@@ -18,7 +18,7 @@ class UtilSpec extends AkkaTestBase("UtilSpec") {
val futures = fastFutures :+ slowFuture
- val collected = Util.collectFuturesWithin(futures, 1 second, system.scheduler)
+ val collected = Util.collectFuturesWithin(futures, 1.second, system.scheduler)
val expectedResult = List.fill(5)(true)
diff --git a/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/process_index/ProcessIndexSpec.scala b/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/process_index/ProcessIndexSpec.scala
index 89d6f1396..4d6c258b2 100644
--- a/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/process_index/ProcessIndexSpec.scala
+++ b/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/process_index/ProcessIndexSpec.scala
@@ -14,15 +14,16 @@ import com.ing.baker.runtime.akka.actor.process_instance.ProcessInstanceProtocol
import com.ing.baker.runtime.akka.actor.process_instance.ProcessInstanceProtocol._
import com.ing.baker.runtime.akka.actor.recipe_manager.RecipeManagerProtocol
import com.ing.baker.runtime.akka.actor.recipe_manager.RecipeManagerProtocol.{AllRecipes, GetAllRecipes, RecipeInformation}
-import com.ing.baker.runtime.akka.actor.serialization.Encryption
-import com.ing.baker.runtime.akka.internal.InteractionManager
+import com.ing.baker.runtime.akka.internal.InteractionManagerLocal
import com.ing.baker.runtime.scaladsl.{EventInstance, RecipeInstanceState}
+import com.ing.baker.runtime.serialization.Encryption
import com.ing.baker.types
import com.ing.baker.types.Value
import com.typesafe.config.{Config, ConfigFactory}
import org.mockito.Mockito
import org.mockito.Mockito.when
import org.scalatest.concurrent.Eventually
+import org.scalatestplus.mockito.MockitoSugar
import org.scalatest.{BeforeAndAfter, BeforeAndAfterAll, Matchers, WordSpecLike}
import org.scalatestplus.mockito.MockitoSugar
import scalax.collection.immutable.Graph
@@ -102,7 +103,7 @@ class ProcessIndexSpec extends TestKit(ActorSystem("ProcessIndexSpec", ProcessIn
}
"delete a process if a retention period is defined, stop command is received" in {
- val recipeRetentionPeriod = 500 milliseconds
+ val recipeRetentionPeriod = 500.milliseconds
val processProbe = TestProbe()
val recipeManagerProbe = TestProbe()
val actorIndex = createActorIndex(processProbe.ref, recipeManagerProbe.ref)
@@ -118,7 +119,7 @@ class ProcessIndexSpec extends TestKit(ActorSystem("ProcessIndexSpec", ProcessIn
Thread.sleep(recipeRetentionPeriod.toMillis)
// inform the index to check for processes to be cleaned up
actorIndex ! CheckForProcessesToBeDeleted
- processProbe.expectMsg(15 seconds, Stop(delete = true))
+ processProbe.expectMsg(15.seconds, Stop(delete = true))
}
"Forward the FireTransition command when a valid HandleEvent is sent" in {
@@ -177,7 +178,7 @@ class ProcessIndexSpec extends TestKit(ActorSystem("ProcessIndexSpec", ProcessIn
"reply with an InvalidEvent rejection message when attempting to fire an event that is now know in the compiledRecipe" in {
- val receivePeriodTimeout = 500 milliseconds
+ val receivePeriodTimeout = 500.milliseconds
val petriNetActorProbe = TestProbe("petrinet-probe")
val recipeManagerProbe = TestProbe("recipe-manager-probe")
@@ -206,7 +207,7 @@ class ProcessIndexSpec extends TestKit(ActorSystem("ProcessIndexSpec", ProcessIn
"reply with an InvalidEvent rejection message when attempting to fire an event that does not comply to the recipe" in {
- val receivePeriodTimeout = 500 milliseconds
+ val receivePeriodTimeout = 500.milliseconds
val petriNetActorProbe = TestProbe("petrinet-probe")
val recipeManagerProbe = TestProbe("recipe-manager-probe")
@@ -283,7 +284,7 @@ class ProcessIndexSpec extends TestKit(ActorSystem("ProcessIndexSpec", ProcessIn
recipeInstanceIdleTimeout = None,
retentionCheckInterval = None,
configuredEncryption = Encryption.NoEncryption,
- interactionManager = new InteractionManager(),
+ interactionManager = new InteractionManagerLocal(),
recipeManager = recipeManager,
Seq.empty) {
override def createProcessActor(id: String, compiledRecipe: CompiledRecipe) = petriNetActorRef
diff --git a/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceEventSourcingSpec.scala b/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceEventSourcingSpec.scala
index 6bcecc828..20a83a3b8 100644
--- a/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceEventSourcingSpec.scala
+++ b/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceEventSourcingSpec.scala
@@ -1,6 +1,6 @@
package com.ing.baker.runtime.akka.actor.process_instance
-import akka.persistence.inmemory.extension.{ InMemoryJournalStorage, StorageExtension }
+import akka.persistence.inmemory.extension.{InMemoryJournalStorage, StorageExtension}
import akka.persistence.query.PersistenceQuery
import akka.persistence.query.scaladsl._
import akka.stream.ActorMaterializer
@@ -13,21 +13,23 @@ import com.ing.baker.runtime.akka.actor.process_instance.ProcessInstanceEventSou
import com.ing.baker.runtime.akka.actor.process_instance.ProcessInstanceProtocol._
import com.ing.baker.runtime.akka.actor.process_instance.ProcessInstanceSpec._
import com.ing.baker.runtime.akka.actor.process_instance.dsl._
-import com.ing.baker.runtime.akka.actor.serialization.Encryption.NoEncryption
import java.util.UUID
+
+import com.ing.baker.runtime.serialization.Encryption.NoEncryption
import org.scalatest.BeforeAndAfterEach
import org.scalatest.Matchers._
+
import scala.concurrent.ExecutionContext
import scala.concurrent.duration._
class ProcessInstanceEventSourcingSpec extends AkkaTestBase("ProcessQuerySpec") with BeforeAndAfterEach {
- implicit val akkaTimout = Timeout(2 seconds)
- val timeOut: Duration = akkaTimout.duration
+ private implicit val akkaTimout: Timeout = Timeout(2 seconds)
+ private val timeOut: Duration = akkaTimout.duration
- implicit def materializer = ActorMaterializer()
+ private implicit val materializer: ActorMaterializer = ActorMaterializer()
- implicit def ec: ExecutionContext = system.dispatcher
+ private implicit val ec: ExecutionContext = system.dispatcher
override protected def beforeEach(): Unit = {
// Clean the journal before each test
@@ -57,16 +59,16 @@ class ProcessInstanceEventSourcingSpec extends AkkaTestBase("ProcessQuerySpec")
instance ! Initialize(p1.markWithN(1), ())
expectMsg(Initialized(p1.markWithN(1), ()))
- expectMsgPF(timeOut) {case TransitionFired(_, 1, _, _, _, _, _) ⇒}
- expectMsgPF(timeOut) {case TransitionFired(_, 2, _, _, _, _, _) ⇒}
+ expectMsgPF(timeOut) { case TransitionFired(_, 1, _, _, _, _, _) ⇒ }
+ expectMsgPF(timeOut) { case TransitionFired(_, 2, _, _, _, _, _) ⇒ }
ProcessInstanceEventSourcing.eventsForInstance[Place, Transition, Unit, Unit](
- "test",
- recipeInstanceId,
- petriNet,
- NoEncryption,
- readJournal,
- t ⇒ eventSourceFunction)
+ processTypeName = "test",
+ recipeInstanceId = recipeInstanceId,
+ topology = petriNet,
+ encryption = NoEncryption,
+ readJournal = readJournal,
+ eventSourceFn = t ⇒ eventSourceFunction)
.map(_._2) // Get the event from the tuple
.runWith(TestSink.probe)
.request(3)
@@ -80,7 +82,6 @@ class ProcessInstanceEventSourcingSpec extends AkkaTestBase("ProcessQuerySpec")
consumed shouldBe p2.markWithN(1).marshall
produced shouldBe p3.markWithN(1).marshall
}
-
}
}
}
diff --git a/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceSpec.scala b/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceSpec.scala
index e34322908..4a62a7363 100644
--- a/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceSpec.scala
+++ b/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/process_instance/ProcessInstanceSpec.scala
@@ -18,7 +18,7 @@ import com.ing.baker.runtime.akka.actor.process_instance.ProcessInstanceSpec._
import com.ing.baker.runtime.akka.actor.process_instance.dsl._
import com.ing.baker.runtime.akka.actor.process_instance.internal.ExceptionStrategy.RetryWithDelay
import com.ing.baker.runtime.akka.actor.process_instance.{ProcessInstanceProtocol => protocol}
-import com.ing.baker.runtime.akka.actor.serialization.Encryption.NoEncryption
+import com.ing.baker.runtime.serialization.Encryption.NoEncryption
import com.ing.baker.runtime.akka.namedCachedThreadPool
import org.mockito.Matchers._
import org.mockito.Mockito._
diff --git a/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/recipe_manager/RecipeManagerProtoSpec.scala b/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/recipe_manager/RecipeManagerProtoSpec.scala
index 27b966abe..94f0c4a12 100644
--- a/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/recipe_manager/RecipeManagerProtoSpec.scala
+++ b/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/recipe_manager/RecipeManagerProtoSpec.scala
@@ -2,8 +2,8 @@ package com.ing.baker.runtime.akka.actor.recipe_manager
import com.ing.baker.BakerRuntimeTestBase
import com.ing.baker.runtime.akka.actor.recipe_manager.RecipeManager.RecipeAdded
-import com.ing.baker.runtime.akka.actor.serialization.{Encryption, SerializationSpec, SerializersProvider}
-
+import com.ing.baker.runtime.akka.actor.serialization.SerializationSpec
+import com.ing.baker.runtime.serialization.{Encryption, SerializersProvider}
import org.scalatest.TryValues._
class RecipeManagerProtoSpec extends BakerRuntimeTestBase {
diff --git a/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/serialization/EncryptionPropertiesSpec.scala b/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/serialization/EncryptionPropertiesSpec.scala
index ea7f9a34c..cc85ddaf5 100644
--- a/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/serialization/EncryptionPropertiesSpec.scala
+++ b/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/serialization/EncryptionPropertiesSpec.scala
@@ -4,7 +4,7 @@ import org.scalacheck.Gen._
import org.scalacheck.Prop.forAll
import org.scalacheck._
import org.scalatest.FunSuite
-import com.ing.baker.runtime.akka.actor.serialization.Encryption._
+import com.ing.baker.runtime.serialization.Encryption._
import org.scalatestplus.scalacheck.Checkers
class EncryptionPropertiesSpec extends FunSuite with Checkers {
diff --git a/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/serialization/SerializationSpec.scala b/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/serialization/SerializationSpec.scala
index c95e1a188..a41f94b7f 100644
--- a/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/serialization/SerializationSpec.scala
+++ b/runtime/src/test/scala/com/ing/baker/runtime/akka/actor/serialization/SerializationSpec.scala
@@ -17,10 +17,11 @@ import com.ing.baker.runtime.akka.actor.recipe_manager.RecipeManager.RecipeAdded
import com.ing.baker.runtime.akka.actor.recipe_manager.RecipeManagerProto._
import com.ing.baker.runtime.akka.actor.recipe_manager.RecipeManagerProtocol.GetRecipe
import com.ing.baker.runtime.akka.actor.recipe_manager.{RecipeManager, RecipeManagerProtocol}
-import com.ing.baker.runtime.akka.actor.serialization.Encryption.{AESEncryption, NoEncryption}
-import com.ing.baker.runtime.akka.actor.serialization.ProtoMap.{ctxFromProto, ctxToProto}
+import com.ing.baker.runtime.serialization.Encryption.{AESEncryption, NoEncryption}
+import com.ing.baker.runtime.serialization.ProtoMap.{ctxFromProto, ctxToProto}
import com.ing.baker.runtime.common.SensoryEventStatus
import com.ing.baker.runtime.scaladsl.{EventInstance, EventMoment, RecipeInstanceState, SensoryEventResult}
+import com.ing.baker.runtime.serialization.ProtoMap
import com.ing.baker.types.modules.PrimitiveModuleSpec._
import com.ing.baker.types.{Value, _}
import com.ing.baker.{AllTypeRecipe, types}
diff --git a/runtime/src/test/scala/com/ing/baker/runtime/akka/internal/InteractionManagerSpec.scala b/runtime/src/test/scala/com/ing/baker/runtime/akka/internal/InteractionManagerSpec.scala
index 4a1b274a1..7dbf1bfb9 100644
--- a/runtime/src/test/scala/com/ing/baker/runtime/akka/internal/InteractionManagerSpec.scala
+++ b/runtime/src/test/scala/com/ing/baker/runtime/akka/internal/InteractionManagerSpec.scala
@@ -9,7 +9,7 @@ import org.mockito.Mockito.when
import org.scalatest.{Matchers, WordSpecLike}
import org.scalatestplus.mockito.MockitoSugar
-class InteractionManagerSpec extends WordSpecLike with Matchers with MockitoSugar {
+class InteractionManagerLocalSpec extends WordSpecLike with Matchers with MockitoSugar {
"getImplementation" should {
"return Some" when {
"an interaction implementation is available" in {
@@ -17,7 +17,7 @@ class InteractionManagerSpec extends WordSpecLike with Matchers with MockitoSuga
when(interactionImplementation.name).thenReturn("InteractionName")
when(interactionImplementation.input).thenReturn(Seq(types.Int32))
- val interactionManager: InteractionManager = new InteractionManager(Seq(interactionImplementation))
+ val interactionManager: InteractionManagerLocal = new InteractionManagerLocal(Seq(interactionImplementation))
val interactionTransition = mock[InteractionTransition]
when(interactionTransition.originalInteractionName).thenReturn("InteractionName")
val ingredientDescriptor: IngredientDescriptor = IngredientDescriptor("ingredientName", types.Int32)
@@ -35,7 +35,7 @@ class InteractionManagerSpec extends WordSpecLike with Matchers with MockitoSuga
when(interactionImplementation2.name).thenReturn("InteractionName2")
when(interactionImplementation2.input).thenReturn(Seq(types.Int32))
- val interactionManager: InteractionManager = new InteractionManager(Seq(interactionImplementation1, interactionImplementation2))
+ val interactionManager: InteractionManagerLocal = new InteractionManagerLocal(Seq(interactionImplementation1, interactionImplementation2))
val interactionTransition = mock[InteractionTransition]
when(interactionTransition.originalInteractionName).thenReturn("InteractionName")
val ingredientDescriptor: IngredientDescriptor = IngredientDescriptor("ingredientName", types.Int32)
@@ -53,7 +53,7 @@ class InteractionManagerSpec extends WordSpecLike with Matchers with MockitoSuga
when(interactionImplementation2.name).thenReturn("InteractionName")
when(interactionImplementation2.input).thenReturn(Seq(types.Int32))
- val interactionManager: InteractionManager = new InteractionManager(Seq(interactionImplementation1, interactionImplementation2))
+ val interactionManager: InteractionManagerLocal = new InteractionManagerLocal(Seq(interactionImplementation1, interactionImplementation2))
val interactionTransition = mock[InteractionTransition]
when(interactionTransition.originalInteractionName).thenReturn("InteractionName")
val ingredientDescriptor: IngredientDescriptor = IngredientDescriptor("ingredientName", types.Int32)
@@ -69,7 +69,7 @@ class InteractionManagerSpec extends WordSpecLike with Matchers with MockitoSuga
when(interactionImplementation.name).thenReturn("InteractionName")
when(interactionImplementation.input).thenReturn(Seq(types.Int32))
- val interactionManager: InteractionManager = new InteractionManager(Seq(interactionImplementation))
+ val interactionManager: InteractionManagerLocal = new InteractionManagerLocal(Seq(interactionImplementation))
val interactionTransition = mock[InteractionTransition]
when(interactionTransition.originalInteractionName).thenReturn("WrongInteractionName")
val ingredientDescriptor: IngredientDescriptor = IngredientDescriptor("ingredientName", types.Int32)
@@ -83,7 +83,7 @@ class InteractionManagerSpec extends WordSpecLike with Matchers with MockitoSuga
when(interactionImplementation.name).thenReturn("InteractionName")
when(interactionImplementation.input).thenReturn(Seq(types.Int32))
- val interactionManager: InteractionManager = new InteractionManager(Seq(interactionImplementation))
+ val interactionManager: InteractionManagerLocal = new InteractionManagerLocal(Seq(interactionImplementation))
val interactionTransition = mock[InteractionTransition]
when(interactionTransition.originalInteractionName).thenReturn("InteractionName")
val ingredientDescriptor: IngredientDescriptor = IngredientDescriptor("ingredientName", types.CharArray)
@@ -97,7 +97,7 @@ class InteractionManagerSpec extends WordSpecLike with Matchers with MockitoSuga
when(interactionImplementation.name).thenReturn("InteractionName")
when(interactionImplementation.input).thenReturn(Seq(types.Int32, types.CharArray))
- val interactionManager: InteractionManager = new InteractionManager(Seq(interactionImplementation))
+ val interactionManager: InteractionManagerLocal = new InteractionManagerLocal(Seq(interactionImplementation))
val interactionTransition = mock[InteractionTransition]
when(interactionTransition.originalInteractionName).thenReturn("InteractionName")
val ingredientDescriptor: IngredientDescriptor = IngredientDescriptor("ingredientName", types.Int32)
@@ -111,7 +111,7 @@ class InteractionManagerSpec extends WordSpecLike with Matchers with MockitoSuga
when(interactionImplementation.name).thenReturn("InteractionName")
when(interactionImplementation.input).thenReturn(Seq(types.Int32))
- val interactionManager: InteractionManager = new InteractionManager(Seq(interactionImplementation))
+ val interactionManager: InteractionManagerLocal = new InteractionManagerLocal(Seq(interactionImplementation))
val interactionTransition = mock[InteractionTransition]
when(interactionTransition.originalInteractionName).thenReturn("InteractionName")
val ingredientDescriptor: IngredientDescriptor = IngredientDescriptor("ingredientName", types.Int32)
@@ -122,7 +122,7 @@ class InteractionManagerSpec extends WordSpecLike with Matchers with MockitoSuga
}
"empty interaction seq" in {
- val interactionManager: InteractionManager = new InteractionManager(Seq.empty)
+ val interactionManager: InteractionManagerLocal = new InteractionManagerLocal(Seq.empty)
val interactionTransition: InteractionTransition = mock[InteractionTransition]
interactionManager.getImplementation(interactionTransition) should equal(None)
diff --git a/split-brain-resolver/src/multi-jvm/scala/com/ing/baker/runtime/akka/actor/downing/SplitBrainResolverHickUpNodeSpec.scala b/split-brain-resolver/src/multi-jvm/scala/com/ing/baker/runtime/akka/actor/downing/SplitBrainResolverHickUpNodeSpec.scala
index f47642b21..0a08ae254 100644
--- a/split-brain-resolver/src/multi-jvm/scala/com/ing/baker/runtime/akka/actor/downing/SplitBrainResolverHickUpNodeSpec.scala
+++ b/split-brain-resolver/src/multi-jvm/scala/com/ing/baker/runtime/akka/actor/downing/SplitBrainResolverHickUpNodeSpec.scala
@@ -45,8 +45,8 @@ abstract class SplitBrainResolverHickUpNodeSpec(splitBrainResolverConfig: SplitB
enterBarrier("cluster-is-up")
runOn(nodeA) {
- scheduleReachable = Some(system.scheduler.schedule(0 seconds, 2 second, () => statusNodeE(reachable = true)))
- scheduleUnreachable = Some(system.scheduler.schedule(1 seconds, 2 second, () => statusNodeE(reachable = false)))
+ scheduleReachable = Some(system.scheduler.schedule(0.seconds, 2 second, () => statusNodeE(reachable = true)))
+ scheduleUnreachable = Some(system.scheduler.schedule(1.seconds, 2 second, () => statusNodeE(reachable = false)))
}
Thread.sleep(10 * 1000)
@@ -66,8 +66,8 @@ abstract class SplitBrainResolverHickUpNodeSpec(splitBrainResolverConfig: SplitB
runOn(nodeD) {
awaitAssert(
clusterView.isTerminated should be(true),
- 20 seconds,
- 1 second
+ 20.seconds,
+ 1.second
)
enterBarrier("fourth-node-down")
}
diff --git a/split-brain-resolver/src/multi-jvm/scala/com/ing/baker/runtime/akka/actor/downing/SplitBrainResolverNodeCrashSpec.scala b/split-brain-resolver/src/multi-jvm/scala/com/ing/baker/runtime/akka/actor/downing/SplitBrainResolverNodeCrashSpec.scala
index 27112790f..668f8c23a 100644
--- a/split-brain-resolver/src/multi-jvm/scala/com/ing/baker/runtime/akka/actor/downing/SplitBrainResolverNodeCrashSpec.scala
+++ b/split-brain-resolver/src/multi-jvm/scala/com/ing/baker/runtime/akka/actor/downing/SplitBrainResolverNodeCrashSpec.scala
@@ -102,7 +102,7 @@ abstract class SplitBrainResolverNodeCrashSpec(splitBrainResolverConfig: SplitBr
awaitAssert(
clusterView.isTerminated should be(true),
20 seconds,
- 1 second
+ 1.second
)
}
@@ -112,7 +112,7 @@ abstract class SplitBrainResolverNodeCrashSpec(splitBrainResolverConfig: SplitBr
awaitAssert(
clusterView.isTerminated should be(true),
20 seconds,
- 1 second
+ 1.second
)
}
diff --git a/split-brain-resolver/src/multi-jvm/scala/com/ing/baker/runtime/akka/actor/downing/SplitBrainResolverWithNetworkSplitSpec.scala b/split-brain-resolver/src/multi-jvm/scala/com/ing/baker/runtime/akka/actor/downing/SplitBrainResolverWithNetworkSplitSpec.scala
index b2aadca42..e4e0cbf00 100644
--- a/split-brain-resolver/src/multi-jvm/scala/com/ing/baker/runtime/akka/actor/downing/SplitBrainResolverWithNetworkSplitSpec.scala
+++ b/split-brain-resolver/src/multi-jvm/scala/com/ing/baker/runtime/akka/actor/downing/SplitBrainResolverWithNetworkSplitSpec.scala
@@ -49,7 +49,7 @@ abstract class SplitBrainResolverWithNetworkSplitSpec(splitBrainResolverConfig:
awaitAssert(
clusterView.isTerminated should be(true),
20 seconds,
- 1 second
+ 1.second
)
}
@@ -85,7 +85,7 @@ abstract class SplitBrainResolverWithNetworkSplitSpec(splitBrainResolverConfig:
awaitAssert(
clusterView.isTerminated should be(true),
20 seconds,
- 1 second
+ 1.second
)
}
@@ -124,7 +124,7 @@ abstract class SplitBrainResolverWithNetworkSplitSpec(splitBrainResolverConfig:
awaitAssert(
clusterView.isTerminated should be(true),
20 seconds,
- 1 second
+ 1.second
)
enterBarrier("unreachable-fourth-node")
}
@@ -158,7 +158,7 @@ abstract class SplitBrainResolverWithNetworkSplitSpec(splitBrainResolverConfig:
awaitAssert(
clusterView.isTerminated should be(true),
20 seconds,
- 1 second
+ 1.second
)
enterBarrier("split-between-remaining-nodes")
}