How extend behaviour of super actor in akka - scala

I want to implement CRUD operation using akka actor. I am a new in akka so dont know the designing fundamentals of akka actors.
I want to share the behaviours of akka actors in multiple sub actors.
Fir example i want to save and delete student , teacher and other entity.
I have created actor for StudentDao.scala
class StudentDao extends Actor with ActorLogging{
override def Receive = {
case Add(student) =>
// Add to database
case Delete =>
//Delete from database
// Some other cases related to Student entity
}
}
case object StudentDao{
case class Add(user : Student)
case class Delete(id : String)
}
Same I have actor for TeacherDao.scala
class TeacherDao extends Actor with ActorLogging{
override def Receive = {
case Add(teacher) =>
// Add to database
case Delete =>
//Delete from database
// Some other cases related to teacher entity
}
}
object TeacherDao{
case class Add(user : teacher)
case class Delete(id : String)
}
I want to abstract delete method for both dao.
So i have create BaseDao.scala
class BaseDao extends Actor with ActorLogging{
override def Receive = {
case Delete =>
//Delete from database dao.delete
}
how can i abstract using base actor.

orElse is the way to extend actor behaviors, because an actor's Receive is simply an alias for PartialFunction[Any, Unit]. Below is a concrete illustration with your use case.
First, define the base behavior in a trait that must be mixed in with an actor. To avoid duplication, move the Delete case class into this trait's companion object.
trait BaseDao { this: Actor with ActorLogging =>
import BaseDao._
def baseBehavior: Receive = {
case Delete(id) =>
log.info(s"Deleting $id from db")
// delete from db
}
}
object BaseDao {
case class Delete(id: String)
}
Then, mix in the above trait into your other actors and chain the behaviors with orElse. Note that I created dummy Student and Teacher case classes so that this code would compile. StudentDao:
class StudentDao extends Actor with ActorLogging with BaseDao {
import StudentDao._
def studentBehavior: Receive = {
case Add(student) =>
log.info(s"Adding student: $student")
// some other cases related to Student
}
def receive = studentBehavior orElse baseBehavior
}
object StudentDao {
case class Add(user: Student)
}
case class Student(name: String)
And TeacherDao:
class TeacherDao extends Actor with ActorLogging with BaseDao {
import TeacherDao._
def teacherBehavior: Receive = {
case Add(teacher) =>
log.info(s"Adding teacher: $teacher")
// some other cases related to Teacher
}
def receive = teacherBehavior orElse baseBehavior
}
object TeacherDao {
case class Add(user: Teacher)
}
case class Teacher(name: String)

You can create a trait for the base actor, with a common receive function orElse another one that has to be implemented in sub actors:
trait BaseActor extends Actor {
override def receive: Receive = commonReceive orElse handleReceive
def commonReceive: Receive = {
case CommonMessage => // do something
}
def handleReceive: Receive
}
And then your sub actors only have to implement handleReceive:
class SubActor extends BaseActor {
override def handleReceive: Receive = {
case SpecificMessage => // do something
}
}

Related

Inject different factories to the same actor

I'm new to Akka and Guice, and just started to explore it.
I'm trying to make a father actor, that produce child actors from one specific type, to be more generic- so it'll produce many kind of child actors with different types.
Currently- I inject to the father-actor a Factory of one specific type of actor,
I don't want to add more cases to the father actor, I'd like to solve this problem in more elegant way.
so now I have 2 child actors, and I want to Inject their factory to the father-actor, to do so i thought that maybe I should create the father-actor twice, and each time to inject a different type of Factory.
what I would want to achieve is something like this code
(this code is not working, but this is the idea):
Base Factory trait:
trait BaseFactory {
apply(id: Int) : Actor
}
object FirstActor {
trait Factory extends BaseFactory
}
class FirstActor (#Assisted id: Int) extends Actor with InjectedActorSupport {
....
}
object SecondActor {
trait Factory extends BaseFactory
}
class SecondActor (#Assisted id: Int) extends Actor with InjectedActorSupport {
....
}
class Father #Inject()(factory: BaseFactory, name: String) extends Actor with InjectedActorSupport {
override def receive: Receive = {
case Command =>
...
val actor = context.child(id)
.getOrElse(injectedChild(factory(id), name, _.withMailbox("deque-mailbox")))
}
}
And then the module:
(this part is not compiling since I can't pass the Factories to props as a trait definition and not an instance)
class Module extends AkkaGuiceSupport {
def configure(): Unit = {
bindActor[ExecutorsOffice]("FirstFather", Props(new Father(FirstActor.Factory)))
bindActor[ExecutorsOffice]("SecondFather", Props(new Father(SecondActor.Factory)))
bindActorFactory[FirstActor, FirstActor.Factory]
bindActorFactory[SecondActor, SecondActor.Factory]
}
I'll be happy to hear your thoughts, and your solutions (other solutions will be great also!)
I'm not sure why you'd need Guice-injection.
type PropsCreator = String => Props
object ParentActor {
def props(childPropsCreator: PropsCreator) = Props(classOf[ParentActor], childPropsCreator)
}
class ParentActor(childPropsCreator: PropsCreator) extends Actor {
// yadda yadda yadda
def receive(): Receive = {
case x: Command =>
// yadda yadda yadda
val child = context.child(id)
.getOrElse(context.actorOf(childPropsCreator(id), id))
child.forward(x)
}
}
object DdvRenderProcessManager {
def props(id: String) = Props(classOf[DdvRenderProcessManager], id)
}
class DdvRenderProcessManager(id: String) extends Actor {
// definition omitted
}
object UpdateProcessManager {
def props(id: String) = Props(classOf[UpdateProcessManager], id)
}
class UpdateProcessManager(id: String) extends Actor {
// definition omitted
}
Then you'd create parents like
val ddvRenderParent = system.actorOf(ParentActor.props(DdvRenderProcessManager.props _), "ddvRenderParent")
val updateParent = system.actorOf(ParentActor.props(UpdateProcessManager.props _), "updateParent")
If you wanted to, for instance have all the DdvRenderProcessManagers have a certain dynamic value:
object DdvRenderProcessManager {
// could also express as
// def props(x: Int)(id: String): Props
// and curry, but this expression is clearer about intent
def propsFor(x: Int): String => Props = { (id: String) =>
Props(classOf[DdvRenderProcessManager], id, x)
}
}
class DdvRenderProcessManager(id: String, x: Int) extends Actor {
// definition omitted
}
And then
val ddvRenderParent = system.actorOf(ParentActor.props(DdvRenderProcessManager.propsFor(42)), "ddvRenderParent")
You could even make the dynamic value implicit to allow for something very-close to compile-time DI.

Injecting Akka's TestProbe in place of child actors

I have a parent actor named "manager" which creates several child actors.
These child actors then send back their response via "sender tell", i.e directly back to "manager".
I want to create a unit test for this manager actor, and therefore need to inject a probe to forward the messages from the manager to its children.
I used the following post:
http://www.superloopy.io/articles/2013/injecting-akka-testprobe.html
However i'm still having some trouble getting this done correctly.
In order to simplify the situation, attached is code describing the actors and unit test i wrote for just one child.
Manager class:
trait ManagerChildProvider {
def createTimestampPointChild: Actor
}
trait ProductionManagerChildProvider extends ManagerChildProvider {
def createTimestampPointChild = new TimeDifferenceCalculationActor
}
object Manager {
def apply() = new Manager("cid1") with ProductionManagerChildProvider
}
class Manager(name: String) extends Actor with ActorLogging {
this: ManagerChildProvider =>
#Autowired private val modelParams = new ModelParams //list of parameters
val timeDifference = context.actorOf(Props(createTimestampPointChild))
def receive = {
case p#TimePoint(tPoint) =>
timeDifference ! p
case _ =>
log.error("Unknown message type")
}
}
Child class:
class TimeDifferenceCalculationActor extends Actor with ActorLogging {
var previousTimestamp: Long = -1
def receive = {
case tPoint(timestamp) =>
if (previousTimestamp != -1) {
sender ! Result(1)
}
case _ =>
log.error("Unknown message type")
}
}
Test class:
object BarSpec {
class Wrapper(target: ActorRef) extends Actor {
def receive = {
case x => target forward x
}
}
}
trait ChildrenProvider {
def newFoo: Actor
}
class BarSpec extends TestKitSpec("BarSpec") {
import Manager._
import BarSpec._
trait TestCase {
val probe = TestProbe()
trait TestChildrenProvider extends ManagerChildProvider {
def newBar = new Wrapper(probe.ref)
}
val actor = system.actorOf(Props(new Manager(componentId = "cid1") with TestChildrenProvider))
}
"Bar" should {
"involve child in doing something" in new TestCase {
actor ! tPoint(1)
actor ! tPoint(2)
probe.expectMsg(tPoint(1))
//probe.reply("ReplyFromChild")
//expectMsg("ReplyFromParent")
}
}
}
Additional test class:
abstract class TestKitSpec(name: String) extends TestKit(ActorSystem(name)) with MustMatchers with BeforeAndAfterAll with ImplicitSender with WordSpecLike{
override def afterAll() {
system.shutdown()
}
}
Currently i get the following errors:
Error:(36, 42) object creation impossible, since method > createTimestampPointChild in trait ManagerChildProvider of > type => akka.actor.Actor is not defined
val actor = system.actorOf(Props(new Manager(componentId = "cid1") with TestChildrenProvider))
Error:(11, 16) overriding method run in trait BeforeAndAfterAll of type > (testName: Option[String], args: > org.scalatest.Args)org.scalatest.Status;
method run in trait WordSpecLike of type (testName: Option[String], > args: org.scalatest.Args)org.scalatest.Status needs `abstract override' > modifiers
abstract class TestKitSpec(name: String) extends > TestKit(ActorSystem(name))
any help with these specific errors or with the task in general would be highly appreciated

stacking multiple traits in akka Actors

I'm creating multiple traits which extend Actor. Then I want to create an actor class which uses some of these traits. However, I'm not sure how to combine the receive methods from all traits in the receive method of the Actor class.
Traits:
trait ServerLocatorTrait extends Actor {
def receive() = {
case "s" => println("I'm server ")
}
}
trait ServiceRegistrationTrait extends Actor {
def receive() = {
case "r" => println("I'm registration ")
}
}
The Actor:
class FinalActor extends Actor with ServiceRegistrationTrait with ServerLocatorTrait {
override def receive = {
super.receive orElse ??? <--- what to put here
}
}
Now if I send "r" and "s" to FinalActor it goes only in ServerLocatorTrait - which is the last trait added.
So the way this works right now is that it considers super the last trait added, so in this case ServerLocatorTrait
Question:
How do I combine the receive methods from all the traits in FinalActor?
PS - I've seen the actors with react example: http://www.kotancode.com/2011/07/19/traits-multiple-inheritance-and-actors-in-scala/
but it's not what I need
I'm not sure if you can combine the receive methods, since that would involve calling the super's super to obtain the ServiceRegistration's receive method. It would also be very confusing.
Another way would be to give different names to the receive method in the traits.
trait ServerLocatorTrait extends Actor {
def handleLocation: Receive = {
case "s" => println("I'm server ")
}
}
trait ServiceRegistrationTrait extends Actor {
def handleRegistration: Receive = {
case "r" => println("I'm registration ")
}
}
class FinalActor extends Actor with ServiceRegistrationTrait with ServerLocatorTrait {
def receive = handleLocation orElse handleRegistration
}
object Main extends App {
val sys = ActorSystem()
val actor = sys.actorOf(Props(new FinalActor))
actor ! "s"
actor ! "r"
sys.shutdown()
}
You can still use you initial approach, but you must chain the super.receive for each mixed trait.
trait IgnoreAll extends Actor {
def receive: Receive = Map()
}
trait ServerLocatorTrait extends Actor {
abstract override def receive = ({
case "s" => println("I'm server ")
}: Receive) orElse super.receive
}
trait ServiceRegistrationTrait extends Actor {
abstract override def receive = ({
case "r" => println("I'm registration ")
}: Receive) orElse super.receive
}
class FinalActor extends IgnoreAll with ServiceRegistrationTrait with ServerLocatorTrait
The latter solution looks pretty ugly to me.
Please see the below link for a more detailed discussion on the subject:
Extending Actors using PartialFunction chaining

Composing trait behavior in Scala in an Akka receive method

Consider these two traits:
trait Poked extends Actor {
override def receive = {
case Poke(port, x) => ReceivePoke(port, x)
}
def ReceivePoke(port: String, x: Any)
}
trait Peeked extends Actor {
override def receive = {
case Peek(port) => ReceivePeek(port)
}
def ReceivePeek(port: String)
}
Now consider I can create a new Actor that implements both traits:
val peekedpoked = actorRef(new Actor extends Poked with Peeked)
How do I compose the receive handlers? i.e., the receiver should be something like the following code, though "automatically generated" (i.e., all traits should compose):
def receive = (Poked.receive: Receive) orElse (Peeked.receive: Receive) orElse ...
You can use super[T] to reference members of particular super classes/traits.
For example:
trait IntActor extends Actor {
def receive = {
case i: Int => println("Int!")
}
}
trait StringActor extends Actor {
def receive = {
case s: String => println("String!")
}
}
class IntOrString extends Actor with IntActor with StringActor {
override def receive = super[IntActor].receive orElse super[StringActor].receive
}
val a = actorOf[IntOrString].start
a ! 5 //prints Int!
a ! "Hello" //prints String!
Edit:
In response to Hugo's comment, here's a solution that allows you to compose the mixins without having to manually wire their receives together. Essentially it involves a base trait with a mutable List[Receive], and each mixed-in trait calls a method to add its own receive to the list.
trait ComposableActor extends Actor {
private var receives: List[Receive] = List()
protected def registerReceive(receive: Receive) {
receives = receive :: receives
}
def receive = receives reduce {_ orElse _}
}
trait IntActor extends ComposableActor {
registerReceive {
case i: Int => println("Int!")
}
}
trait StringActor extends ComposableActor {
registerReceive {
case s: String => println("String!")
}
}
val a = actorOf(new ComposableActor with IntActor with StringActor).start
a ! 5 //prints Int!
a ! "test" //prints String!
The only thing to keep in mind is that the order of the receives should not be important, since you won't be able to easily predict which one is first in the chain, though you could solve that by using a mutable hashmap instead of a list.
You can use empty Receive in base actor class and chain receives in their definitions.
Sample for Akka 2.0-M2:
import akka.actor.Actor
import akka.actor.Props
import akka.event.Logging
import akka.actor.ActorSystem
class Logger extends Actor {
val log = Logging(context.system, this)
override def receive = new Receive {
def apply(any: Any) = {}
def isDefinedAt(any: Any) = false
}
}
trait Errors extends Logger {
override def receive = super.receive orElse {
case "error" => log.info("received error")
}
}
trait Warns extends Logger {
override def receive = super.receive orElse {
case "warn" => log.info("received warn")
}
}
object Main extends App {
val system = ActorSystem("mysystem")
val actor = system.actorOf(Props(new Logger with Errors with Warns), name = "logger")
actor ! "error"
actor ! "warn"
}

Inherit message handling behaviour

I have some events in my model and some handling logic. I want organize communication logic throw Actors. But how I can inherit handling logic without specifying act() in each concrete class
Simplified example
class Event {}
case class FooEvent(str : String) extends Event
case class BarEvent(i : java.lang.Integer) extends Event
trait FooListener extends Actor {
def act() {
react{
case FooEvent => print("foo received")
}
}
}
trait BarListener extends Actor {
def act() {
react{
case BarEvent => print("bar received")
}
}
}
class ListensOnlyBar extends BarListener{}
//can't be done:
//error: overriding method act in trait FooListener of type ()Unit;
//method act in trait BarListener of type ()Unit needs `override' modifier
//class ListensBarAndFoo extends FooListener with BarListener{
class ListensBarAndFoo extends FooListener with BarListener{}
react expects PartialFunction[Any, Unit] and you can nicely compose them together. Here is an example:
type Listener = PartialFunction[Any, Unit]
val foo: Listener = {
case FooEvent => print("foo received")
}
val bar: Listener = {
case BarEvent => print("bar received")
}
case class GenericListener(listener: Listener) extends Actor {
def act() {
react(listener)
}
}
GenericListener(bar)
GenericListener(foo orElse bar)