Adding a convenience BundleActivator implementation to bootstrap Akka from an OSGi bundle
This commit is contained in:
parent
12bd97b66d
commit
07dd654849
3 changed files with 169 additions and 0 deletions
|
|
@ -0,0 +1,78 @@
|
|||
package akka.osgi
|
||||
|
||||
import com.typesafe.config.{ Config, ConfigFactory }
|
||||
import akka.actor.ActorSystem
|
||||
import org.osgi.framework.{ BundleContext, BundleActivator }
|
||||
import java.util.Properties
|
||||
|
||||
/**
|
||||
* Abstract {@link BundleActivator} implementation to bootstrap and configure an {@link ActorSystem} in an
|
||||
* OSGi environment.
|
||||
*/
|
||||
abstract class ActorSystemActivator extends BundleActivator {
|
||||
|
||||
var system: ActorSystem = null
|
||||
|
||||
/**
|
||||
* Implement this method to add your own actors to the ActorSystem
|
||||
*
|
||||
* @param system the ActorSystem that was created by the activator
|
||||
*/
|
||||
def configure(system: ActorSystem)
|
||||
|
||||
/**
|
||||
* Sets up a new ActorSystem and registers it in the OSGi Service Registry
|
||||
*
|
||||
* @param context the BundleContext
|
||||
*/
|
||||
def start(context: BundleContext) {
|
||||
system = createActorSystem(context)
|
||||
configure(system)
|
||||
|
||||
val properties = new Properties();
|
||||
properties.put("name", getActorSystemName(context))
|
||||
context.registerService(classOf[ActorSystem].getName, system, properties)
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts down the ActorSystem when the bundle is stopped.
|
||||
*
|
||||
* @param context the BundleContext
|
||||
*/
|
||||
def stop(context: BundleContext) {
|
||||
if (system != null) {
|
||||
system.shutdown()
|
||||
system.shutdown()
|
||||
system = null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy method to create the ActorSystem.
|
||||
*/
|
||||
def createActorSystem(context: BundleContext) =
|
||||
ActorSystem(getActorSystemName(context), getActorSystemConfig(context), getClass.getClassLoader)
|
||||
|
||||
|
||||
/**
|
||||
* Strategy method to create the Config for the ActorSystem, ensuring that the default/reference configuration is
|
||||
* loaded from the akka-actor bundle.
|
||||
*/
|
||||
def getActorSystemConfig(context: BundleContext): Config = {
|
||||
val reference = ConfigFactory.defaultReference(classOf[ActorSystem].getClassLoader)
|
||||
ConfigFactory.load(getClass.getClassLoader).withFallback(reference)
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy method to determine the ActorSystem name - override this method to define the ActorSytem name yourself.
|
||||
*
|
||||
* The default implementation will use 'bundle-<id>-ActorSystem' where <id> matches the bundle id for the containing bundle.
|
||||
*
|
||||
* @param context the BundleContext
|
||||
* @return the ActorSystem name
|
||||
*/
|
||||
def getActorSystemName(context: BundleContext): String = {
|
||||
"bundle-%s-ActorSystem".format(context.getBundle().getBundleId)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
package akka.osgi
|
||||
|
||||
import java.util.{ ServiceLoader, HashMap }
|
||||
import de.kalpatec.pojosr.framework.launch.{ ClasspathScanner, PojoServiceRegistryFactory }
|
||||
import org.scalatest.FlatSpec
|
||||
import org.osgi.framework.BundleContext
|
||||
import akka.actor.{ Actor, Props, ActorSystem }
|
||||
import akka.pattern.ask
|
||||
import akka.dispatch.Await
|
||||
import akka.util.duration._
|
||||
import akka.util.Timeout
|
||||
|
||||
/**
|
||||
* Test cases for {@link ActorSystemActivator}
|
||||
*/
|
||||
class ActorSystemActivatorTest extends FlatSpec {
|
||||
|
||||
abstract class TestMessage
|
||||
|
||||
case object Ping extends TestMessage
|
||||
case object Pong extends TestMessage
|
||||
|
||||
class PongActor extends Actor {
|
||||
def receive = {
|
||||
case Ping ⇒
|
||||
sender ! Pong
|
||||
}
|
||||
}
|
||||
|
||||
lazy val context: BundleContext = {
|
||||
val config = new HashMap[String, AnyRef]();
|
||||
config.put(PojoServiceRegistryFactory.BUNDLE_DESCRIPTORS, new ClasspathScanner().scanForBundles());
|
||||
|
||||
val loader = ServiceLoader.load(classOf[PojoServiceRegistryFactory]);
|
||||
|
||||
val registry = loader.iterator().next().newPojoServiceRegistry(config);
|
||||
registry.getBundleContext
|
||||
}
|
||||
|
||||
val activator = new ActorSystemActivator {
|
||||
def configure(system: ActorSystem) {
|
||||
system.actorOf(Props(new PongActor), name = "pong")
|
||||
}
|
||||
}
|
||||
|
||||
"ActorSystemActivator" should "start and register the ActorSystem on start" in {
|
||||
|
||||
activator.start(context)
|
||||
|
||||
val reference = context.getServiceReference(classOf[ActorSystem].getName)
|
||||
assert(reference != null)
|
||||
|
||||
val system = context.getService(reference).asInstanceOf[ActorSystem]
|
||||
val actor = system.actorFor("/user/pong")
|
||||
|
||||
implicit val timeout = Timeout(5 seconds)
|
||||
val future = actor ? Ping
|
||||
val result = Await.result(future, timeout.duration)
|
||||
assert(result != null)
|
||||
}
|
||||
|
||||
it should "stop the ActorSystem on bundle stop" in {
|
||||
val reference = context.getServiceReference(classOf[ActorSystem].getName)
|
||||
assert(reference != null)
|
||||
|
||||
val system = context.getService(reference).asInstanceOf[ActorSystem]
|
||||
assert(!system.isTerminated)
|
||||
|
||||
activator.stop(context)
|
||||
|
||||
system.awaitTermination()
|
||||
assert(system.isTerminated)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -209,6 +209,15 @@ object AkkaBuild extends Build {
|
|||
)
|
||||
)
|
||||
|
||||
lazy val osgi = Project(
|
||||
id = "akka-osgi",
|
||||
base = file("akka-osgi"),
|
||||
dependencies = Seq(actor),
|
||||
settings = defaultSettings ++ OSGi.osgi ++ Seq(
|
||||
libraryDependencies ++= Dependencies.osgi
|
||||
)
|
||||
)
|
||||
|
||||
lazy val akkaSbtPlugin = Project(
|
||||
id = "akka-sbt-plugin",
|
||||
base = file("akka-sbt-plugin"),
|
||||
|
|
@ -419,6 +428,8 @@ object Dependencies {
|
|||
|
||||
val camel = Seq(camelCore, Test.scalatest, Test.junit, Test.mockito)
|
||||
|
||||
val osgi = Seq(osgiCore, Test.pojosr, Test.scalatest, Test.junit)
|
||||
|
||||
val tutorials = Seq(Test.scalatest, Test.junit)
|
||||
|
||||
val docs = Seq(Test.scalatest, Test.junit, Test.specs2)
|
||||
|
|
@ -434,6 +445,7 @@ object Dependency {
|
|||
val Camel = "2.8.0"
|
||||
val Logback = "0.9.28"
|
||||
val Netty = "3.3.0.Final"
|
||||
val OSGi = "4.2.0"
|
||||
val Protobuf = "2.4.1"
|
||||
val ScalaStm = "0.5"
|
||||
val Scalatest = "1.6.1"
|
||||
|
|
@ -444,6 +456,7 @@ object Dependency {
|
|||
|
||||
val camelCore = "org.apache.camel" % "camel-core" % V.Camel // ApacheV2
|
||||
val netty = "io.netty" % "netty" % V.Netty // ApacheV2
|
||||
val osgiCore = "org.osgi" % "org.osgi.core" % V.OSGi // ApacheV2
|
||||
val protobuf = "com.google.protobuf" % "protobuf-java" % V.Protobuf // New BSD
|
||||
val scalaStm = "org.scala-tools" % "scala-stm_2.9.1" % V.ScalaStm // Modified BSD (Scala)
|
||||
val slf4jApi = "org.slf4j" % "slf4j-api" % V.Slf4j // MIT
|
||||
|
|
@ -463,6 +476,7 @@ object Dependency {
|
|||
val junit = "junit" % "junit" % "4.5" % "test" // Common Public License 1.0
|
||||
val logback = "ch.qos.logback" % "logback-classic" % V.Logback % "test" // EPL 1.0 / LGPL 2.1
|
||||
val mockito = "org.mockito" % "mockito-all" % "1.8.1" % "test" // MIT
|
||||
val pojosr = "com.googlecode.pojosr" % "de.kalpatec.pojosr.framework" % "0.1.8" % "test" // ApacheV2
|
||||
val scalatest = "org.scalatest" % "scalatest_2.9.1" % V.Scalatest % "test" // ApacheV2
|
||||
val scalacheck = "org.scala-tools.testing" % "scalacheck_2.9.1" % "1.9" % "test" // New BSD
|
||||
val specs2 = "org.specs2" % "specs2_2.9.1" % "1.9" % "test" // Modified BSD / ApacheV2
|
||||
|
|
@ -487,6 +501,8 @@ object OSGi {
|
|||
|
||||
val mailboxesCommon = exports(Seq("akka.actor.mailbox.*"))
|
||||
|
||||
val osgi = exports(Seq("akka.osgi.*"))
|
||||
|
||||
val remote = exports(Seq("akka.remote.*", "akka.routing.*", "akka.serialization.*"))
|
||||
|
||||
val slf4j = exports(Seq("akka.event.slf4j.*"))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue