From 00e215a106383e14d61a2361bdcf80d9fdffb88c Mon Sep 17 00:00:00 2001 From: Michael Kober Date: Thu, 12 Aug 2010 15:54:46 +0200 Subject: [PATCH] closing ticket 377, 376 and 200 --- .../akka/spring/akka-0.10.xsd | 57 +++++++++++++ ...ctoryBean.scala => ActorFactoryBean.scala} | 79 +++++++++++++------ ...pedActorParser.scala => ActorParser.scala} | 6 +- ...Properties.scala => ActorProperties.scala} | 4 +- .../src/main/scala/AkkaNamespaceHandler.scala | 1 + .../scala/AkkaSpringConfigurationTags.scala | 6 +- .../DispatcherBeanDefinitionParser.scala | 2 +- .../src/main/scala/PropertyEntries.scala | 16 ++-- .../src/main/scala/PropertyEntry.scala | 22 +++--- .../SupervisionBeanDefinitionParser.scala | 28 +++++-- .../main/scala/SupervisionFactoryBean.scala | 52 ++++++++++-- .../TypedActorBeanDefinitionParser.scala | 8 +- .../UntypedActorBeanDefinitionParser.scala | 31 ++++++++ .../akka/spring/foo/PingActor.java | 33 ++++++++ .../akka/spring/foo/PongActor.java | 18 +++++ .../src/test/resources/dispatcher-config.xml | 2 +- .../src/test/resources/supervisor-config.xml | 17 ++++ .../test/resources/untyped-actor-config.xml | 37 +++++++++ ...nTest.scala => ActorFactoryBeanTest.scala} | 9 ++- .../scala/DispatcherSpringFeatureTest.scala | 4 +- .../SupervisionBeanDefinitionParserTest.scala | 4 +- .../scala/SupervisionFactoryBeanTest.scala | 8 +- .../scala/SupervisorSpringFeatureTest.scala | 64 ++------------- .../TypedActorBeanDefinitionParserTest.scala | 10 +-- .../scala/UntypedActorSpringFeatureTest.scala | 79 +++++++++++++++++++ 25 files changed, 462 insertions(+), 135 deletions(-) rename akka-spring/src/main/scala/{TypedActorFactoryBean.scala => ActorFactoryBean.scala} (77%) rename akka-spring/src/main/scala/{TypedActorParser.scala => ActorParser.scala} (92%) rename akka-spring/src/main/scala/{TypedActorProperties.scala => ActorProperties.scala} (93%) create mode 100644 akka-spring/src/main/scala/UntypedActorBeanDefinitionParser.scala create mode 100644 akka-spring/src/test/java/se/scalablesolutions/akka/spring/foo/PingActor.java create mode 100644 akka-spring/src/test/java/se/scalablesolutions/akka/spring/foo/PongActor.java create mode 100644 akka-spring/src/test/resources/untyped-actor-config.xml rename akka-spring/src/test/scala/{TypedActorFactoryBeanTest.scala => ActorFactoryBeanTest.scala} (92%) create mode 100644 akka-spring/src/test/scala/UntypedActorSpringFeatureTest.scala diff --git a/akka-spring/src/main/resources/se/scalablesolutions/akka/spring/akka-0.10.xsd b/akka-spring/src/main/resources/se/scalablesolutions/akka/spring/akka-0.10.xsd index fc83bea3e3..5bd18e3c44 100644 --- a/akka-spring/src/main/resources/se/scalablesolutions/akka/spring/akka-0.10.xsd +++ b/akka-spring/src/main/resources/se/scalablesolutions/akka/spring/akka-0.10.xsd @@ -161,6 +161,52 @@ + + + + + + + + + + + + + Name of the implementation class. + + + + + + + The default timeout for '!!' invocations. + + + + + + + Set this to true if messages should have REQUIRES_NEW semantics. + + + + + + + Defines the lifecycle, can be either 'permanent' or 'temporary'. + + + + + + + Supported scopes are 'singleton' and 'prototype'. + + + + + @@ -175,6 +221,13 @@ + + + + + + + @@ -208,6 +261,7 @@ + @@ -227,6 +281,9 @@ + + + diff --git a/akka-spring/src/main/scala/TypedActorFactoryBean.scala b/akka-spring/src/main/scala/ActorFactoryBean.scala similarity index 77% rename from akka-spring/src/main/scala/TypedActorFactoryBean.scala rename to akka-spring/src/main/scala/ActorFactoryBean.scala index 0cb70e5ae3..f2abe62879 100644 --- a/akka-spring/src/main/scala/TypedActorFactoryBean.scala +++ b/akka-spring/src/main/scala/ActorFactoryBean.scala @@ -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 Johan Rask * @author Martin Krasser * @author Jonas Bonér */ -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._ - createNewInstance(dispatcher) + if (dispatcher.dispatcherType != THREAD_BASED) { + createNewInstance(dispatcher) + } else { + println("### create thread based dispatcher") + createNewInstance(dispatcher) + } + } } diff --git a/akka-spring/src/main/scala/TypedActorParser.scala b/akka-spring/src/main/scala/ActorParser.scala similarity index 92% rename from akka-spring/src/main/scala/TypedActorParser.scala rename to akka-spring/src/main/scala/ActorParser.scala index 5f4d68f297..9858c1fad4 100644 --- a/akka-spring/src/main/scala/TypedActorParser.scala +++ b/akka-spring/src/main/scala/ActorParser.scala @@ -15,7 +15,7 @@ import se.scalablesolutions.akka.actor.IllegalActorStateException * @author Johan Rask * @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) diff --git a/akka-spring/src/main/scala/TypedActorProperties.scala b/akka-spring/src/main/scala/ActorProperties.scala similarity index 93% rename from akka-spring/src/main/scala/TypedActorProperties.scala rename to akka-spring/src/main/scala/ActorProperties.scala index 46c9cd35aa..15c7e61fe0 100644 --- a/akka-spring/src/main/scala/TypedActorProperties.scala +++ b/akka-spring/src/main/scala/ActorProperties.scala @@ -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) diff --git a/akka-spring/src/main/scala/AkkaNamespaceHandler.scala b/akka-spring/src/main/scala/AkkaNamespaceHandler.scala index 694daa90d4..a478b7b262 100644 --- a/akka-spring/src/main/scala/AkkaNamespaceHandler.scala +++ b/akka-spring/src/main/scala/AkkaNamespaceHandler.scala @@ -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); diff --git a/akka-spring/src/main/scala/AkkaSpringConfigurationTags.scala b/akka-spring/src/main/scala/AkkaSpringConfigurationTags.scala index e432edaf23..518727bd4c 100644 --- a/akka-spring/src/main/scala/AkkaSpringConfigurationTags.scala +++ b/akka-spring/src/main/scala/AkkaSpringConfigurationTags.scala @@ -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" diff --git a/akka-spring/src/main/scala/DispatcherBeanDefinitionParser.scala b/akka-spring/src/main/scala/DispatcherBeanDefinitionParser.scala index 9d4a16ff9b..90c56b0b5b 100644 --- a/akka-spring/src/main/scala/DispatcherBeanDefinitionParser.scala +++ b/akka-spring/src/main/scala/DispatcherBeanDefinitionParser.scala @@ -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) */ diff --git a/akka-spring/src/main/scala/PropertyEntries.scala b/akka-spring/src/main/scala/PropertyEntries.scala index aa2843064c..bf1898a805 100644 --- a/akka-spring/src/main/scala/PropertyEntries.scala +++ b/akka-spring/src/main/scala/PropertyEntries.scala @@ -1,3 +1,6 @@ +/** + * Copyright (C) 2009-2010 Scalable Solutions AB + */ package se.scalablesolutions.akka.spring import org.springframework.beans.factory.support.BeanDefinitionBuilder @@ -5,14 +8,13 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder import scala.collection.mutable._ /** -* Simple container for Properties -* @author Johan Rask -*/ + * Simple container for Properties + * @author Johan Rask + */ class PropertyEntries { + var entryList: ListBuffer[PropertyEntry] = ListBuffer[PropertyEntry]() - var entryList:ListBuffer[PropertyEntry] = ListBuffer[PropertyEntry]() - - def add(entry:PropertyEntry) = { - entryList.append(entry) + def add(entry: PropertyEntry) = { + entryList.append(entry) } } diff --git a/akka-spring/src/main/scala/PropertyEntry.scala b/akka-spring/src/main/scala/PropertyEntry.scala index 4d1aaa1a44..9fe6357fc0 100644 --- a/akka-spring/src/main/scala/PropertyEntry.scala +++ b/akka-spring/src/main/scala/PropertyEntry.scala @@ -1,17 +1,19 @@ +/** + * Copyright (C) 2009-2010 Scalable Solutions AB + */ package se.scalablesolutions.akka.spring /** -* Represents a property element -* @author Johan Rask -*/ + * Represents a property element + * @author Johan Rask + */ class PropertyEntry { - - var name:String = _ - var value:String = null - var ref:String = null + var name: String = _ + var value: String = null + var ref: String = null - override def toString(): String = { - format("name = %s,value = %s, ref = %s", name,value,ref) - } + override def toString(): String = { + format("name = %s,value = %s, ref = %s", name, value, ref) + } } diff --git a/akka-spring/src/main/scala/SupervisionBeanDefinitionParser.scala b/akka-spring/src/main/scala/SupervisionBeanDefinitionParser.scala index 5d430c9450..cc88e39f91 100644 --- a/akka-spring/src/main/scala/SupervisionBeanDefinitionParser.scala +++ b/akka-spring/src/main/scala/SupervisionBeanDefinitionParser.scala @@ -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) - parseTypedActorList(typedActorsElement, 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]] = { diff --git a/akka-spring/src/main/scala/SupervisionFactoryBean.scala b/akka-spring/src/main/scala/SupervisionFactoryBean.scala index 80a1f8a5fa..8ff62ba4af 100644 --- a/akka-spring/src/main/scala/SupervisionFactoryBean.scala +++ b/akka-spring/src/main/scala/SupervisionFactoryBean.scala @@ -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 + } } diff --git a/akka-spring/src/main/scala/TypedActorBeanDefinitionParser.scala b/akka-spring/src/main/scala/TypedActorBeanDefinitionParser.scala index ec987aacc0..e8e0cef7d4 100644 --- a/akka-spring/src/main/scala/TypedActorBeanDefinitionParser.scala +++ b/akka-spring/src/main/scala/TypedActorBeanDefinitionParser.scala @@ -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] } diff --git a/akka-spring/src/main/scala/UntypedActorBeanDefinitionParser.scala b/akka-spring/src/main/scala/UntypedActorBeanDefinitionParser.scala new file mode 100644 index 0000000000..752e18559f --- /dev/null +++ b/akka-spring/src/main/scala/UntypedActorBeanDefinitionParser.scala @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2009-2010 Scalable Solutions AB + */ +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] +} diff --git a/akka-spring/src/test/java/se/scalablesolutions/akka/spring/foo/PingActor.java b/akka-spring/src/test/java/se/scalablesolutions/akka/spring/foo/PingActor.java new file mode 100644 index 0000000000..c624d63ecd --- /dev/null +++ b/akka-spring/src/test/java/se/scalablesolutions/akka/spring/foo/PingActor.java @@ -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); + } + } + + +} diff --git a/akka-spring/src/test/java/se/scalablesolutions/akka/spring/foo/PongActor.java b/akka-spring/src/test/java/se/scalablesolutions/akka/spring/foo/PongActor.java new file mode 100644 index 0000000000..b67c0809fb --- /dev/null +++ b/akka-spring/src/test/java/se/scalablesolutions/akka/spring/foo/PongActor.java @@ -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); + } + } +} diff --git a/akka-spring/src/test/resources/dispatcher-config.xml b/akka-spring/src/test/resources/dispatcher-config.xml index 2d295f7614..18c27c778b 100644 --- a/akka-spring/src/test/resources/dispatcher-config.xml +++ b/akka-spring/src/test/resources/dispatcher-config.xml @@ -78,7 +78,7 @@ http://scalablesolutions.se/akka/akka-0.10.xsd"> implementation="se.scalablesolutions.akka.spring.foo.MyPojo" timeout="1000"> - --> + --> diff --git a/akka-spring/src/test/resources/supervisor-config.xml b/akka-spring/src/test/resources/supervisor-config.xml index ba57a68685..698581d903 100644 --- a/akka-spring/src/test/resources/supervisor-config.xml +++ b/akka-spring/src/test/resources/supervisor-config.xml @@ -33,6 +33,23 @@ http://scalablesolutions.se/akka/akka-0.10.xsd"> + + + + java.io.IOException + java.lang.NullPointerException + + + + + + + +