Adding PojoSR tests and a lot of code cleanup
This commit is contained in:
parent
94d68e8f2d
commit
cc79aae1a4
18 changed files with 517 additions and 170 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import akka.actor.{Props, ActorSystem}
|
||||
import akka.actor.{ Props, ActorSystem }
|
||||
import akka.osgi.ActorSystemActivator
|
||||
import org.apache.servicemix.examples.akka.Listener
|
||||
import org.apache.servicemix.examples.akka.Master
|
||||
|
|
|
|||
|
|
@ -1,25 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
-->
|
||||
|
||||
<!-- $Rev: 699828 $ $Date: 2008-09-28 16:35:27 +0200 (Sun, 28 Sep 2008) $ -->
|
||||
|
||||
<xsd:schema xmlns="http://akka.io/xmlns/blueprint/v1.0.0"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:bp="http://www.osgi.org/xmlns/blueprint/v1.0.0"
|
||||
|
|
@ -44,24 +23,20 @@
|
|||
</xsd:annotation>
|
||||
<xsd:sequence>
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:element ref="actor"/>
|
||||
<xsd:element ref="config" />
|
||||
</xsd:choice>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="id" type="xsd:ID"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="optional"/>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="actor">
|
||||
<xsd:complexType>
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Defines an Akka Actor
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:attribute name="id" type="xsd:ID"/>
|
||||
<xsd:attribute name="name" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="class" type="xsd:string" use="optional"/>
|
||||
</xsd:complexType>
|
||||
<xsd:element name="config" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Defines an Akka ActorSystem configuration
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
|
||||
</xsd:schema>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ abstract class ActorSystemActivator(nameFor: (BundleContext) ⇒ String) extends
|
|||
*/
|
||||
def stop(context: BundleContext) {
|
||||
if (system != null) {
|
||||
system.shutdown()
|
||||
system.shutdown()
|
||||
system = null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ package akka.osgi
|
|||
|
||||
import impl.BundleDelegatingClassLoader
|
||||
import org.osgi.framework.BundleContext
|
||||
import java.util.Properties
|
||||
import akka.actor.ActorSystem
|
||||
import com.typesafe.config.{ ConfigFactory, Config }
|
||||
import java.util.{ Dictionary, Properties }
|
||||
|
||||
/**
|
||||
* Factory class to create ActorSystem implementations in an OSGi environment. This mainly involves dealing with
|
||||
|
|
@ -20,16 +20,18 @@ class OsgiActorSystemFactory(val context: BundleContext) {
|
|||
/**
|
||||
* Creates the ActorSystem and registers it in the OSGi Service Registry
|
||||
*/
|
||||
def createActorSystem(name: String) = {
|
||||
def createActorSystem(name: String): ActorSystem = createActorSystem(Option(name))
|
||||
|
||||
def createActorSystem(name: Option[String]): ActorSystem = {
|
||||
val system = ActorSystem(actorSystemName(name), actorSystemConfig(context), classloader)
|
||||
registerService(system)
|
||||
system
|
||||
}
|
||||
|
||||
def registerService(system: ActorSystem) {
|
||||
val properties = new Properties();
|
||||
val properties = new Properties()
|
||||
properties.put("name", system.name)
|
||||
context.registerService(classOf[ActorSystem].getName, system, properties)
|
||||
context.registerService(classOf[ActorSystem].getName, system, properties.asInstanceOf[Dictionary[String, Any]])
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -44,8 +46,8 @@ class OsgiActorSystemFactory(val context: BundleContext) {
|
|||
/**
|
||||
* Determine a the ActorSystem name
|
||||
*/
|
||||
def actorSystemName(name: String): String =
|
||||
Option(name).getOrElse("bundle-%s-ActorSystem".format(context.getBundle().getBundleId))
|
||||
def actorSystemName(name: Option[String]): String =
|
||||
name.getOrElse("bundle-%s-ActorSystem".format(context.getBundle().getBundleId))
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,31 +4,39 @@ import org.osgi.framework.BundleContext
|
|||
import akka.osgi.OsgiActorSystemFactory
|
||||
import collection.mutable.Buffer
|
||||
import akka.actor.{ Actor, Props, ActorSystem }
|
||||
import com.typesafe.config.ConfigFactory
|
||||
|
||||
/**
|
||||
* A set of helper/factory classes to build a Akka system using Blueprint
|
||||
*/
|
||||
class BlueprintActorSystemFactory(context: BundleContext, name: String) extends OsgiActorSystemFactory(context) {
|
||||
|
||||
val systems: Buffer[ActorSystem] = Buffer()
|
||||
var config: Option[String] = None
|
||||
|
||||
def this(context: BundleContext) = this(context, null)
|
||||
lazy val system = super.createActorSystem(stringToOption(name))
|
||||
|
||||
def create: ActorSystem = create(null)
|
||||
def create(name: String): ActorSystem = {
|
||||
val system = super.createActorSystem(name)
|
||||
systems += system
|
||||
system
|
||||
def setConfig(config: String) = { this.config = Some(config) }
|
||||
|
||||
def create = system
|
||||
|
||||
def destroy = system.shutdown()
|
||||
|
||||
def stringToOption(original: String) = if (original == null || original.isEmpty) {
|
||||
None
|
||||
} else {
|
||||
Some(original)
|
||||
}
|
||||
|
||||
def destroy = for (system ← systems) {
|
||||
system.shutdown()
|
||||
/**
|
||||
* Strategy method to create the Config for the ActorSystem, ensuring that the default/reference configuration is
|
||||
* loaded from the akka-actor bundle.
|
||||
*/
|
||||
override def actorSystemConfig(context: BundleContext) = {
|
||||
config match {
|
||||
case Some(value) ⇒ ConfigFactory.parseString(value).withFallback(super.actorSystemConfig(context))
|
||||
case None ⇒ super.actorSystemConfig(context)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class BlueprintActorSystem(context: BundleContext, system: ActorSystem) {
|
||||
|
||||
def createActor(name: String) = system.actorOf(Props(context.getBundle.loadClass(name).asInstanceOf[Class[Actor]]))
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,92 +9,122 @@ import org.osgi.framework.BundleContext
|
|||
import org.apache.aries.blueprint.reflect.{ ValueMetadataImpl, RefMetadataImpl, BeanArgumentImpl }
|
||||
import org.w3c.dom.{ NodeList, Element, Node }
|
||||
import org.osgi.service.blueprint.reflect.{ BeanMetadata, ComponentMetadata }
|
||||
import akka.actor.{ ActorRef, ActorSystem }
|
||||
import akka.osgi.blueprint.{ BlueprintActorSystem, BlueprintActorSystemFactory }
|
||||
import akka.actor.{ ActorSystem }
|
||||
import akka.osgi.blueprint.{ BlueprintActorSystemFactory }
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
import ParserHelper.childElements
|
||||
|
||||
/**
|
||||
* Aries Blueprint namespace handler implementation
|
||||
*/
|
||||
class NamespaceHandler extends org.apache.aries.blueprint.NamespaceHandler {
|
||||
|
||||
val CLASS_ATTRIBUTE = "class";
|
||||
val ID_ATTRIBUTE = "id";
|
||||
val NAME_ATTRIBUTE = "name";
|
||||
import NamespaceHandler._
|
||||
|
||||
var idCounter = 1
|
||||
val idCounter = new AtomicInteger(0)
|
||||
|
||||
def getSchemaLocation(namespace: String) = getClass().getResource("akka.xsd")
|
||||
|
||||
def getManagedClasses = setAsJavaSet(Set(classOf[BlueprintActorSystemFactory]))
|
||||
|
||||
def parse(element: Element, context: ParserContext) = {
|
||||
val factory = context.createMetadata(classOf[MutableBeanMetadata])
|
||||
factory.setId(getId(context, element))
|
||||
factory.setScope(BeanMetadata.SCOPE_SINGLETON)
|
||||
factory.setProcessor(true)
|
||||
factory.setClassName(classOf[BlueprintActorSystemFactory].getName)
|
||||
factory.setDestroyMethod("destroy")
|
||||
factory.addArgument(new BeanArgumentImpl(new RefMetadataImpl("blueprintBundleContext"), classOf[BundleContext].getName, -1))
|
||||
|
||||
val system = context.createMetadata(classOf[MutableBeanMetadata])
|
||||
system.setId(getId(context, element))
|
||||
system.setFactoryComponent(factory)
|
||||
system.setFactoryMethod("create")
|
||||
system.setRuntimeClass(classOf[ActorSystem])
|
||||
if (element.hasAttribute(NAME_ATTRIBUTE)) {
|
||||
system.addArgument(new BeanArgumentImpl(new ValueMetadataImpl(element.getAttribute(NAME_ATTRIBUTE)), classOf[String].getName, -1))
|
||||
}
|
||||
|
||||
val actorsystem = context.createMetadata(classOf[MutableBeanMetadata])
|
||||
actorsystem.setId(getId(context, element))
|
||||
actorsystem.setClassName(classOf[BlueprintActorSystem].getName)
|
||||
actorsystem.addArgument(new BeanArgumentImpl(new RefMetadataImpl("blueprintBundleContext"), classOf[BundleContext].getName, -1))
|
||||
actorsystem.addArgument(new BeanArgumentImpl(system, classOf[ActorSystem].getName, -1))
|
||||
context.getComponentDefinitionRegistry.registerComponentDefinition(actorsystem)
|
||||
|
||||
val nodelist = element.getChildNodes
|
||||
var i = 0
|
||||
while (i < nodelist.getLength) {
|
||||
val node = nodelist.item(i)
|
||||
node.getLocalName match {
|
||||
case "actor" if node.isInstanceOf[Element] ⇒ parseActor(node.asInstanceOf[Element], context, actorsystem)
|
||||
case _ ⇒
|
||||
}
|
||||
i += 1
|
||||
}
|
||||
factory
|
||||
}
|
||||
|
||||
def parseActor(node: Element, context: ParserContext, actorsystem: MutableBeanMetadata) = {
|
||||
val actor = context.createMetadata(classOf[MutableBeanMetadata])
|
||||
actor.setFactoryComponent(actorsystem)
|
||||
if (node.hasAttribute(CLASS_ATTRIBUTE)) {
|
||||
actor.addArgument(new BeanArgumentImpl(new ValueMetadataImpl(node.getAttribute(CLASS_ATTRIBUTE)), classOf[String].getName, -1))
|
||||
}
|
||||
actor.setId(getId(context, node))
|
||||
actor.setFactoryMethod("createActor")
|
||||
// actor.setRuntimeClass(classOf[ActorRef])
|
||||
context.getComponentDefinitionRegistry.registerComponentDefinition(actor)
|
||||
def parse(element: Element, context: ParserContext) = element.getLocalName match {
|
||||
case ACTORSYSTEM_ELEMENT_NAME ⇒ parseActorSystem(element, context)
|
||||
case _ ⇒ throw new ComponentDefinitionException("Unexpected element for Akka namespace: %s".format(element))
|
||||
}
|
||||
|
||||
def decorate(node: Node, component: ComponentMetadata, context: ParserContext) =
|
||||
throw new ComponentDefinitionException("Bad xml syntax: node decoration is not supported");
|
||||
|
||||
/*
|
||||
* Parse <akka:actor-system/>
|
||||
*/
|
||||
def parseActorSystem(element: Element, context: ParserContext) = {
|
||||
val factory = createFactoryBean(context, element.getAttribute(NAME_ATTRIBUTE))
|
||||
|
||||
for (child ← childElements(element)) {
|
||||
child.getLocalName match {
|
||||
case CONFIG_ELEMENT_NAME ⇒ parseConfig(child, context, factory)
|
||||
case _ ⇒ throw new ComponentDefinitionException("Unexpected child element %s found in %s".format(child, element))
|
||||
}
|
||||
}
|
||||
|
||||
createActorSystemBean(context, element, factory)
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse <akka:config/>
|
||||
*/
|
||||
def parseConfig(node: Element, context: ParserContext, factory: MutableBeanMetadata) = {
|
||||
factory.addProperty("config", new ValueMetadataImpl(node.getTextContent))
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the bean definition for the ActorSystem
|
||||
*/
|
||||
def createActorSystemBean(context: ParserContext, element: Element, factory: MutableBeanMetadata): MutableBeanMetadata = {
|
||||
val system = context.createMetadata(classOf[MutableBeanMetadata])
|
||||
system.setId(getId(context, element))
|
||||
system.setFactoryComponent(factory)
|
||||
|
||||
system.setFactoryMethod(FACTORY_METHOD_NAME)
|
||||
system.setRuntimeClass(classOf[ActorSystem])
|
||||
system
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the bean definition for the BlueprintActorSystemFactory
|
||||
*/
|
||||
def createFactoryBean(context: ParserContext, name: String): MutableBeanMetadata = {
|
||||
val factory = context.createMetadata(classOf[MutableBeanMetadata])
|
||||
factory.setId(findAvailableId(context))
|
||||
factory.setScope(BeanMetadata.SCOPE_SINGLETON)
|
||||
factory.setProcessor(true)
|
||||
factory.setClassName(classOf[BlueprintActorSystemFactory].getName)
|
||||
|
||||
factory.setDestroyMethod(DESTROY_METHOD_NAME)
|
||||
|
||||
factory.addArgument(new BeanArgumentImpl(new RefMetadataImpl(BUNDLE_CONTEXT_REFID), classOf[BundleContext].getName, -1))
|
||||
factory.addArgument(new BeanArgumentImpl(new ValueMetadataImpl(name), classOf[String].getName, -1))
|
||||
factory.setProcessor(true)
|
||||
context.getComponentDefinitionRegistry.registerComponentDefinition(factory)
|
||||
factory
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the assigned id or generate a suitable id
|
||||
*/
|
||||
def getId(context: ParserContext, element: Element) = {
|
||||
if (element.hasAttribute(ID_ATTRIBUTE)) {
|
||||
element.getAttribute(ID_ATTRIBUTE);
|
||||
} else {
|
||||
generateId(context);
|
||||
findAvailableId(context);
|
||||
}
|
||||
}
|
||||
|
||||
def generateId(context: ParserContext): String = {
|
||||
var id = "";
|
||||
do {
|
||||
idCounter += 1
|
||||
id = ".akka-" + idCounter;
|
||||
} while (context.getComponentDefinitionRegistry().containsComponentDefinition(id));
|
||||
id;
|
||||
/*
|
||||
* Find the next available component id
|
||||
*/
|
||||
def findAvailableId(context: ParserContext): String = {
|
||||
val id = ".akka-" + idCounter.incrementAndGet()
|
||||
if (context.getComponentDefinitionRegistry.containsComponentDefinition(id)) {
|
||||
// id already exists, let's try the next one
|
||||
findAvailableId(context)
|
||||
} else id
|
||||
}
|
||||
}
|
||||
|
||||
object NamespaceHandler {
|
||||
|
||||
private val ID_ATTRIBUTE = "id";
|
||||
private val NAME_ATTRIBUTE = "name";
|
||||
|
||||
private val BUNDLE_CONTEXT_REFID = "blueprintBundleContext"
|
||||
|
||||
private val ACTORSYSTEM_ELEMENT_NAME = "actor-system"
|
||||
private val CONFIG_ELEMENT_NAME = "config"
|
||||
|
||||
private val DESTROY_METHOD_NAME = "destroy"
|
||||
private val FACTORY_METHOD_NAME = "create"
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
package akka.osgi.blueprint.aries
|
||||
|
||||
import org.w3c.dom.{ Node, Element }
|
||||
|
||||
/**
|
||||
* Helper class to deal with the W3C DOM types
|
||||
*/
|
||||
object ParserHelper {
|
||||
|
||||
def childElements(element: Element) = children(element).filter(_.getNodeType == Node.ELEMENT_NODE).asInstanceOf[Seq[Element]]
|
||||
|
||||
private[this] def children(element: Element) = {
|
||||
val nodelist = element.getChildNodes
|
||||
for (index ← 0 until nodelist.getLength) yield nodelist.item(index)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
|
||||
xmlns:akka="http://akka.io/xmlns/blueprint/v1.0.0">
|
||||
|
||||
<akka:actor-system name="config">
|
||||
<akka:config>
|
||||
some.config {
|
||||
key=value
|
||||
}
|
||||
</akka:config>
|
||||
</akka:actor-system>
|
||||
|
||||
</blueprint>
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
|
||||
xmlns:akka="http://akka.io/xmlns/blueprint/v1.0.0">
|
||||
|
||||
<service interface="akka.osgi.test.ActorSystemAwareBean">
|
||||
<bean class="akka.osgi.test.ActorSystemAwareBean">
|
||||
<argument>
|
||||
<akka:actor-system name="simple" />
|
||||
</argument>
|
||||
</bean>
|
||||
</service>
|
||||
|
||||
</blueprint>
|
||||
|
|
@ -1,9 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
|
||||
xmlns:akka="http://akka.io/xmlns/blueprint/aries/v1.0.0">
|
||||
xmlns:akka="http://akka.io/xmlns/blueprint/v1.0.0">
|
||||
|
||||
<akka:actor-system name="test">
|
||||
<akka:actor/>
|
||||
</akka:actor-system>
|
||||
<akka:actor-system name="simple" />
|
||||
|
||||
</blueprint>
|
||||
|
|
|
|||
23
akka-osgi/src/test/resources/logback-test.xml
Normal file
23
akka-osgi/src/test/resources/logback-test.xml
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<configuration>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%date{ISO8601} %-5level %logger %X{akkaSource} %X{sourceThread} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
|
||||
<file>target/akka-osgi.log</file>
|
||||
<append>true</append>
|
||||
<encoder>
|
||||
<pattern>%date{ISO8601} %-5level %logger %X{akkaSource} %X{sourceThread} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="debug">
|
||||
<appender-ref ref="FILE" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
|
|
@ -1,53 +1,28 @@
|
|||
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.actor.ActorSystem
|
||||
import akka.pattern.ask
|
||||
import akka.dispatch.Await
|
||||
import akka.util.duration._
|
||||
import akka.util.Timeout
|
||||
import de.kalpatec.pojosr.framework.launch.BundleDescriptor
|
||||
import test.TestActorSystemActivator
|
||||
import test.PingPong._
|
||||
import PojoSRTestSupport.bundle
|
||||
|
||||
/**
|
||||
* Test cases for {@link ActorSystemActivator}
|
||||
*/
|
||||
class ActorSystemActivatorTest extends FlatSpec {
|
||||
class ActorSystemActivatorTest extends FlatSpec with PojoSRTestSupport {
|
||||
|
||||
abstract class TestMessage
|
||||
val TEST_BUNDLE_NAME = "akka.osgi.test.activator"
|
||||
|
||||
case object Ping extends TestMessage
|
||||
case object Pong extends TestMessage
|
||||
val testBundles: Seq[BundleDescriptor] = Seq(
|
||||
bundle(TEST_BUNDLE_NAME).withActivator(classOf[TestActorSystemActivator]))
|
||||
|
||||
class PongActor extends Actor {
|
||||
def receive = {
|
||||
case Ping ⇒
|
||||
sender ! Pong
|
||||
}
|
||||
}
|
||||
|
||||
lazy val context: BundleContext = {
|
||||
val config = new HashMap[String, AnyRef]();
|
||||
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]
|
||||
"ActorSystemActivator" should "start and register the ActorSystem when bundle starts" in {
|
||||
val system = serviceForType[ActorSystem]
|
||||
val actor = system.actorFor("/user/pong")
|
||||
|
||||
implicit val timeout = Timeout(5 seconds)
|
||||
|
|
@ -56,14 +31,11 @@ class ActorSystemActivatorTest extends FlatSpec {
|
|||
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]
|
||||
it should "stop the ActorSystem when bundle stops" in {
|
||||
val system = serviceForType[ActorSystem]
|
||||
assert(!system.isTerminated)
|
||||
|
||||
activator.stop(context)
|
||||
bundleForName(TEST_BUNDLE_NAME).stop()
|
||||
|
||||
system.awaitTermination()
|
||||
assert(system.isTerminated)
|
||||
|
|
|
|||
150
akka-osgi/src/test/scala/akka/osgi/PojoSRTestSupport.scala
Normal file
150
akka-osgi/src/test/scala/akka/osgi/PojoSRTestSupport.scala
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
package akka.osgi
|
||||
|
||||
import de.kalpatec.pojosr.framework.launch.{ BundleDescriptor, PojoServiceRegistryFactory, ClasspathScanner }
|
||||
|
||||
import scala.collection.JavaConversions.seqAsJavaList
|
||||
import scala.collection.JavaConversions.collectionAsScalaIterable
|
||||
import org.apache.commons.io.IOUtils.copy
|
||||
|
||||
import org.osgi.framework._
|
||||
import java.net.URL
|
||||
|
||||
import java.util.jar.JarInputStream
|
||||
import java.io.{ FileInputStream, FileOutputStream, File }
|
||||
import java.util.{ Date, ServiceLoader, HashMap }
|
||||
import org.scalatest.{ BeforeAndAfterAll, Suite }
|
||||
|
||||
/**
|
||||
* Trait that provides support for building akka-osgi tests using PojoSR
|
||||
*/
|
||||
trait PojoSRTestSupport extends Suite with BeforeAndAfterAll {
|
||||
|
||||
val MAX_WAIT_TIME = 8000;
|
||||
val START_WAIT_TIME = 100;
|
||||
|
||||
implicit def buildBundleDescriptor(builder: BundleDescriptorBuilder) = builder.build
|
||||
|
||||
/**
|
||||
* All bundles being found on the test classpath are automatically installed and started in the PojoSR runtime.
|
||||
* Implement this to define the extra bundles that should be available for testing.
|
||||
*/
|
||||
val testBundles: Seq[BundleDescriptor]
|
||||
|
||||
lazy val context: BundleContext = {
|
||||
val config = new HashMap[String, AnyRef]();
|
||||
System.setProperty("org.osgi.framework.storage", "target/akka-osgi/" + System.currentTimeMillis)
|
||||
|
||||
val bundles = new ClasspathScanner().scanForBundles()
|
||||
bundles.addAll(testBundles)
|
||||
config.put(PojoServiceRegistryFactory.BUNDLE_DESCRIPTORS, bundles);
|
||||
|
||||
val loader: ServiceLoader[PojoServiceRegistryFactory] = ServiceLoader.load(classOf[PojoServiceRegistryFactory])
|
||||
|
||||
val registry = loader.iterator.next.newPojoServiceRegistry(config)
|
||||
registry.getBundleContext
|
||||
}
|
||||
|
||||
// Ensure bundles get stopped at the end of the test to release resources and stop threads
|
||||
override protected def afterAll() = context.getBundles.foreach(_.stop)
|
||||
|
||||
/**
|
||||
* Convenience method to find a bundle by symbolic name
|
||||
*/
|
||||
def bundleForName(name: String) = context.getBundles.find(_.getSymbolicName == name) match {
|
||||
case Some(bundle) ⇒ bundle
|
||||
case None ⇒ fail("Unable to find bundle with symbolic name %s".format(name))
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to find a service by interface. If the service is not already available in the OSGi Service
|
||||
* Registry, this method will wait for a few seconds for the service to appear.
|
||||
*/
|
||||
def serviceForType[T](implicit manifest: Manifest[T]): T = {
|
||||
val reference = awaitReference(manifest.erasure)
|
||||
context.getService(reference).asInstanceOf[T]
|
||||
}
|
||||
|
||||
def awaitReference(serviceType: Class[_]): ServiceReference = awaitReference(serviceType, START_WAIT_TIME)
|
||||
|
||||
def awaitReference(serviceType: Class[_], wait: Long): ServiceReference = {
|
||||
val option = Option(context.getServiceReference(serviceType.getName))
|
||||
option match {
|
||||
case Some(reference) ⇒ reference;
|
||||
case None if (wait > MAX_WAIT_TIME) ⇒ fail("Gave up waiting for service of type %s".format(serviceType))
|
||||
case None ⇒ {
|
||||
Thread.sleep(wait);
|
||||
awaitReference(serviceType, wait * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object PojoSRTestSupport {
|
||||
|
||||
/**
|
||||
* Convenience method to define additional test bundles
|
||||
*/
|
||||
def bundle(name: String) = new BundleDescriptorBuilder(name)
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to make it easier to define test bundles
|
||||
*/
|
||||
class BundleDescriptorBuilder(name: String) {
|
||||
|
||||
import org.ops4j.pax.tinybundles.core.TinyBundles
|
||||
|
||||
val tinybundle = TinyBundles.bundle.set(Constants.BUNDLE_SYMBOLICNAME, name)
|
||||
|
||||
def withBlueprintFile(name: String, contents: URL) =
|
||||
returnBuilder(tinybundle.add("OSGI-INF/blueprint/%s".format(name), contents))
|
||||
|
||||
def withBlueprintFile(contents: URL): BundleDescriptorBuilder = withBlueprintFile(filename(contents), contents)
|
||||
|
||||
def withActivator(activator: Class[_ <: BundleActivator]) =
|
||||
returnBuilder(tinybundle.set(Constants.BUNDLE_ACTIVATOR, activator.getName))
|
||||
|
||||
def returnBuilder(block: ⇒ Unit) = {
|
||||
block
|
||||
this
|
||||
}
|
||||
|
||||
def build = {
|
||||
val file: File = tinybundleToJarFile(name)
|
||||
|
||||
new BundleDescriptor(
|
||||
getClass().getClassLoader(),
|
||||
new URL("jar:" + file.toURI().toString() + "!/"),
|
||||
extractHeaders(file));
|
||||
}
|
||||
|
||||
def extractHeaders(file: File): HashMap[String, String] = {
|
||||
val headers = new HashMap[String, String]();
|
||||
|
||||
val jis = new JarInputStream(new FileInputStream(file));
|
||||
try {
|
||||
for (entry ← jis.getManifest().getMainAttributes().entrySet()) {
|
||||
headers.put(entry.getKey().toString(), entry.getValue().toString());
|
||||
}
|
||||
} finally {
|
||||
jis.close()
|
||||
}
|
||||
|
||||
headers
|
||||
}
|
||||
|
||||
def tinybundleToJarFile(name: String): File = {
|
||||
val file = new File("target/%s-%tQ.jar".format(name, new Date()));
|
||||
val fos = new FileOutputStream(file);
|
||||
try {
|
||||
copy(tinybundle.build(), fos);
|
||||
} finally {
|
||||
fos.close();
|
||||
}
|
||||
file
|
||||
}
|
||||
|
||||
private[this] def filename(url: URL) = url.getFile.split("/").last
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
package akka.osgi.blueprint.aries
|
||||
|
||||
import org.scalatest.FlatSpec
|
||||
import akka.actor.ActorSystem
|
||||
import de.kalpatec.pojosr.framework.launch.BundleDescriptor
|
||||
import akka.osgi.PojoSRTestSupport
|
||||
import akka.osgi.PojoSRTestSupport.bundle
|
||||
import akka.osgi.test.ActorSystemAwareBean
|
||||
|
||||
/**
|
||||
* Test cases for {@link ActorSystemActivator}
|
||||
*/
|
||||
object NamespaceHandlerTest {
|
||||
|
||||
/*
|
||||
* Bundle-SymbolicName to easily find our test bundle
|
||||
*/
|
||||
val TEST_BUNDLE_NAME = "akka.osgi.test.aries.namespace"
|
||||
|
||||
/*
|
||||
* Bundle descriptor representing the akka-osgi bundle itself
|
||||
*/
|
||||
val AKKA_OSGI_BLUEPRINT =
|
||||
bundle("akka-osgi").withBlueprintFile(getClass.getResource("/OSGI-INF/blueprint/akka-namespacehandler.xml"))
|
||||
|
||||
}
|
||||
|
||||
class SimpleNamespaceHandlerTest extends FlatSpec with PojoSRTestSupport {
|
||||
|
||||
import NamespaceHandlerTest._
|
||||
|
||||
val testBundles: Seq[BundleDescriptor] = Seq(
|
||||
AKKA_OSGI_BLUEPRINT,
|
||||
bundle(TEST_BUNDLE_NAME).withBlueprintFile(getClass.getResource("simple.xml")))
|
||||
|
||||
"simple.xml" should "set up ActorSystem when bundle starts" in {
|
||||
val system = serviceForType[ActorSystem]
|
||||
assert(system != null)
|
||||
}
|
||||
|
||||
it should "stop the ActorSystem when bundle stops" in {
|
||||
val system = serviceForType[ActorSystem]
|
||||
assert(!system.isTerminated)
|
||||
|
||||
bundleForName(TEST_BUNDLE_NAME).stop()
|
||||
|
||||
system.awaitTermination()
|
||||
assert(system.isTerminated)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ConfigNamespaceHandlerTest extends FlatSpec with PojoSRTestSupport {
|
||||
|
||||
import NamespaceHandlerTest._
|
||||
|
||||
val testBundles: Seq[BundleDescriptor] = Seq(
|
||||
AKKA_OSGI_BLUEPRINT,
|
||||
bundle(TEST_BUNDLE_NAME).withBlueprintFile(getClass.getResource("config.xml")))
|
||||
|
||||
"config.xml" should "set up ActorSystem when bundle starts" in {
|
||||
val system = serviceForType[ActorSystem]
|
||||
assert(system != null)
|
||||
|
||||
assert(system.settings.config.getString("some.config.key") == "value")
|
||||
}
|
||||
|
||||
it should "stop the ActorSystem when bundle stops" in {
|
||||
val system = serviceForType[ActorSystem]
|
||||
assert(!system.isTerminated)
|
||||
|
||||
bundleForName(TEST_BUNDLE_NAME).stop()
|
||||
|
||||
system.awaitTermination()
|
||||
assert(system.isTerminated)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class DependencyInjectionNamespaceHandlerTest extends FlatSpec with PojoSRTestSupport {
|
||||
|
||||
import NamespaceHandlerTest._
|
||||
|
||||
val testBundles: Seq[BundleDescriptor] = Seq(
|
||||
AKKA_OSGI_BLUEPRINT,
|
||||
bundle(TEST_BUNDLE_NAME).withBlueprintFile(getClass.getResource("injection.xml")))
|
||||
|
||||
"injection.xml" should "set up bean containing ActorSystem" in {
|
||||
val bean = serviceForType[ActorSystemAwareBean]
|
||||
assert(bean != null)
|
||||
assert(bean.system != null)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package akka.osgi.test
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
|
||||
/**
|
||||
* Just a simple POJO that can contain an actor system.
|
||||
* Used for testing dependency injection with Blueprint
|
||||
*/
|
||||
class ActorSystemAwareBean(val system: ActorSystem) {
|
||||
|
||||
}
|
||||
22
akka-osgi/src/test/scala/akka/osgi/test/PingPong.scala
Normal file
22
akka-osgi/src/test/scala/akka/osgi/test/PingPong.scala
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
package akka.osgi.test
|
||||
|
||||
import akka.actor.Actor
|
||||
|
||||
/**
|
||||
* Simple ping-pong actor, used for testing
|
||||
*/
|
||||
object PingPong {
|
||||
|
||||
abstract class TestMessage
|
||||
|
||||
case object Ping extends TestMessage
|
||||
case object Pong extends TestMessage
|
||||
|
||||
class PongActor extends Actor {
|
||||
def receive = {
|
||||
case Ping ⇒
|
||||
sender ! Pong
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package akka.osgi.test
|
||||
|
||||
import akka.osgi.ActorSystemActivator
|
||||
import akka.actor.{ Props, ActorSystem }
|
||||
import PingPong._
|
||||
|
||||
/**
|
||||
* Sample ActorSystemActivator implementation used for testing purposes
|
||||
*/
|
||||
class TestActorSystemActivator extends ActorSystemActivator {
|
||||
|
||||
def configure(system: ActorSystem) {
|
||||
system.actorOf(Props(new PongActor), name = "pong")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -480,7 +480,7 @@ object Dependencies {
|
|||
|
||||
val camel = Seq(camelCore, Test.scalatest, Test.junit, Test.mockito)
|
||||
|
||||
val osgi = Seq(osgiCore, ariesBlueprint, Runtime.logback, Test.pojosr, Test.tinybundles, Test.scalatest, Test.junit)
|
||||
val osgi = Seq(osgiCore, ariesBlueprint, Runtime.logback, Test.ariesProxy, Test.commonsIo, Test.pojosr, Test.tinybundles, Test.scalatest, Test.junit)
|
||||
|
||||
val tutorials = Seq(Test.scalatest, Test.junit)
|
||||
|
||||
|
|
@ -505,7 +505,7 @@ object Dependency {
|
|||
}
|
||||
|
||||
// Compile
|
||||
val ariesBlueprint = "org.apache.aries.blueprint" % "org.apache.aries.blueprint" % "0.3.1" // ApacheV2
|
||||
val ariesBlueprint = "org.apache.aries.blueprint" % "org.apache.aries.blueprint" % "0.3.2" // ApacheV2
|
||||
val config = "com.typesafe" % "config" % "0.4.1" // ApacheV2
|
||||
val camelCore = "org.apache.camel" % "camel-core" % V.Camel // ApacheV2
|
||||
val netty = "io.netty" % "netty" % V.Netty // ApacheV2
|
||||
|
|
@ -518,12 +518,13 @@ object Dependency {
|
|||
// Test
|
||||
|
||||
object Test {
|
||||
val ariesProxy = "org.apache.aries.proxy" % "org.apache.aries.proxy.impl" % "0.3" % "test" // ApacheV2
|
||||
val commonsMath = "org.apache.commons" % "commons-math" % "2.1" % "test" // ApacheV2
|
||||
val commonsIo = "commons-io" % "commons-io" % "2.0.1" % "test"// ApacheV2
|
||||
val commonsIo = "commons-io" % "commons-io" % "2.0.1" % "test"// ApacheV2
|
||||
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 pojosr = "com.googlecode.pojosr" % "de.kalpatec.pojosr.framework" % "0.1.4" % "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
|
||||
|
|
@ -548,7 +549,10 @@ object OSGi {
|
|||
|
||||
val mailboxesCommon = exports(Seq("akka.actor.mailbox.*"))
|
||||
|
||||
val osgi = exports(Seq("akka.osgi.*"))
|
||||
val osgi = exports(Seq("akka.osgi.*")) ++ Seq(
|
||||
OsgiKeys.importPackage := Seq("org.apache.aries.blueprint.*;resolution:=optional",
|
||||
"org.osgi.service.blueprint.*;resolution:=optional") ++ defaultImports
|
||||
)
|
||||
|
||||
val remote = exports(Seq("akka.remote.*", "akka.routing.*", "akka.serialization.*"))
|
||||
|
||||
|
|
@ -559,10 +563,11 @@ object OSGi {
|
|||
val zeroMQ = exports(Seq("akka.zeromq.*"))
|
||||
|
||||
def exports(packages: Seq[String]) = osgiSettings ++ Seq(
|
||||
OsgiKeys.importPackage := Seq("!sun.misc", akkaImport(), configImport(), scalaImport(), "*"),
|
||||
OsgiKeys.importPackage := defaultImports,
|
||||
OsgiKeys.exportPackage := packages
|
||||
)
|
||||
|
||||
def defaultImports = Seq("!sun.misc", akkaImport(), configImport(), scalaImport(), "*")
|
||||
def akkaImport(packageName: String = "akka.*") = "%s;version=\"[2.1,2.2)\"".format(packageName)
|
||||
def configImport(packageName: String = "com.typesafe.config.*") = "%s;version=\"[0.4.1,0.5)\"".format(packageName)
|
||||
def scalaImport(packageName: String = "scala.*") = "%s;version=\"[2.9.2,2.10)\"".format(packageName)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue