-
Notifications
You must be signed in to change notification settings - Fork 0
/
HelloDemo.scala
103 lines (90 loc) · 3.71 KB
/
HelloDemo.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package training.akka.funcvsoo
import akka.actor.typed.scaladsl.{AbstractBehavior, ActorContext, Behaviors}
import akka.actor.typed.{ActorRef, ActorSystem, Behavior, PostStop, Signal}
/**
* What is the recommended syntax to build an Akka typed actor?
* 1) Functional: HelloFrench.apply defines the Behavior[HelloMessage]
* calling directly the Behaviors.receive combinator
* 2) Object-Oriented style: HelloSpanish.apply setups
* a class extending AbstractBehavior[HelloMessage] which overrides def onMessage()
*
* ANSWER:
* Style guide "Functional versus object-oriented style"
* https://doc.akka.io/docs/akka/current/typed/style-guide.html#functional-versus-object-oriented-style
*/
object HelloDemo extends App {
val guardianActor = ActorSystem(HelloMain(), "userRootActor")
guardianActor ! HelloCommand(guestName = "AkkaMania", guardianActor)
}
sealed trait HelloMessage
/**
* Command the actor to say hello
* @param ackTo is needed to receive the acknowledgement event that the cmd has been executed
* this is a good practice to respond to a command and also to make
* unit testing possible (otherwise how can we know the actor has executed the cmd?)
*/
final case class HelloCommand(guestName: String, ackTo: ActorRef[HelloMessage]) extends HelloMessage
final case class HelloDone(confirmText: String, doneBy: ActorRef[HelloCommand]) extends HelloMessage
object HelloMain {
def apply(): Behavior[HelloMessage] =
Behaviors.receive{
case (context, message: HelloCommand) =>
context.log.info(s"HelloMain receives $message")
val frenchActor = context.spawn(FrenchReceptionist(), "HelloFrench")
val spanishActor = context.spawn(SpanishReceptionist(), "HelloSpanish")
frenchActor ! message
spanishActor ! message
Behaviors.stopped
case (context, message: HelloDone) =>
context.log.info(s"Good job ${message.doneBy.toString}")
Behaviors.same
}
}
/**
* Build an actor, using directly Behaviors factory methods
* This syntax is used in
* [Akka Quickstart with Scala](https://developer.lightbend.com/guides/akka-quickstart-scala/)
*/
object FrenchReceptionist {
def apply(): Behavior[HelloMessage] =
Behaviors.receive[HelloMessage]{
case (context, message: HelloCommand) =>
context.log.info(s"BONJOUR MADAME/MONSIEUR ${message.guestName}")
message.ackTo ! HelloDone(confirmText = s"Greeted ${message.guestName} in FRENCH", context.self)
Behaviors.stopped
case _ =>
Behaviors.same
}
.receiveSignal{
case (context, signal: PostStop) =>
context.log.info("'{}' actor stopped", this.getClass.getSimpleName)
Behaviors.same
}
}
/**
* Build an actor via a subclass of AbstractBehavior[T]
* This style is used in Akka Tutorial
* [The Akka actor hierarchy](https://doc.akka.io/docs/akka/current/typed/guide/tutorial_1.html#the-akka-actor-hierarchy)
*/
object SpanishReceptionist {
def apply(): Behavior[HelloMessage] =
Behaviors.setup(context => new SpanishReceptionist(context))
}
class SpanishReceptionist private(context: ActorContext[HelloMessage])
extends AbstractBehavior[HelloMessage](context) {
override def onMessage(message: HelloMessage): Behavior[HelloMessage] = {
message match {
case msg: HelloCommand =>
context.log.info(s"HOLA SEÑORA/SEÑOR ${msg.guestName}")
msg.ackTo ! HelloDone(confirmText = s"Greeted ${msg.guestName} in SPANISH", context.self)
Behaviors.stopped
case _ =>
Behaviors.same
}
}
override def onSignal: PartialFunction[Signal, Behavior[HelloMessage]] = {
case PostStop =>
context.log.info("'{}' actor stopped", this.getClass.getSimpleName)
this
}
}