closing ticket 377, 376 and 200

This commit is contained in:
Michael Kober 2010-08-12 15:54:46 +02:00
parent ef79befe9a
commit 00e215a106
25 changed files with 462 additions and 135 deletions

View file

@ -161,6 +161,52 @@
</xsd:attribute>
</xsd:complexType>
<!-- untyped actor -->
<xsd:complexType name="untyped-actor-type">
<xsd:sequence>
<xsd:element name="remote" type="remote-type" minOccurs="0" maxOccurs="1"/>
<xsd:element name="dispatcher" type="dispatcher-type" minOccurs="0" maxOccurs="1"/>
<xsd:element ref="dispatcher" minOccurs="0" maxOccurs="1"/>
<xsd:element ref="beans:property" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:ID"/>
<xsd:attribute name="implementation" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation>
Name of the implementation class.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="timeout" type="xsd:long" use="required">
<xsd:annotation>
<xsd:documentation>
The default timeout for '!!' invocations.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="transactional" type="xsd:boolean">
<xsd:annotation>
<xsd:documentation>
Set this to true if messages should have REQUIRES_NEW semantics.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="lifecycle" type="lifecycle-type">
<xsd:annotation>
<xsd:documentation>
Defines the lifecycle, can be either 'permanent' or 'temporary'.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="scope" type="scope-enum-type">
<xsd:annotation>
<xsd:documentation>
Supported scopes are 'singleton' and 'prototype'.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<!-- trap exits -->
<xsd:complexType name="trap-exits-type">
<xsd:choice minOccurs="1" maxOccurs="unbounded">
@ -175,6 +221,13 @@
</xsd:choice>
</xsd:complexType>
<!-- untyped actors -->
<xsd:complexType name="untyped-actors-type">
<xsd:choice minOccurs="1" maxOccurs="unbounded">
<xsd:element name="untyped-actor" type="untyped-actor-type"/>
</xsd:choice>
</xsd:complexType>
<!-- Supervisor strategy -->
<xsd:complexType name="strategy-type">
<xsd:sequence>
@ -208,6 +261,7 @@
<xsd:all>
<xsd:element name="restart-strategy" type="strategy-type" minOccurs="1" maxOccurs="1"/>
<xsd:element name="typed-actors" type="typed-actors-type" minOccurs="0" maxOccurs="1"/>
<xsd:element name="untyped-actors" type="untyped-actors-type" minOccurs="0" maxOccurs="1"/>
<xsd:element name="supervision" type="supervision-type" minOccurs="0"/>
</xsd:all>
<xsd:attribute name="id" type="xsd:ID"/>
@ -227,6 +281,9 @@
<!-- TypedActor -->
<xsd:element name="typed-actor" type="typed-actor-type"/>
<!-- UntypedActor -->
<xsd:element name="untyped-actor" type="untyped-actor-type"/>
<!-- Dispatcher -->
<xsd:element name="dispatcher" type="dispatcher-type"/>

View file

