Added 'withRouter[TYPE]' to 'Props'.

Added docs (Scala and Java) and (code for the docs) for 'Props'.
Renamed UntypedActorTestBase to UntypedActorDocTestBase.

Signed-off-by: Jonas Bonér <jonas@jonasboner.com>
This commit is contained in:
Jonas Bonér 2011-12-14 14:05:44 +01:00
parent 66e7155ef1
commit 80600abc33
10 changed files with 178 additions and 83 deletions

View file

@ -62,7 +62,7 @@ class RoutingSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
"no router" must { "no router" must {
"be started when constructed" in { "be started when constructed" in {
val routedActor = system.actorOf(Props(new TestActor).withRouter(NoRouter)) val routedActor = system.actorOf(Props[TestActor].withRouter(NoRouter))
routedActor.isTerminated must be(false) routedActor.isTerminated must be(false)
} }
@ -90,7 +90,7 @@ class RoutingSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
"round robin router" must { "round robin router" must {
"be started when constructed" in { "be started when constructed" in {
val routedActor = system.actorOf(Props(new TestActor).withRouter(RoundRobinRouter(nrOfInstances = 1))) val routedActor = system.actorOf(Props[TestActor].withRouter(RoundRobinRouter(nrOfInstances = 1)))
routedActor.isTerminated must be(false) routedActor.isTerminated must be(false)
} }
@ -118,7 +118,7 @@ class RoutingSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
actors = actors :+ actor actors = actors :+ actor
} }
val routedActor = system.actorOf(Props(new TestActor).withRouter(RoundRobinRouter(targets = actors))) val routedActor = system.actorOf(Props[TestActor].withRouter(RoundRobinRouter(targets = actors)))
//send messages to the actor. //send messages to the actor.
for (i 0 until iterationCount) { for (i 0 until iterationCount) {
@ -156,7 +156,7 @@ class RoutingSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
} }
})) }))
val routedActor = system.actorOf(Props(new TestActor).withRouter(RoundRobinRouter(targets = List(actor1, actor2)))) val routedActor = system.actorOf(Props[TestActor].withRouter(RoundRobinRouter(targets = List(actor1, actor2))))
routedActor ! Broadcast(1) routedActor ! Broadcast(1)
routedActor ! Broadcast("end") routedActor ! Broadcast("end")
@ -171,7 +171,7 @@ class RoutingSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
"random router" must { "random router" must {
"be started when constructed" in { "be started when constructed" in {
val routedActor = system.actorOf(Props(new TestActor).withRouter(RandomRouter(nrOfInstances = 1))) val routedActor = system.actorOf(Props[TestActor].withRouter(RandomRouter(nrOfInstances = 1)))
routedActor.isTerminated must be(false) routedActor.isTerminated must be(false)
} }
@ -194,7 +194,7 @@ class RoutingSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
} }
})) }))
val routedActor = system.actorOf(Props(new TestActor).withRouter(RandomRouter(targets = List(actor1, actor2)))) val routedActor = system.actorOf(Props[TestActor].withRouter(RandomRouter(targets = List(actor1, actor2))))
routedActor ! Broadcast(1) routedActor ! Broadcast(1)
routedActor ! Broadcast("end") routedActor ! Broadcast("end")
@ -208,7 +208,7 @@ class RoutingSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
"broadcast router" must { "broadcast router" must {
"be started when constructed" in { "be started when constructed" in {
val routedActor = system.actorOf(Props(new TestActor).withRouter(BroadcastRouter(nrOfInstances = 1))) val routedActor = system.actorOf(Props[TestActor].withRouter(BroadcastRouter(nrOfInstances = 1)))
routedActor.isTerminated must be(false) routedActor.isTerminated must be(false)
} }
@ -231,7 +231,7 @@ class RoutingSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
} }
})) }))
val routedActor = system.actorOf(Props(new TestActor).withRouter(BroadcastRouter(targets = List(actor1, actor2)))) val routedActor = system.actorOf(Props[TestActor].withRouter(BroadcastRouter(targets = List(actor1, actor2))))
routedActor ! 1 routedActor ! 1
routedActor ! "end" routedActor ! "end"
@ -262,7 +262,7 @@ class RoutingSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
} }
})) }))
val routedActor = system.actorOf(Props(new TestActor).withRouter(BroadcastRouter(targets = List(actor1, actor2)))) val routedActor = system.actorOf(Props[TestActor].withRouter(BroadcastRouter(targets = List(actor1, actor2))))
routedActor ? 1 routedActor ? 1
routedActor ! "end" routedActor ! "end"
@ -276,7 +276,7 @@ class RoutingSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
"Scatter-gather router" must { "Scatter-gather router" must {
"be started when constructed" in { "be started when constructed" in {
val routedActor = system.actorOf(Props(new TestActor).withRouter(ScatterGatherFirstCompletedRouter(targets = List(newActor(0))))) val routedActor = system.actorOf(Props[TestActor].withRouter(ScatterGatherFirstCompletedRouter(targets = List(newActor(0)))))
routedActor.isTerminated must be(false) routedActor.isTerminated must be(false)
} }
@ -299,7 +299,7 @@ class RoutingSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
} }
})) }))
val routedActor = system.actorOf(Props(new TestActor).withRouter(ScatterGatherFirstCompletedRouter(targets = List(actor1, actor2)))) val routedActor = system.actorOf(Props[TestActor].withRouter(ScatterGatherFirstCompletedRouter(targets = List(actor1, actor2))))
routedActor ! Broadcast(1) routedActor ! Broadcast(1)
routedActor ! Broadcast("end") routedActor ! Broadcast("end")
@ -313,7 +313,7 @@ class RoutingSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
val shutdownLatch = new TestLatch(1) val shutdownLatch = new TestLatch(1)
val actor1 = newActor(1, Some(shutdownLatch)) val actor1 = newActor(1, Some(shutdownLatch))
val actor2 = newActor(22, Some(shutdownLatch)) val actor2 = newActor(22, Some(shutdownLatch))
val routedActor = system.actorOf(Props(new TestActor).withRouter(ScatterGatherFirstCompletedRouter(targets = List(actor1, actor2)))) val routedActor = system.actorOf(Props[TestActor].withRouter(ScatterGatherFirstCompletedRouter(targets = List(actor1, actor2))))
routedActor ! Broadcast(Stop(Some(1))) routedActor ! Broadcast(Stop(Some(1)))
shutdownLatch.await shutdownLatch.await

View file

@ -8,11 +8,13 @@ import akka.dispatch._
import akka.japi.Creator import akka.japi.Creator
import akka.util._ import akka.util._
import collection.immutable.Stack import collection.immutable.Stack
import akka.routing.{ NoRouter, RouterConfig } import akka.routing._
/** /**
* Factory for Props instances. * Factory for Props instances.
*
* Props is a ActorRef configuration object, that is thread safe and fully sharable. * Props is a ActorRef configuration object, that is thread safe and fully sharable.
*
* Used when creating new actors through; <code>ActorSystem.actorOf</code> and <code>ActorContext.actorOf</code>. * Used when creating new actors through; <code>ActorSystem.actorOf</code> and <code>ActorContext.actorOf</code>.
*/ */
object Props { object Props {
@ -47,6 +49,8 @@ object Props {
/** /**
* Returns a Props that has default values except for "creator" which will be a function that creates an instance * Returns a Props that has default values except for "creator" which will be a function that creates an instance
* of the supplied type using the default constructor. * of the supplied type using the default constructor.
*
* Scala API.
*/ */
def apply[T <: Actor: ClassManifest]: Props = def apply[T <: Actor: ClassManifest]: Props =
default.withCreator(implicitly[ClassManifest[T]].erasure.asInstanceOf[Class[_ <: Actor]].newInstance) default.withCreator(implicitly[ClassManifest[T]].erasure.asInstanceOf[Class[_ <: Actor]].newInstance)
@ -61,6 +65,8 @@ object Props {
/** /**
* Returns a Props that has default values except for "creator" which will be a function that creates an instance * Returns a Props that has default values except for "creator" which will be a function that creates an instance
* using the supplied thunk. * using the supplied thunk.
*
* Scala API.
*/ */
def apply(creator: Actor): Props = def apply(creator: Actor): Props =
default.withCreator(creator) default.withCreator(creator)
@ -87,7 +93,17 @@ object Props {
* {{{ * {{{
* val props = Props[MyActor] * val props = Props[MyActor]
* val props = Props(new MyActor) * val props = Props(new MyActor)
* val props = Props {
* creator = ..,
* dispatcher = ..,
* timeout = ..,
* faultHandler = ..,
* routerConfig = ..
* }
* val props = Props().withCreator(new MyActor)
* val props = Props[MyActor].withTimeout(timeout) * val props = Props[MyActor].withTimeout(timeout)
* val props = Props[MyActor].withRouter[RoundRobinRouter]
* val props = Props[MyActor].withRouter(new RoundRobinRouter(..))
* val props = Props[MyActor].withFaultHandler(OneForOneStrategy { * val props = Props[MyActor].withFaultHandler(OneForOneStrategy {
* case e: IllegalStateException Resume * case e: IllegalStateException Resume
* }) * })
@ -103,11 +119,13 @@ object Props {
* } * }
* }); * });
* Props props = new Props().withCreator(new UntypedActorFactory() { ... }); * Props props = new Props().withCreator(new UntypedActorFactory() { ... });
* Props props = new Props().withTimeout(timeout); * Props props = new Props(MyActor.class).withTimeout(timeout);
* Props props = new Props().withFaultHandler(new OneForOneStrategy(...)); * Props props = new Props(MyActor.class).withFaultHandler(new OneForOneStrategy(...));
* Props props = new Props(MyActor.class).withRouter(new RoundRobinRouter(..));
* }}} * }}}
*/ */
case class Props(creator: () Actor = Props.defaultCreator, case class Props(
creator: () Actor = Props.defaultCreator,
@transient dispatcher: MessageDispatcher = Props.defaultDispatcher, @transient dispatcher: MessageDispatcher = Props.defaultDispatcher,
timeout: Timeout = Props.defaultTimeout, timeout: Timeout = Props.defaultTimeout,
faultHandler: FaultHandlingStrategy = Props.defaultFaultHandler, faultHandler: FaultHandlingStrategy = Props.defaultFaultHandler,
@ -115,7 +133,6 @@ case class Props(creator: () ⇒ Actor = Props.defaultCreator,
/** /**
* No-args constructor that sets all the default values. * No-args constructor that sets all the default values.
* Java API.
*/ */
def this() = this( def this() = this(
creator = Props.defaultCreator, creator = Props.defaultCreator,
@ -144,43 +161,58 @@ case class Props(creator: () ⇒ Actor = Props.defaultCreator,
/** /**
* Returns a new Props with the specified creator set. * Returns a new Props with the specified creator set.
*
* Scala API. * Scala API.
*/ */
def withCreator(c: Actor) = copy(creator = () c) def withCreator(c: Actor) = copy(creator = () c)
/** /**
* Returns a new Props with the specified creator set. * Returns a new Props with the specified creator set.
*
* Java API. * Java API.
*/ */
def withCreator(c: Creator[Actor]) = copy(creator = () c.create) def withCreator(c: Creator[Actor]) = copy(creator = () c.create)
/** /**
* Returns a new Props with the specified creator set. * Returns a new Props with the specified creator set.
*
* Java API. * Java API.
*/ */
def withCreator(c: Class[_ <: Actor]) = copy(creator = () c.newInstance) def withCreator(c: Class[_ <: Actor]) = copy(creator = () c.newInstance)
/** /**
* Returns a new Props with the specified dispatcher set. * Returns a new Props with the specified dispatcher set.
* Java API.
*/ */
def withDispatcher(d: MessageDispatcher) = copy(dispatcher = d) def withDispatcher(d: MessageDispatcher) = copy(dispatcher = d)
/** /**
* Returns a new Props with the specified timeout set * Returns a new Props with the specified timeout set.
* Java API.
*/ */
def withTimeout(t: Timeout) = copy(timeout = t) def withTimeout(t: Timeout) = copy(timeout = t)
/** /**
* Returns a new Props with the specified faulthandler set. * Returns a new Props with the specified faulthandler set.
* Java API.
*/ */
def withFaultHandler(f: FaultHandlingStrategy) = copy(faultHandler = f) def withFaultHandler(f: FaultHandlingStrategy) = copy(faultHandler = f)
/** /**
* Returns a new Props with the specified router config set * Returns a new Props with the specified router config set.
* Java API
*/ */
def withRouter(r: RouterConfig) = copy(routerConfig = r) def withRouter(r: RouterConfig) = copy(routerConfig = r)
/**
* Returns a new Props with the specified router config set.
*
* Scala API.
*/
def withRouter[T <: RouterConfig: ClassManifest] = {
val routerConfig = implicitly[ClassManifest[T]].erasure.asInstanceOf[Class[_ <: RouterConfig]] match {
case RoundRobinRouterClass RoundRobinRouter()
case RandomRouterClass RandomRouter()
case BroadcastRouterClass BroadcastRouter()
case ScatterGatherRouterClass ScatterGatherFirstCompletedRouter()
case unknown throw new akka.config.ConfigurationException("Router not supported [" + unknown.getName + "]")
}
copy(routerConfig = routerConfig)
}
} }

View file

@ -8,4 +8,9 @@ package object routing {
type Route = PartialFunction[(akka.actor.ActorRef, Any), Iterable[Destination]] type Route = PartialFunction[(akka.actor.ActorRef, Any), Iterable[Destination]]
// To allow pattern matching on the class types
val RoundRobinRouterClass = classOf[RoundRobinRouter]
val RandomRouterClass = classOf[RandomRouter]
val BroadcastRouterClass = classOf[BroadcastRouter]
val ScatterGatherRouterClass = classOf[ScatterGatherFirstCompletedRouter]
} }

View file

@ -0,0 +1,5 @@
package akka.docs.actor
import org.scalatest.junit.JUnitSuite
class UntypedActorDocTest extends UntypedActorDocTestBase with JUnitSuite

View file

@ -1,5 +1,7 @@
package akka.docs.actor; package akka.docs.actor;
import akka.actor.Timeout;
//#imports //#imports
import akka.actor.ActorRef; import akka.actor.ActorRef;
import akka.actor.ActorSystem; import akka.actor.ActorSystem;
@ -33,7 +35,26 @@ import scala.Option;
import static org.junit.Assert.*; import static org.junit.Assert.*;
public class UntypedActorTestBase { public class UntypedActorDocTestBase {
@Test
public void createProps() {
//#creating-props-config
Props props1 = new Props();
Props props2 = new Props(MyUntypedActor.class);
Props props3 = new Props(new UntypedActorFactory() {
public UntypedActor create() {
return new MyUntypedActor();
}
});
Props props4 = props1.withCreator(new UntypedActorFactory() {
public UntypedActor create() {
return new MyUntypedActor();
}
});
Props props5 = props4.withTimeout(new Timeout(1000));
//#creating-props-config
}
@Test @Test
public void systemActorOf() { public void systemActorOf() {

View file

@ -1,5 +0,0 @@
package akka.docs.actor
import org.scalatest.junit.JUnitSuite
class UntypedActorTest extends UntypedActorTestBase with JUnitSuite

View file

@ -42,7 +42,7 @@ Here is an example:
Creating Actors with default constructor Creating Actors with default constructor
---------------------------------------- ----------------------------------------
.. includecode:: code/akka/docs/actor/UntypedActorTestBase.java .. includecode:: code/akka/docs/actor/UntypedActorDocTestBase.java
:include: imports,system-actorOf :include: imports,system-actorOf
The call to :meth:`actorOf` returns an instance of ``ActorRef``. This is a handle to The call to :meth:`actorOf` returns an instance of ``ActorRef``. This is a handle to
@ -85,17 +85,26 @@ which can lead to corrupt data.
Here is an example: Here is an example:
.. includecode:: code/akka/docs/actor/UntypedActorTestBase.java#creating-constructor .. includecode:: code/akka/docs/actor/UntypedActorDocTestBase.java#creating-constructor
This way of creating the Actor is also great for integrating with Dependency Injection (DI) frameworks like Guice or Spring. This way of creating the Actor is also great for integrating with Dependency Injection (DI) frameworks like Guice or Spring.
Props
-----
``Props`` is a configuration object to specify configuration options for the creation
of actors. Here are some examples on how to create a ``Props`` instance.
.. includecode:: code/akka/docs/actor/UntypedActorDocTestBase.java#creating-props-config
Creating Actors with Props Creating Actors with Props
-------------------------- --------------------------
``Props`` is a configuration object to specify additional things for the actor to Actors are created by passing in the ``Props`` object into the ``actorOf`` factory method.
be created, such as the ``MessageDispatcher``.
.. includecode:: code/akka/docs/actor/UntypedActorTestBase.java#creating-props .. includecode:: code/akka/docs/actor/UntypedActorDocTestBase.java#creating-props
UntypedActor API UntypedActor API
@ -119,7 +128,7 @@ In addition, it offers:
The remaining visible methods are user-overridable life-cycle hooks which are The remaining visible methods are user-overridable life-cycle hooks which are
described in the following: described in the following:
.. includecode:: code/akka/docs/actor/UntypedActorTestBase.java#lifecycle-callbacks .. includecode:: code/akka/docs/actor/UntypedActorDocTestBase.java#lifecycle-callbacks
The implementations shown above are the defaults provided by the :class:`UntypedActor` The implementations shown above are the defaults provided by the :class:`UntypedActor`
class. class.
@ -250,7 +259,7 @@ To complete the future with an exception you need send a Failure message to the
This is not done automatically when an actor throws an exception while processing a This is not done automatically when an actor throws an exception while processing a
message. message.
.. includecode:: code/akka/docs/actor/UntypedActorTestBase.java#reply-exception .. includecode:: code/akka/docs/actor/UntypedActorDocTestBase.java#reply-exception
If the actor does not complete the future, it will expire after the timeout period, If the actor does not complete the future, it will expire after the timeout period,
specified as parameter to the ``ask`` method. specified as parameter to the ``ask`` method.
@ -278,7 +287,7 @@ even if that entails waiting for it (but keep in mind that waiting inside an
actor is prone to dead-locks, e.g. if obtaining the result depends on actor is prone to dead-locks, e.g. if obtaining the result depends on
processing another message on this actor). processing another message on this actor).
.. includecode:: code/akka/docs/actor/UntypedActorTestBase.java .. includecode:: code/akka/docs/actor/UntypedActorDocTestBase.java
:include: import-future,using-ask :include: import-future,using-ask
Forward message Forward message
@ -381,7 +390,7 @@ If the ``PoisonPill`` was sent with ``ask``, the ``Future`` will be completed wi
Use it like this: Use it like this:
.. includecode:: code/akka/docs/actor/UntypedActorTestBase.java .. includecode:: code/akka/docs/actor/UntypedActorDocTestBase.java
:include: import-actors,poison-pill :include: import-actors,poison-pill
.. _UntypedActor.HotSwap: .. _UntypedActor.HotSwap:
@ -402,7 +411,7 @@ The hotswapped code is kept in a Stack which can be pushed and popped.
To hotswap the Actor using ``getContext().become``: To hotswap the Actor using ``getContext().become``:
.. includecode:: code/akka/docs/actor/UntypedActorTestBase.java .. includecode:: code/akka/docs/actor/UntypedActorDocTestBase.java
:include: import-procedure,hot-swap-actor :include: import-procedure,hot-swap-actor
The ``become`` method is useful for many different things, such as to implement The ``become`` method is useful for many different things, such as to implement
@ -432,7 +441,7 @@ through regular supervisor semantics.
Use it like this: Use it like this:
.. includecode:: code/akka/docs/actor/UntypedActorTestBase.java .. includecode:: code/akka/docs/actor/UntypedActorDocTestBase.java
:include: import-actors,kill :include: import-actors,kill
Actors and exceptions Actors and exceptions

View file

@ -95,11 +95,19 @@ Here is an example:
.. includecode:: code/ActorDocSpec.scala#creating-constructor .. includecode:: code/ActorDocSpec.scala#creating-constructor
Props
-----
``Props`` is a configuration object to specify configuration options for the creation
of actors. Here are some examples on how to create a ``Props`` instance.
.. includecode:: code/ActorDocSpec.scala#creating-props-config
Creating Actors with Props Creating Actors with Props
-------------------------- --------------------------
``Props`` is a configuration object to specify additional things for the actor to Actors are created by passing in the ``Props`` object into the ``actorOf`` factory method.
be created, such as the ``MessageDispatcher``.
.. includecode:: code/ActorDocSpec.scala#creating-props .. includecode:: code/ActorDocSpec.scala#creating-props

View file

@ -1,5 +1,7 @@
package akka.docs.actor package akka.docs.actor
import akka.actor.Timeout
//#imports1 //#imports1
import akka.actor.Actor import akka.actor.Actor
import akka.actor.Props import akka.actor.Props
@ -13,6 +15,7 @@ import akka.actor.ActorSystem
import org.scalatest.{ BeforeAndAfterAll, WordSpec } import org.scalatest.{ BeforeAndAfterAll, WordSpec }
import org.scalatest.matchers.MustMatchers import org.scalatest.matchers.MustMatchers
import akka.testkit._ import akka.testkit._
import akka.util._
import akka.util.duration._ import akka.util.duration._
//#my-actor //#my-actor
@ -185,6 +188,23 @@ class ActorDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) {
myActor.stop() myActor.stop()
} }
"creating a Props config" in {
val dispatcher = system.dispatcherFactory.lookup("my-dispatcher")
//#creating-props-config
import akka.actor.Props
val props1 = Props()
val props2 = Props[MyActor]
val props3 = Props(new MyActor)
val props4 = Props(
creator = { () new MyActor },
dispatcher = dispatcher,
timeout = Timeout(100))
val props5 = props1.withCreator(new MyActor)
val props6 = props5.withDispatcher(dispatcher)
val props7 = props6.withTimeout(Timeout(100))
//#creating-props-config
}
"creating actor with Props" in { "creating actor with Props" in {
//#creating-props //#creating-props
import akka.actor.Props import akka.actor.Props

View file

@ -50,7 +50,7 @@ object Pi extends App {
var start: Long = _ var start: Long = _
//#create-router //#create-router
val router = context.actorOf(Props(new Worker).withRouter(RoundRobinRouter(nrOfInstances = nrOfWorkers)), "pi") val router = context.actorOf(Props[Worker].withRouter(RoundRobinRouter(nrOfInstances = nrOfWorkers)), "pi")
//#create-router //#create-router
//#master-receive //#master-receive