When building a truly modular software application, OSGi really is an obvious choice these days. The modules are OSGi bundles, each exporting services other bundles can consume. Clean and simple, what else can one want?
Things get a bit more complicated when developing OSGi bundles using Scala, and to be more specific, when using Scala actors. The Scala libraries are available as OSGi bundles, so that's a no-brainer. But what happens when you want to use actors in Scala, and you decide to use the Scala actors from the Akka project?
Akka itself consists of multiple modules, and each of them is an OSGi bundle. Some of the Akka 3rd party dependencies are on the other hand not available as OSGi bundles, so that's why Akka provides one big dependency OSGi bundle. Not really the nicest solution, but the Akka guys can't help it that their dependencies aren't available as OSGi bundles. When creating actors in Akka, each actor is registered in the ActorRegistry so the actor can later on easily be looked up, sent messages to be started and stopped etc. This ActorRegistry is a singleton, so there's one registry for all actors in an application.
Using Akka actors and the ActorRegistry in an OSGi environment triggers some interesting architecture questions however. An OSGi application bundle acts as some sort of mini-application, and allows to export services and keep all the other functionality of a bundle private. If this bundle creates actors however, they're registered in the application-wide ActorRegistry, and are available to other bundles without being exported explicitly as OSGi services. This makes the use of OSGi services superfluous, that's one way to look at it. But at the same time the bundle can no longer control which actors (acting as services) are made available publicly: every actor is accessible via the ActorRegistry.
In an OSGi environment the application bundles are mini-applications themselves. They can be started and stopped, they can execute logic when started and stopped (using a bundle activator), they come and go. When a bundle starts it typically creates it actors, when stopped the actors should be stopped. Be careful however when using the ActorRegistry to stop the actors of a bundle, as using shutdownAll would stop all the actors of all the bundles.
There are things you can try to achieve some more control in what your bundle makes available to other bundles. Using TypedActor's or by using Scala case classes as messages you achieve more strong-typed behavior, which is a good thing anyway. But it also allows you not to make these classes available to other bundles by not including them in the OSGi bundle's export-package. Using the functionality of your actor without the message classes becomes impossible this way, but the actor is still available in the ActorRegistry, and can be controlled this way by other bundles (stopped, started, ...).
Ideally in an OSGi environment each bundle should have it's own ActorRegistry, and make actors available to other bundles by exporting them as OSGi services. Or at least it should be possible to use Akka actors this way. Or maybe there are other solutions to achieve this more application-bundle-like behavior?
There's a thread on the Akka-users mailinglist on this topic. There's a suggestion to use classloader isolation for the different bundles and use remote actors to communicate between bundles. Feel free to provide any other insights or suggestions in the comments.
Interesting article. It seems to me the proper solution would be to change ActorRegistry from being a singleton, and make it a trait that can be implemented as a service instead. The default non-OSGi setup, that would ideally *not* be packaged in the core bundle, could very well create the companion object to keep backwards compatibility (companion objects have to be in the same file, so that means generating something different for OSGi & non-OSGi clients, and that's something better to avoid -- just like singletons!).
ReplyDeleteIt's a bit disappointing that people are using Scala objects as stateful public singletons. They're certainly practical for side-effect free stuff (like static factories, helper functions, defining implicit conversions, ...) and I could understand, even if I don't like it, having an internal stateful singleton if it's not leaked to the API... but classes like ActorRegistry mix badly with OSGi (for good reasons).
On the other hand, Akka is awesome and the team is great so hopefully they would be open for a nice proposal to clean up things. I know some of the usual suspects in the OSGi community use Akka so I'm sure they'll come up with something. I've been following Akka for some time and the API already went through several refactorings (including the one which introduced that ActorRegistry! ;)) so maybe they'd be OK with one more to get rid of these ugly stateful singletons.