@ -20,7 +20,7 @@ import org.springframework.context.{ApplicationContext,ApplicationContextAware}
import org.springframework.util.ReflectionUtils
import org.springframework.util.StringUtils
import se.scalablesolutions.akka.actor.{AspectInitRegistry, TypedActorConfiguration, TypedActor}
import se.scalablesolutions.akka.actor.{AspectInitRegistry, TypedActorConfiguration, TypedActor, UntypedActor, UntypedActorRef}
import se.scalablesolutions.akka.dispatch.MessageDispatcher
import se.scalablesolutions.akka.util.{Logging, Duration}
@ -34,17 +34,18 @@ class AkkaBeansException(message: String, cause:Throwable) extends BeansExceptio
}
/**
* Factory bean for typed actors.
* Factory bean for typed and untyped actors.
*
* @author michaelkober
* @author <a href="johan.rask@jayway.com">Johan Rask</a>
* @author Martin Krasser
* @author <a href="http://jonasboner.com">Jonas Bon&#233;r</a>
*/
class TypedActorFactoryBean extends AbstractFactoryBean[AnyRef] with Logging with ApplicationContextAware {
class ActorFactoryBean extends AbstractFactoryBean[AnyRef] with Logging with ApplicationContextAware {
import StringReflect._
import AkkaSpringConfigurationTags._
@BeanProperty var typed: String = ""
@BeanProperty var interface: String = ""
@BeanProperty var implementation: String = ""
@BeanProperty var timeout: Long = _
@ -82,15 +83,57 @@ class TypedActorFactoryBean extends AbstractFactoryBean[AnyRef] with Logging wit
if (isRemote) argumentList += "r"
if (hasInterface) argumentList += "i"
if (hasDispatcher) argumentList += "d"
val ref = create(argumentList)
setProperties(AspectInitRegistry.initFor(ref).targetInstance)
val ref = typed match {
case TYPED_ACTOR_TAG => val typedActor = createTypedInstance(argumentList)
setProperties(AspectInitRegistry.initFor(typedActor).targetInstance)
typedActor
case UNTYPED_ACTOR_TAG => createUntypedInstance(argumentList)
}
ref
}
private[akka] def createTypedInstance(argList: String) : AnyRef = {
if (interface == null || interface == "") throw new AkkaBeansException(
"The 'interface' part of the 'akka:actor' element in the Spring config file can't be null or empty string")
if (implementation == null || implementation == "") throw new AkkaBeansException(
"The 'implementation' part of the 'akka:typed-actor' element in the Spring config file can't be null or empty string")
argList match {
case "ri" => TypedActor.newInstance(interface.toClass, implementation.toClass, createConfig.makeRemote(host, port))
case "i" => TypedActor.newInstance(interface.toClass, implementation.toClass, createConfig)
case "id" => TypedActor.newInstance(interface.toClass, implementation.toClass, createConfig.dispatcher(dispatcherInstance))
case "rid" => TypedActor.newInstance(interface.toClass, implementation.toClass, createConfig.makeRemote(host, port).dispatcher(dispatcherInstance))
case _ => TypedActor.newInstance(interface.toClass, implementation.toClass, createConfig)
}
}
private[akka] def createUntypedInstance(args: String) : UntypedActorRef = {
if (implementation == null || implementation == "") throw new AkkaBeansException(
"The 'implementation' part of the 'akka:untyped-actor' element in the Spring config file can't be null or empty string")
val actorRef = UntypedActor.actorOf(implementation.toClass)
if (timeout > 0) {
actorRef.setTimeout(timeout)
}
if (transactional) {
actorRef.makeTransactionRequired
}
if (isRemote) {
actorRef.makeRemote(host, port)
}
if (hasDispatcher) {
actorRef.setDispatcher(dispatcherInstance)
}
actorRef
}
/**
* Stop the typed actor if it is a singleton.
*/
override def destroyInstance(instance: AnyRef) = TypedActor.stop(instance)
override def destroyInstance(instance: AnyRef) {
typed match {
case TYPED_ACTOR_TAG => TypedActor.stop(instance)
case UNTYPED_ACTOR_TAG => instance.asInstanceOf[UntypedActorRef].stop
}
}
private def setProperties(ref: AnyRef): AnyRef = {
if (hasSetDependecies) return ref
@ -114,22 +157,6 @@ class TypedActorFactoryBean extends AbstractFactoryBean[AnyRef] with Logging wit
ref
}
private[akka] def create(argList: String): AnyRef = {
if (interface == null || interface == "") throw new AkkaBeansException(
"The 'interface' part of the 'akka:actor' element in the Spring config file can't be null or empty string")
if (implementation == null || implementation == "") throw new AkkaBeansException(
"The 'implementation' part of the 'akka:typed-actor' element in the Spring config file can't be null or empty string")
argList match {
case "ri" => TypedActor.newInstance(interface.toClass, implementation.toClass, createConfig.makeRemote(host, port))
case "i" => TypedActor.newInstance(interface.toClass, implementation.toClass, createConfig)
case "id" => TypedActor.newInstance(interface.toClass, implementation.toClass, createConfig.dispatcher(dispatcherInstance))
case "rid" => TypedActor.newInstance(interface.toClass, implementation.toClass, createConfig.makeRemote(host, port).dispatcher(dispatcherInstance))
case _ => TypedActor.newInstance(interface.toClass, implementation.toClass, createConfig)
// case "rd" => TypedActor.newInstance(implementation.toClass, createConfig.makeRemote(host, port).dispatcher(dispatcherInstance))
// case "r" => TypedActor.newInstance(implementation.toClass, createConfig.makeRemote(host, port))
// case "d" => TypedActor.newInstance(implementation.toClass, createConfig.dispatcher(dispatcherInstance))
}
}
private[akka] def createConfig: TypedActorConfiguration = {
val config = new TypedActorConfiguration().timeout(Duration(timeout, "millis"))
@ -148,6 +175,12 @@ class TypedActorFactoryBean extends AbstractFactoryBean[AnyRef] with Logging wit
private[akka] def dispatcherInstance: MessageDispatcher = {
import DispatcherFactoryBean._
if (dispatcher.dispatcherType != THREAD_BASED) {
createNewInstance(dispatcher)
} else {
println("### create thread based dispatcher")
createNewInstance(dispatcher)
}
}
}

View file

@ -15,7 +15,7 @@ import se.scalablesolutions.akka.actor.IllegalActorStateException
* @author <a href="johan.rask@jayway.com">Johan Rask</a>
* @author Martin Krasser
*/
trait TypedActorParser extends BeanParser with DispatcherParser {
trait ActorParser extends BeanParser with DispatcherParser {
import AkkaSpringConfigurationTags._
/**
@ -23,8 +23,8 @@ trait TypedActorParser extends BeanParser with DispatcherParser {
* @param element dom element to parse
* @return configuration for the typed actor
*/
def parseTypedActor(element: Element): TypedActorProperties = {
val objectProperties = new TypedActorProperties()
def parseActor(element: Element): ActorProperties = {
val objectProperties = new ActorProperties()
val remoteElement = DomUtils.getChildElementByTagName(element, REMOTE_TAG);
val dispatcherElement = DomUtils.getChildElementByTagName(element, DISPATCHER_TAG)
val propertyEntries = DomUtils.getChildElementsByTagName(element,PROPERTYENTRY_TAG)

View file

@ -12,7 +12,8 @@ import AkkaSpringConfigurationTags._
* @author michaelkober
* @author Martin Krasser
*/
class TypedActorProperties {
class ActorProperties {
var typed: String = ""
var target: String = ""
var timeout: Long = _
var interface: String = ""
@ -30,6 +31,7 @@ class TypedActorProperties {
* @param builder bean definition builder
*/
def setAsProperties(builder: BeanDefinitionBuilder) {
builder.addPropertyValue("typed", typed)
builder.addPropertyValue(HOST, host)
builder.addPropertyValue(PORT, port)
builder.addPropertyValue(TIMEOUT, timeout)

View file

@ -13,6 +13,7 @@ import AkkaSpringConfigurationTags._
class AkkaNamespaceHandler extends NamespaceHandlerSupport {
def init = {
registerBeanDefinitionParser(TYPED_ACTOR_TAG, new TypedActorBeanDefinitionParser());
registerBeanDefinitionParser(UNTYPED_ACTOR_TAG, new UntypedActorBeanDefinitionParser());
registerBeanDefinitionParser(SUPERVISION_TAG, new SupervisionBeanDefinitionParser());
registerBeanDefinitionParser(DISPATCHER_TAG, new DispatcherBeanDefinitionParser());
registerBeanDefinitionParser(CAMEL_SERVICE_TAG, new CamelServiceBeanDefinitionParser);

View file

@ -14,16 +14,18 @@ object AkkaSpringConfigurationTags {
//
// top level tags
val TYPED_ACTOR_TAG = "typed-actor"
val UNTYPED_ACTOR_TAG = "untyped-actor"
val SUPERVISION_TAG = "supervision"
val DISPATCHER_TAG = "dispatcher"
val PROPERTYENTRY_TAG = "property"
val CAMEL_SERVICE_TAG = "camel-service"
// typed-actor sub tags
// actor sub tags
val REMOTE_TAG = "remote"
// superivision sub tags
val TYPED_ACTORS_TAG = "typed-actors"
val UNTYPED_ACTORS_TAG = "untyped-actors"
val STRATEGY_TAG = "restart-strategy"
val TRAP_EXISTS_TAG = "trap-exits"
val TRAP_EXIT_TAG = "trap-exit"
@ -36,7 +38,7 @@ object AkkaSpringConfigurationTags {
// --- ATTRIBUTES
//
// typed actor attributes
// actor attributes
val TIMEOUT = "timeout"
val IMPLEMENTATION = "implementation"
val INTERFACE = "interface"

View file

@ -12,7 +12,7 @@ import org.springframework.beans.factory.xml.{ParserContext, AbstractSingleBeanD
* Parser for custom namespace configuration.
* @author michaelkober
*/
class DispatcherBeanDefinitionParser extends AbstractSingleBeanDefinitionParser with TypedActorParser with DispatcherParser {
class DispatcherBeanDefinitionParser extends AbstractSingleBeanDefinitionParser with ActorParser with DispatcherParser {
/*
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#doParse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext, org.springframework.beans.factory.support.BeanDefinitionBuilder)
*/

View file

@ -1,3 +1,6 @@
/**
* Copyright (C) 2009-2010 Scalable Solutions AB <http://scalablesolutions.se>
*/
package se.scalablesolutions.akka.spring
import org.springframework.beans.factory.support.BeanDefinitionBuilder
@ -9,7 +12,6 @@ import scala.collection.mutable._
* @author <a href="johan.rask@jayway.com">Johan Rask</a>
*/
class PropertyEntries {
var entryList: ListBuffer[PropertyEntry] = ListBuffer[PropertyEntry]()
def add(entry: PropertyEntry) = {

View file

@ -1,3 +1,6 @@
/**
* Copyright (C) 2009-2010 Scalable Solutions AB <http://scalablesolutions.se>
*/
package se.scalablesolutions.akka.spring
/**
@ -5,7 +8,6 @@ package se.scalablesolutions.akka.spring
* @author <a href="johan.rask@jayway.com">Johan Rask</a>
*/
class PropertyEntry {
var name: String = _
var value: String = null
var ref: String = null

View file

@ -18,7 +18,7 @@ import org.springframework.util.xml.DomUtils
* Parser for custom namespace for Akka declarative supervisor configuration.
* @author michaelkober
*/
class SupervisionBeanDefinitionParser extends AbstractSingleBeanDefinitionParser with TypedActorParser {
class SupervisionBeanDefinitionParser extends AbstractSingleBeanDefinitionParser with ActorParser {
/* (non-Javadoc)
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#doParse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext, org.springframework.beans.factory.support.BeanDefinitionBuilder)
*/
@ -30,10 +30,20 @@ class SupervisionBeanDefinitionParser extends AbstractSingleBeanDefinitionParser
* made accessible for testing
*/
private[akka] def parseSupervisor(element: Element, builder: BeanDefinitionBuilder) {
val strategyElement = mandatoryElement(element, STRATEGY_TAG);
val typedActorsElement = mandatoryElement(element, TYPED_ACTORS_TAG);
val strategyElement = mandatoryElement(element, STRATEGY_TAG)
val typedActorsElement = DomUtils.getChildElementByTagName(element, TYPED_ACTORS_TAG)
val untypedActorsElement = DomUtils.getChildElementByTagName(element, UNTYPED_ACTORS_TAG)
if ((typedActorsElement == null) && (untypedActorsElement == null)) {
throw new IllegalArgumentException("One of 'akka:typed-actors' or 'akka:untyped-actors' needed.")
}
parseRestartStrategy(strategyElement, builder)
if (typedActorsElement != null) {
builder.addPropertyValue("typed", AkkaSpringConfigurationTags.TYPED_ACTOR_TAG)
parseTypedActorList(typedActorsElement, builder)
} else {
builder.addPropertyValue("typed", AkkaSpringConfigurationTags.UNTYPED_ACTOR_TAG)
parseUntypedActorList(untypedActorsElement, builder)
}
}
private[akka] def parseRestartStrategy(element: Element, builder: BeanDefinitionBuilder) {
@ -48,8 +58,14 @@ class SupervisionBeanDefinitionParser extends AbstractSingleBeanDefinitionParser
private[akka] def parseTypedActorList(element: Element, builder: BeanDefinitionBuilder) {
val typedActors = DomUtils.getChildElementsByTagName(element, TYPED_ACTOR_TAG).toArray.toList.asInstanceOf[List[Element]]
val typedActorProperties = typedActors.map(parseTypedActor(_))
builder.addPropertyValue("supervised", typedActorProperties)
val actorProperties = typedActors.map(parseActor(_))
builder.addPropertyValue("supervised", actorProperties)
}
private[akka] def parseUntypedActorList(element: Element, builder: BeanDefinitionBuilder) {
val untypedActors = DomUtils.getChildElementsByTagName(element, UNTYPED_ACTOR_TAG).toArray.toList.asInstanceOf[List[Element]]
val actorProperties = untypedActors.map(parseActor(_))
builder.addPropertyValue("supervised", actorProperties)
}
private def parseTrapExits(element: Element): Array[Class[_ <: Throwable]] = {

View file

@ -6,6 +6,8 @@ package se.scalablesolutions.akka.spring
import org.springframework.beans.factory.config.AbstractFactoryBean
import se.scalablesolutions.akka.config.TypedActorConfigurator
import se.scalablesolutions.akka.config.JavaConfig._
import se.scalablesolutions.akka.config.ScalaConfig.{Supervise, Server, SupervisorConfig, RemoteAddress => SRemoteAddress}
import se.scalablesolutions.akka.actor.{Supervisor, SupervisorFactory, UntypedActor}
import AkkaSpringConfigurationTags._
import reflect.BeanProperty
@ -14,31 +16,45 @@ import reflect.BeanProperty
* Factory bean for supervisor configuration.
* @author michaelkober
*/
class SupervisionFactoryBean extends AbstractFactoryBean[TypedActorConfigurator] {
class SupervisionFactoryBean extends AbstractFactoryBean[AnyRef] {
@BeanProperty var restartStrategy: RestartStrategy = _
@BeanProperty var supervised: List[TypedActorProperties] = _
@BeanProperty var supervised: List[ActorProperties] = _
@BeanProperty var typed: String = ""
/*
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
*/
def getObjectType: Class[TypedActorConfigurator] = classOf[TypedActorConfigurator]
def getObjectType: Class[AnyRef] = classOf[AnyRef]
/*
* @see org.springframework.beans.factory.config.AbstractFactoryBean#createInstance()
*/
def createInstance: TypedActorConfigurator = {
val configurator = new TypedActorConfigurator()
def createInstance: AnyRef = typed match {
case AkkaSpringConfigurationTags.TYPED_ACTOR_TAG => createInstanceForTypedActors
case AkkaSpringConfigurationTags.UNTYPED_ACTOR_TAG => createInstanceForUntypedActors
}
private def createInstanceForTypedActors() : TypedActorConfigurator = {
val configurator = new TypedActorConfigurator()
configurator.configure(
restartStrategy,
supervised.map(createComponent(_)).toArray
).supervise
}
private def createInstanceForUntypedActors() : Supervisor = {
val factory = new SupervisorFactory(
new SupervisorConfig(
restartStrategy.transform,
supervised.map(createSupervise(_))))
factory.newInstance
}
/**
* Create configuration for TypedActor
*/
private[akka] def createComponent(props: TypedActorProperties): Component = {
private[akka] def createComponent(props: ActorProperties): Component = {
import StringReflect._
val lifeCycle = if (!props.lifecycle.isEmpty && props.lifecycle.equalsIgnoreCase(VAL_LIFECYCYLE_TEMPORARY)) new LifeCycle(new Temporary()) else new LifeCycle(new Permanent())
val isRemote = (props.host != null) && (!props.host.isEmpty)
@ -58,4 +74,28 @@ class SupervisionFactoryBean extends AbstractFactoryBean[TypedActorConfigurator]
}
}
}
/**
* Create configuration for UntypedActor
*/
private[akka] def createSupervise(props: ActorProperties): Server = {
import StringReflect._
val lifeCycle = if (!props.lifecycle.isEmpty && props.lifecycle.equalsIgnoreCase(VAL_LIFECYCYLE_TEMPORARY)) new LifeCycle(new Temporary()) else new LifeCycle(new Permanent())
val isRemote = (props.host != null) && (!props.host.isEmpty)
val untypedActorRef = UntypedActor.actorOf(props.target.toClass)
if (props.timeout > 0) {
untypedActorRef.setTimeout(props.timeout)
}
if (props.transactional) {
untypedActorRef.makeTransactionRequired
}
val supervise = if (isRemote) {
val remote = new SRemoteAddress(props.host, props.port)
Supervise(untypedActorRef.actorRef, lifeCycle.transform, remote)
} else {
Supervise(untypedActorRef.actorRef, lifeCycle.transform)
}
supervise
}
}

View file

@ -6,6 +6,7 @@ package se.scalablesolutions.akka.spring
import org.springframework.beans.factory.support.BeanDefinitionBuilder
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser
import org.springframework.beans.factory.xml.ParserContext
import AkkaSpringConfigurationTags._
import org.w3c.dom.Element
@ -13,17 +14,18 @@ import org.w3c.dom.Element
* Parser for custom namespace configuration.
* @author michaelkober
*/
class TypedActorBeanDefinitionParser extends AbstractSingleBeanDefinitionParser with TypedActorParser {
class TypedActorBeanDefinitionParser extends AbstractSingleBeanDefinitionParser with ActorParser {
/*
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#doParse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext, org.springframework.beans.factory.support.BeanDefinitionBuilder)
*/
override def doParse(element: Element, parserContext: ParserContext, builder: BeanDefinitionBuilder) {
val typedActorConf = parseTypedActor(element)
val typedActorConf = parseActor(element)
typedActorConf.typed = TYPED_ACTOR_TAG
typedActorConf.setAsProperties(builder)
}
/*
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#getBeanClass(org.w3c.dom.Element)
*/
override def getBeanClass(element: Element): Class[_] = classOf[TypedActorFactoryBean]
override def getBeanClass(element: Element): Class[_] = classOf[ActorFactoryBean]
}

View file

@ -0,0 +1,31 @@
/**
* Copyright (C) 2009-2010 Scalable Solutions AB <http://scalablesolutions.se>
*/
package se.scalablesolutions.akka.spring
import org.springframework.beans.factory.support.BeanDefinitionBuilder
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser
import org.springframework.beans.factory.xml.ParserContext
import AkkaSpringConfigurationTags._
import org.w3c.dom.Element
/**
* Parser for custom namespace configuration.
* @author michaelkober
*/
class UntypedActorBeanDefinitionParser extends AbstractSingleBeanDefinitionParser with ActorParser {
/*
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#doParse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext, org.springframework.beans.factory.support.BeanDefinitionBuilder)
*/
override def doParse(element: Element, parserContext: ParserContext, builder: BeanDefinitionBuilder) {
val untypedActorConf = parseActor(element)
untypedActorConf.typed = UNTYPED_ACTOR_TAG
untypedActorConf.setAsProperties(builder)
}
/*
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#getBeanClass(org.w3c.dom.Element)
*/
override def getBeanClass(element: Element): Class[_] = classOf[ActorFactoryBean]
}

View file

@ -0,0 +1,33 @@
package se.scalablesolutions.akka.spring.foo;
import se.scalablesolutions.akka.actor.UntypedActor;
import se.scalablesolutions.akka.actor.UntypedActorRef;
/**
* test class
*/
public class PingActor extends UntypedActor {
private String longRunning() {
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
}
return "this took long";
}
public void onReceive(Object message) throws Exception {
if (message instanceof String) {
System.out.println("Ping received String message: " + message);
if (message.equals("longRunning")) {
System.out.println("### starting pong");
UntypedActorRef pongActor = UntypedActor.actorOf(PongActor.class).start();
pongActor.sendRequestReply("longRunning", getContext());
}
} else {
throw new IllegalArgumentException("Unknown message: " + message);
}
}
}

View file

@ -0,0 +1,18 @@
package se.scalablesolutions.akka.spring.foo;
import se.scalablesolutions.akka.actor.UntypedActor;
/**
* test class
*/
public class PongActor extends UntypedActor {
public void onReceive(Object message) throws Exception {
if (message instanceof String) {
System.out.println("Pongeceived String message: " + message);
getContext().replyUnsafe(message + " from " + getContext().getUuid());
} else {
throw new IllegalArgumentException("Unknown message: " + message);
}
}
}

View file

@ -33,6 +33,23 @@ http://scalablesolutions.se/akka/akka-0.10.xsd">
</akka:typed-actors>
</akka:supervision>
<akka:supervision id="supervision-untyped-actors">
<akka:restart-strategy failover="AllForOne" retries="3" timerange="1000">
<akka:trap-exits>
<akka:trap-exit>java.io.IOException</akka:trap-exit>
<akka:trap-exit>java.lang.NullPointerException</akka:trap-exit>
</akka:trap-exits>
</akka:restart-strategy>
<akka:untyped-actors>
<akka:untyped-actor implementation="se.scalablesolutions.akka.spring.foo.PingActor"
lifecycle="permanent"
timeout="1000"/>
<akka:untyped-actor implementation="se.scalablesolutions.akka.spring.foo.PongActor"
lifecycle="permanent"
timeout="1000"/>
</akka:untyped-actors>
</akka:supervision>
<!--
<akka:supervision id="supervision2">
<akka:restart-strategy failover="AllForOne" retries="3" timerange="5000">

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:akka="http://www.akkasource.org/schema/akka"
xmlns:beans="http://www.springframework.org/schema/lang"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.akkasource.org/schema/akka
http://scalablesolutions.se/akka/akka-0.10.xsd">
<akka:untyped-actor id="simple-untyped-actor"
implementation="se.scalablesolutions.akka.spring.foo.PingActor"
timeout="1000"/>
<akka:untyped-actor id="simple-untyped-actor-long-timeout"
implementation="se.scalablesolutions.akka.spring.foo.PingActor"
timeout="10000"/>
<akka:untyped-actor id="transactional-untyped-actor"
implementation="se.scalablesolutions.akka.spring.foo.PingActor"
timeout="2000"
transactional="true"/>
<akka:untyped-actor id="remote-untyped-actor"
implementation="se.scalablesolutions.akka.spring.foo.PingActor"
timeout="2000">
<akka:remote host="localhost" port="9999"/>
</akka:untyped-actor>
<akka:untyped-actor id="untyped-actor-with-dispatcher"
implementation="se.scalablesolutions.akka.spring.foo.PingActor"
timeout="1000">
<akka:dispatcher type="executor-based-event-driven-work-stealing" name="myWorkStealingDispatcher"/>
</akka:untyped-actor>
</beans>

View file

@ -16,12 +16,12 @@ import org.scalatest.matchers.ShouldMatchers
* @author michaelkober
*/
@RunWith(classOf[JUnitRunner])
class TypedActorFactoryBeanTest extends Spec with ShouldMatchers with BeforeAndAfterAll {
class ActorFactoryBeanTest extends Spec with ShouldMatchers with BeforeAndAfterAll {
override protected def afterAll = ActorRegistry.shutdownAll
describe("A TypedActorFactoryBean") {
val bean = new TypedActorFactoryBean
describe("A ActorFactoryBean") {
val bean = new ActorFactoryBean
it("should have java getters and setters for all properties") {
bean.setImplementation("java.lang.String")
assert(bean.getImplementation == "java.lang.String")
@ -52,10 +52,11 @@ class TypedActorFactoryBeanTest extends Spec with ShouldMatchers with BeforeAndA
}
it("should create a proxy of type PojoInf") {
val bean = new TypedActorFactoryBean()
val bean = new ActorFactoryBean()
bean.setInterface("se.scalablesolutions.akka.spring.PojoInf")
bean.setImplementation("se.scalablesolutions.akka.spring.Pojo")
bean.timeout = 1000
bean.typed = AkkaSpringConfigurationTags.TYPED_ACTOR_TAG
val entries = new PropertyEntries()
val entry = new PropertyEntry()
entry.name = "stringFromVal"

View file

@ -111,11 +111,13 @@ class DispatcherSpringFeatureTest extends FeatureSpec with ShouldMatchers {
assert(dispatcher.aggregate === false)
}
/*
scenario("get a thread-based-dispatcher from context") {
val context = new ClassPathXmlApplicationContext("/dispatcher-config.xml")
val pojo = context.getBean("typed-actor-with-thread-based-dispatcher").asInstanceOf[IMyPojo]
assert(pojo != null)
}
*/
}

View file

@ -27,7 +27,7 @@ class SupervisionBeanDefinitionParserTest extends Spec with ShouldMatchers {
val builder = BeanDefinitionBuilder.genericBeanDefinition("foo.bar.Foo")
it("should be able to parse typed actor configuration") {
val props = parser.parseTypedActor(createTypedActorElement);
val props = parser.parseActor(createTypedActorElement);
assert(props != null)
assert(props.timeout == 1000)
assert(props.target == "foo.bar.MyPojo")
@ -47,7 +47,7 @@ class SupervisionBeanDefinitionParserTest extends Spec with ShouldMatchers {
it("should parse the supervised typed actors") {
parser.parseSupervisor(createSupervisorElement, builder);
val supervised = builder.getBeanDefinition.getPropertyValues.getPropertyValue("supervised").getValue.asInstanceOf[List[TypedActorProperties]]
val supervised = builder.getBeanDefinition.getPropertyValues.getPropertyValue("supervised").getValue.asInstanceOf[List[ActorProperties]]
assert(supervised != null)
expect(4) { supervised.length }
val iterator = supervised.iterator

View file

@ -18,8 +18,8 @@ class SupervisionFactoryBeanTest extends Spec with ShouldMatchers {
val restartStrategy = new RestartStrategy(new AllForOne(), 3, 1000, Array(classOf[Throwable]))
val typedActors = List(createTypedActorProperties("se.scalablesolutions.akka.spring.Foo", 1000L))
def createTypedActorProperties(target: String, timeout: Long) : TypedActorProperties = {
val properties = new TypedActorProperties()
def createTypedActorProperties(target: String, timeout: Long) : ActorProperties = {
val properties = new ActorProperties()
properties.target = target
properties.timeout = timeout
properties
@ -34,8 +34,8 @@ class SupervisionFactoryBeanTest extends Spec with ShouldMatchers {
assert(bean.getSupervised == typedActors)
}
it("should return the object type TypedActorConfigurator") {
assert(bean.getObjectType == classOf[TypedActorConfigurator])
it("should return the object type AnyRef") {
assert(bean.getObjectType == classOf[AnyRef])
}
}
}

View file

@ -7,6 +7,7 @@ package se.scalablesolutions.akka.spring
import se.scalablesolutions.akka.spring.foo.{IMyPojo, MyPojo, IFoo, IBar}
import se.scalablesolutions.akka.dispatch._
import se.scalablesolutions.akka.config.TypedActorConfigurator
import se.scalablesolutions.akka.actor.Supervisor
import org.scalatest.FeatureSpec
import org.scalatest.matchers.ShouldMatchers
@ -28,7 +29,7 @@ class SupervisorSpringFeatureTest extends FeatureSpec with ShouldMatchers {
feature("Spring configuration") {
scenario("get a supervisor from context") {
scenario("get a supervisor for typed actors from context") {
val context = new ClassPathXmlApplicationContext("/supervisor-config.xml")
val myConfigurator = context.getBean("supervision1").asInstanceOf[TypedActorConfigurator]
// get TypedActors
@ -40,6 +41,12 @@ class SupervisorSpringFeatureTest extends FeatureSpec with ShouldMatchers {
assert(pojo != null)
}
scenario("get a supervisor for untyped actors from context") {
val context = new ClassPathXmlApplicationContext("/supervisor-config.xml")
val supervisor = context.getBean("supervision-untyped-actors").asInstanceOf[Supervisor]
supervisor.children
}
scenario("get a supervisor and dispatcher from context") {
val context = new ClassPathXmlApplicationContext("/supervisor-config.xml")
val myConfigurator = context.getBean("supervision-with-dispatcher").asInstanceOf[TypedActorConfigurator]
@ -47,59 +54,4 @@ class SupervisorSpringFeatureTest extends FeatureSpec with ShouldMatchers {
assert(foo != null)
}
}
/*
@Test
public void testTransactionalState() {
TypedActorConfigurator conf = (TypedActorConfigurator) context
.getBean("supervision2");
StatefulPojo stateful = conf.getInstance(StatefulPojo.class);
stateful.setMapState("testTransactionalState", "some map state");
stateful.setVectorState("some vector state");
stateful.setRefState("some ref state");
assertEquals("some map state", stateful
.getMapState("testTransactionalState"));
assertEquals("some vector state", stateful.getVectorState());
assertEquals("some ref state", stateful.getRefState());
}
@Test
public void testInitTransactionalState() {
StatefulPojo stateful = TypedActor.newInstance(StatefulPojo.class,
1000, true);
assertTrue("should be inititalized", stateful.isInitialized());
}
@Test
public void testSupervisedRemoteTypedActor() {
new Thread(new Runnable() {
public void run() {
RemoteNode.start();
}
}).start();
try {
Thread.currentThread().sleep(1000);
} catch (Exception e) {
}
TypedActorConfigurator conf = new TypedActorConfigurator();
conf.configure(
new RestartStrategy(new AllForOne(), 3, 10000, new Class[] { Exception.class }),
new Component[] {
new Component(
Foo.class,
new LifeCycle(new Permanent()),
10000,
new RemoteAddress("localhost", 9999))
}).supervise();
Foo instance = conf.getInstance(Foo.class);
assertEquals("foo", instance.foo());
}
*/
}

View file

@ -17,7 +17,7 @@ import org.w3c.dom.Element
*/
@RunWith(classOf[JUnitRunner])
class TypedActorBeanDefinitionParserTest extends Spec with ShouldMatchers {
private class Parser extends TypedActorParser
private class Parser extends ActorParser
describe("An TypedActorParser") {
val parser = new Parser()
@ -30,7 +30,7 @@ class TypedActorBeanDefinitionParserTest extends Spec with ShouldMatchers {
<property name="someProp" value="someValue" ref="someRef"/>
</akka:typed-actor>
val props = parser.parseTypedActor(dom(xml).getDocumentElement);
val props = parser.parseActor(dom(xml).getDocumentElement);
assert(props != null)
assert(props.timeout === 1000)
assert(props.target === "foo.bar.MyPojo")
@ -44,7 +44,7 @@ class TypedActorBeanDefinitionParserTest extends Spec with ShouldMatchers {
timeout="1000"
transactional="true"/>
evaluating { parser.parseTypedActor(dom(xml).getDocumentElement) } should produce [IllegalArgumentException]
evaluating { parser.parseActor(dom(xml).getDocumentElement) } should produce [IllegalArgumentException]
}
it("should parse TypedActors configuration with dispatcher") {
@ -52,7 +52,7 @@ class TypedActorBeanDefinitionParserTest extends Spec with ShouldMatchers {
timeout="1000">
<akka:dispatcher type="thread-based" name="my-thread-based-dispatcher"/>
</akka:typed-actor>
val props = parser.parseTypedActor(dom(xml).getDocumentElement);
val props = parser.parseActor(dom(xml).getDocumentElement);
assert(props != null)
assert(props.dispatcher.dispatcherType === "thread-based")
}
@ -62,7 +62,7 @@ class TypedActorBeanDefinitionParserTest extends Spec with ShouldMatchers {
timeout="1000">
<akka:remote host="com.some.host" port="9999"/>
</akka:typed-actor>
val props = parser.parseTypedActor(dom(xml).getDocumentElement);
val props = parser.parseActor(dom(xml).getDocumentElement);
assert(props != null)
assert(props.host === "com.some.host")
assert(props.port === 9999)

View file

@ -0,0 +1,79 @@
/**
* Copyright (C) 2009-2010 Scalable Solutions AB <http://scalablesolutions.se>
*/
package se.scalablesolutions.akka.spring
import foo.PingActor
import se.scalablesolutions.akka.dispatch.ExecutorBasedEventDrivenWorkStealingDispatcher
import se.scalablesolutions.akka.remote.RemoteNode
import se.scalablesolutions.akka.actor.UntypedActorRef
import org.scalatest.FeatureSpec
import org.scalatest.matchers.ShouldMatchers
import org.scalatest.junit.JUnitRunner
import org.junit.runner.RunWith
import org.springframework.context.ApplicationContext
import org.springframework.context.support.ClassPathXmlApplicationContext
/**
* Tests for spring configuration of typed actors.
* @author michaelkober
*/
@RunWith(classOf[JUnitRunner])
class UntypedActorSpringFeatureTest extends FeatureSpec with ShouldMatchers {
feature("parse Spring application context") {
scenario("get a untyped actor") {
val context = new ClassPathXmlApplicationContext("/untyped-actor-config.xml")
val myactor = context.getBean("simple-untyped-actor").asInstanceOf[UntypedActorRef]
assert(myactor.getActorClassName() === "se.scalablesolutions.akka.spring.foo.PingActor")
myactor.start()
myactor.sendOneWay("Hello")
assert(myactor.actorRef.isDefinedAt("some string message"))
}
scenario("untyped-actor with timeout") {
val context = new ClassPathXmlApplicationContext("/untyped-actor-config.xml")
val myactor = context.getBean("simple-untyped-actor-long-timeout").asInstanceOf[UntypedActorRef]
assert(myactor.getActorClassName() === "se.scalablesolutions.akka.spring.foo.PingActor")
myactor.start()
myactor.sendOneWay("Hello")
assert(myactor.getTimeout() === 10000)
}
scenario("transactional untyped-actor") {
val context = new ClassPathXmlApplicationContext("/untyped-actor-config.xml")
val myactor = context.getBean("transactional-untyped-actor").asInstanceOf[UntypedActorRef]
assert(myactor.getActorClassName() === "se.scalablesolutions.akka.spring.foo.PingActor")
myactor.start()
myactor.sendOneWay("Hello")
assert(myactor.actorRef.isDefinedAt("some string message"))
}
scenario("get a remote typed-actor") {
RemoteNode.start
Thread.sleep(1000)
val context = new ClassPathXmlApplicationContext("/untyped-actor-config.xml")
val myactor = context.getBean("remote-untyped-actor").asInstanceOf[UntypedActorRef]
assert(myactor.getActorClassName() === "se.scalablesolutions.akka.spring.foo.PingActor")
myactor.start()
myactor.sendOneWay("Hello")
assert(myactor.actorRef.isDefinedAt("some string message"))
assert(myactor.getRemoteAddress().isDefined)
assert(myactor.getRemoteAddress().get.getHostName() === "localhost")
assert(myactor.getRemoteAddress().get.getPort() === 9999)
}
scenario("untyped-actor with custom dispatcher") {
val context = new ClassPathXmlApplicationContext("/untyped-actor-config.xml")
val myactor = context.getBean("untyped-actor-with-dispatcher").asInstanceOf[UntypedActorRef]
assert(myactor.getActorClassName() === "se.scalablesolutions.akka.spring.foo.PingActor")
myactor.start()
myactor.sendOneWay("Hello")
assert(myactor.getTimeout() === 1000)
assert(myactor.getDispatcher.isInstanceOf[ExecutorBasedEventDrivenWorkStealingDispatcher])
}
}
}