Lifecycle - laforge49/Asynchronous-Functional-Programming GitHub Wiki
Large composites often have complex initialization and takedown. To help with this, on receipt of the first message an actor calls the open method on each of its components in the order in which they were added to the actor. In addition, actors have a close method which calls a close method on its components in reverse order.
Once an actor receives a message, no more components can be added.
The open and close methods of a component should not send messages to any actors.
We can illustrate this with two simple components which print a message when they are opened or closed.
class SC1Factory extends ComponentFactory {
addDependency(classOf[SC2Factory])
override protected def instantiate(actor: Actor) = new SC1(actor)
}
class SC1(actor: Actor)
extends Component(actor) {
override def open {println("SC1 open")}
override def close {println("SC1 close")}
}
class SC2Factory extends ComponentFactory {
override protected def instantiate(actor: Actor) = new SC2(actor)
}
case class DoIt()
class SC2(actor: Actor)
extends Component(actor) {
override def open {println("SC2 open")}
override def close {println("SC2 close")}
def doit(msg: AnyRef, rf: Any => Unit) {
println("Done it!")
rf(null)
}
}
Since SC1 depends on SC2, SC2 should be opened before SC1 and SC1 should be closed before SC2. Now for convenience, there is also a CompositeFactory class.
class CompositeFactory(factoryId: FactoryId,
rootComponentFactory: ComponentFactory,
actorClass: Class[_ <: Actor] = classOf[Actor])
extends Factory(factoryId) {
include(rootComponentFactory)
override protected def instantiate = actorClass.newInstance
}
The test code for this is now quite brief.
val actor = (new CompositeFactory(null, new SC1Factory)).newActor(null)
Future(actor, DoIt())
actor.close
And here is the output.
SC2 open
SC1 open
Done it!
SC1 close
SC2 close