Subsystems - laforge49/Asynchronous-Functional-Programming GitHub Wiki
Dependency Injection can be a great simplifier but as the complexity of an application grows, having all services in a flat namespace can make things difficult. There is a real need for subsystems and hierarchical dependency injection is a great way to implement that. We define a subsystem then as a system services actor which has a superior actor.
object Subsystem {
def apply(systemServices: Actor,
rootComponentFactory: ComponentFactory,
mailbox: Mailbox = null,
factoryId: FactoryId = new FactoryId("System"),
properties: Properties = null,
actorClass: Class[_ <: Id_Actor] = classOf[Id_Actor],
actorId: ActorId = null) = {
val subSystemFactory = new CompositeFactory(factoryId, rootComponentFactory, actorClass)
SetProperties(subSystemFactory, properties)
val _mailbox = if (mailbox == null) systemServices.mailbox else mailbox
val subSystem = subSystemFactory.newActor(_mailbox).asInstanceOf[Id_Actor]
if (actorId != null) {
subSystem.id(actorId)
}
subSystem.setSystemServices(subSystem)
subSystem.setSuperior(systemServices)
subSystem._open
subSystem
}
}
Note that when a subsystem is created without a mailbox, it uses the mailbox of its superior.
A subsystem actor implements IdActor, so it can be registered with an ActorRegistry. Generally, it is a good idea for subsystems to be registered with their superior.
The FactoryRegistry and ActorRegistry services also support subspaces. So when an actor attempts to create an actor using a registered factory or to get a registered actor and the registration has not been done in a subsystem, the FactoryRegistry or ActorRegistry of the superior system services actor is accessed.
Here is a test where an actor tied to a subsystem uses a factory registered to the superior system services actor.
case class Greet()
class Greeter
extends Actor {
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
}
class SomeComponentFactory
extends ComponentFactory {
addDependency(classOf[FactoryRegistryComponentFactory])
override def configure(compositeFactory: Factory) {
val factoryRegistryComponentFactory =
compositeFactory.componentFactory(classOf[FactoryRegistryComponentFactory]).
asInstanceOf[FactoryRegistryComponentFactory]
factoryRegistryComponentFactory.registerFactory(new GreeterFactory)
}
}
case class DoIt()
class Driver extends Actor {
bind(classOf[DoIt], doit)
setMailbox(new ReactorMailbox)
def doit(msg: AnyRef, rf: Any => Unit) {
systemServices(Instantiate(FactoryId("greeter"), null)) {rsp =>
val greeter = rsp.asInstanceOf[Actor]
greeter(Greet())(rf)
}
}
}
class SubsystemTest extends SpecificationWithJUnit {
"SubsystemTest" should {
"instantiate" in {
val systemServices = SystemServices(new SomeComponentFactory)
val aSubsystem = Subsystem(systemServices, new FactoryRegistryComponentFactory)
val driver = new Driver
driver.setSystemServices(aSubsystem)
Future(driver, DoIt())
}
}
}
Output.
Hello world!