Skip to content
laforge49 edited this page Oct 28, 2011 · 11 revisions

An actor registry allows you to look up a registered actor by ActorId. It also maintains a hard reference to the registered actors to keep them from being garbage collected. And when the ActorRegistry is closed, it closes all the registered actors.

The actor registry is a component that can be used to create a composite actor for dependency injection. It processes 4 types of messages.

case class Register(actor: IdActor)
case class Unregister(actorId: ActorId)
case class GetActor(actorId: ActorId)
case class ResolveName(name: Name, mailbox: Mailbox)

The response to a Register or Unregister message is a null, while the response to a GetActor or ResolveName message is either an Actor or null.

There are 2 subclasses of Name, ActorId and FactoryId. A ResolveName message with a FactoryId instantiates the actor synchronously, while a ResolveName message with an ActorId acts the same as a GetActor message and returns the registered actor if present.

To test ActorRegistry we will need to create some actors which implement IdActor. These will be of the Greeter class.

case class Greet()

class Greeter
  extends Actor with IdActor {
  bind(classOf[Greet], greet)
  def greet(msg: AnyRef, rf: Any => Unit) {
    println("Hello world!")
    rf(null)
  }
}

class GreeterFactory
  extends Factory(new FactoryId("greeter")) {
  override def instantiate = new Greeter
}

We will also need an actor that will exercise the ActorRegistry.

case class DoIt1()
case class DoIt2()

class Driver extends Actor {
  setMailbox(new ReactorMailbox)
  bind(classOf[DoIt1], doit1)
  bind(classOf[DoIt2], doit2)

  def doit1(msg: AnyRef, rf: Any => Unit) {
    systemServices(Instantiate(FactoryId("greeter"), null)) {rsp =>
      val greeter = rsp.asInstanceOf[IdActor]
      greeter.id(ActorId("a"))
      systemServices(Register(greeter)) {rsp => {}}
    }
    systemServices(ResolveName(FactoryId("greeter"), null)) {rsp =>
      val greeter = rsp.asInstanceOf[IdActor]
      greeter.id(ActorId("b"))
      systemServices(Register(greeter)) {rsp => {}}
    }
    rf(null)
  }

  def doit2(msg: AnyRef, rf: Any => Unit) {
    systemServices(Unregister(ActorId("a"))) {rsp => {}}
    systemServices(ResolveName(ActorId("b"), null)) {rsp =>
      val actor = rsp.asInstanceOf[Actor]
      actor(Greet())(rf)
    }
  }
}

We will also need to define a component that we can use to create a composite actor for dependency injection and which will pull together the needed components. This component will also register the factory for Greeter with the FactoryRegistry.

class SomeComponentFactory
  extends ComponentFactory {
  addDependency(classOf[FactoryRegistryComponentFactory])
  addDependency(classOf[ActorRegistryComponentFactory])

  override def configure(compositeFactory: Factory) {
    val factoryRegistryComponentFactory =
      compositeFactory.componentFactory(classOf[FactoryRegistryComponentFactory]).
        asInstanceOf[FactoryRegistryComponentFactory]
    factoryRegistryComponentFactory.registerFactory(new GreeterFactory)
  }
}

Finally we need to create our system services composite and driver actor and inject the former into the latter, as well as running the actual tests.

val systemServices = SystemServices(new SomeComponentFactory)
val driver = new Driver
driver.setSystemServices(systemServices)
Future(driver, DoIt1())
Future(driver, DoIt2())

Output.

Hello world!

ActorRegistryTest

Of particular note is that, while the ActorRegistry sends an Instantiate message when it receives a ResolveName message containing a FactoryId, the ActorRegistry component does not depend on the FactoryRegistry component. This allows you to replace the FactoryRegistry component with some other component of your choosing, so long as it abides by the implicit contract of Instantiate. The ActorRegistry does however verify that the Instantiate message is an available service. This is when the component is opened.

override def open {
  actor.requiredService(classOf[Instantiate])
}

Tutorial

Clone this wiki locally