Hello I am new to Scala and I have failed to figure out how one can store an actor reference within a second actor, for sending a message at a later time. In my code I try to send a test message to one actor. when it receives this message it should store the reference (OutputChannel) to the second actor and at a later time should be able to send a message to the second actor. I did not want to use the reply() as I need the message to be sent only when i invoke the respond. Here is the code. Thanks for any help!
import scala.actors.Actor
import scala.actors.Actor._
import scala.collection.mutable.ArrayBuffer
import scala.actors.OutputChannel
object testactors {
case object TestMessage
case object Respond
class TestActor(name: String) extends Actor {
private var source : ArrayBuffer[OutputChannel[Any]] = new ArrayBuffer
def act() {
loop {
react{
case TestMessage =>
println("i received a TestMessage " + name)
source += sender
case Respond =>
println("i received a ResponseMessage " + name)
}
}
}
def sendMessage(dest: Actor) = dest ! TestMessage
def respond = {
println("responding... " + name)
source(0) ! Respond
}
}
def main(args: Array[String]) {
val actor1 = new TestActor("one")
actor1.start
val actor2 = new TestActor("two")
actor2.start
actor1.sendMessage(actor2)
Thread.sleep(5000)
actor2.respond
}
}
1. You can create a centralized actor registry. To avoid reinventing the wheel, you can use a good existing implementation - Akka's Actor Registry (or, at least, get inspired with it).
2 You can avoid using mutable list of actor references passing it through react loop:
case class AddActor(actor: Actor)
case object NotifyAll
class StatefulActor extends Actor {
override def act = loop(Nil)
def loop(actors: List[Actor]):Unit = {
react {
case AddActor(actor) => println("Added new actor")
loop(actor :: actors)
case NotifyAll => println("Notifying actors: " + actors)
actors.foreach(_ ! "Hi!")
loop(actors)
case unknown => println("Unknown message: " + unknown)
loop(actors)
}
}
}
One way to do it is to create an Actor Factory that stores actors that you can grab from anywhere.
import scala.actors.Actor
import scala.actors.Actor._
import scala.collection.mutable._
Messages can be either objects (with no "payload"), or can be classes that contain data
abstract class Message
case object MessageType1 extends Message
case class MessageType2(str:String) extends Message
Here are a couple of actor types. The Actor2 instance is instantiated "on-the-fly", and stored in the ActorFactory for later use, as is the Actor1 instance that is explicitly declared in the main
class MyActor1 extends Actor {
def act() {
loop {
react {
case MessageType1 =>
println("MessageType1 received")
ActorFactory.getActor2("B") ! MessageType2("Hello")
case _ =>
}
}
}
}
class MyActor2 extends Actor {
def act() {
loop {
react {
case MessageType2(theString) =>
println(theString+" from actor 2 instance")
case _ =>
}
}
}
}
The following ActorFactory creates and stores actors. Here, you can create multiple instances of a type of actor, and store by name.
object ActorFactory {
val actorMap = new HashMap[String,Actor] with SynchronizedMap[String,Actor]
def getActor1(symbol:String): Actor = {
val actor = actorMap.getOrElseUpdate(symbol,new MyActor1().start)
actor
}
def getActor2(symbol:String): Actor = {
val actor = actorMap.getOrElseUpdate(symbol,new MyActor2().start)
actor
}
}
object Test {
def main(args : Array[String]) {
val actor1 = ActorFactory.getActor1("A")
actor1 ! MessageType1
}
}
The output of this is
MessageType1 received
Hello from actor 2 instance
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With