Merge remote-tracking branch 'origin/wip-simplify-configuring-new-router-in-props-jboner'

Signed-off-by: Jonas Bonér <jonas@jonasboner.com>
This commit is contained in:
Jonas Bonér 2011-12-15 10:06:04 +01:00
commit b4f1978b37
8 changed files with 117 additions and 55 deletions

View file

@ -63,7 +63,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)
} }
@ -91,7 +91,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)
} }
@ -119,7 +119,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) {
@ -157,7 +157,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")
@ -172,7 +172,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)
} }
@ -195,7 +195,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")
@ -209,7 +209,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)
} }
@ -232,7 +232,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"
@ -263,7 +263,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"
@ -277,7 +277,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)
} }
@ -300,7 +300,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")
@ -314,7 +314,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,16 @@ 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].withFaultHandler(OneForOneStrategy { * val props = Props[MyActor].withFaultHandler(OneForOneStrategy {
* case e: IllegalStateException Resume * case e: IllegalStateException Resume
* }) * })
@ -103,11 +118,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 +132,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 +160,42 @@ 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)
} }

View file

@ -5,7 +5,5 @@
package akka package akka
package object routing { package object routing {
type Route = PartialFunction[(akka.actor.ActorRef, Any), Iterable[Destination]] type Route = PartialFunction[(akka.actor.ActorRef, Any), Iterable[Destination]]
} }

View file

@ -4,24 +4,21 @@ package akka.docs.actor;
import akka.actor.ActorRef; import akka.actor.ActorRef;
import akka.actor.ActorSystem; import akka.actor.ActorSystem;
import akka.actor.Props; import akka.actor.Props;
//#imports //#imports
//#import-future //#import-future
import akka.dispatch.Future; import akka.dispatch.Future;
import akka.dispatch.Await; import akka.dispatch.Await;
import akka.util.Duration; import akka.util.Duration;
import akka.util.Timeout;
//#import-future //#import-future
//#import-actors //#import-actors
import static akka.actor.Actors.*; import static akka.actor.Actors.*;
//#import-actors //#import-actors
//#import-procedure //#import-procedure
import akka.japi.Procedure; import akka.japi.Procedure;
//#import-procedure //#import-procedure
import akka.actor.Props; import akka.actor.Props;
@ -38,6 +35,25 @@ import static org.junit.Assert.*;
public class UntypedActorDocTestBase { 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() {
//#system-actorOf //#system-actorOf
@ -78,7 +94,8 @@ public class UntypedActorDocTestBase {
ActorSystem system = ActorSystem.create("MySystem"); ActorSystem system = ActorSystem.create("MySystem");
//#creating-props //#creating-props
MessageDispatcher dispatcher = system.dispatcherFactory().lookup("my-dispatcher"); MessageDispatcher dispatcher = system.dispatcherFactory().lookup("my-dispatcher");
ActorRef myActor = system.actorOf(new Props().withCreator(MyUntypedActor.class).withDispatcher(dispatcher), ActorRef myActor = system.actorOf(
new Props().withCreator(MyUntypedActor.class).withDispatcher(dispatcher),
"myactor"); "myactor");
//#creating-props //#creating-props
myActor.tell("test"); myActor.tell("test");

View file

@ -39,6 +39,23 @@ Here is an example:
.. includecode:: code/akka/docs/actor/MyUntypedActor.java#my-untyped-actor .. includecode:: code/akka/docs/actor/MyUntypedActor.java#my-untyped-actor
Props
-----
``Props`` is a configuration class to specify 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
--------------------------
Actors are created by passing in a ``Props`` instance into the ``actorOf`` factory method.
.. includecode:: code/akka/docs/actor/UntypedActorDocTestBase.java#creating-props
Creating Actors with default constructor Creating Actors with default constructor
---------------------------------------- ----------------------------------------
@ -76,26 +93,16 @@ add initialization code for the actor.
Creating Actors with non-default constructor Creating Actors with non-default constructor
-------------------------------------------- --------------------------------------------
If your UntypedActor has a constructor that takes parameters then you can't create it using 'actorOf(clazz)'. If your UntypedActor has a constructor that takes parameters then you can't create it using
Instead you can use a variant of ``actorOf`` that takes an instance of an 'UntypedActorFactory' 'actorOf(new Props(clazz))'. Then you can instead pass in 'new Props(new UntypedActorFactory() {..})'
in which you can create the Actor in any way you like. If you use this method then you to make sure that in which you can create the Actor in any way you like.
no one can get a reference to the actor instance. If they can get a reference it then they can
touch state directly in bypass the whole actor dispatching mechanism and create race conditions
which can lead to corrupt data.
Here is an example: Here is an example:
.. includecode:: code/akka/docs/actor/UntypedActorDocTestBase.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.
Creating Actors with Props
--------------------------
``Props`` is a configuration object to specify additional things for the actor to
be created, such as the ``MessageDispatcher``.
.. includecode:: code/akka/docs/actor/UntypedActorDocTestBase.java#creating-props
UntypedActor API UntypedActor API

View file

@ -95,11 +95,19 @@ Here is an example:
.. includecode:: code/akka/docs/actor/ActorDocSpec.scala#creating-constructor .. includecode:: code/akka/docs/actor/ActorDocSpec.scala#creating-constructor
Props
-----
``Props`` is a configuration class to specify 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 a ``Props`` instance into the ``actorOf`` factory method.
be created, such as the ``MessageDispatcher``.
.. includecode:: code/akka/docs/actor/ActorDocSpec.scala#creating-props .. includecode:: code/akka/docs/actor/ActorDocSpec.scala#creating-props

View file

@ -15,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
@ -187,6 +188,23 @@ class ActorDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) {
system.stop(myActor) system.stop(myActor)
} }
"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,8 +50,7 @@ object Pi extends App {
var start: Long = _ var start: Long = _
//#create-router //#create-router
val router = context.actorOf(Props(new Worker).withRouter( val router = context.actorOf(Props[Worker].withRouter(RoundRobinRouter(nrOfWorkers)), "pi")
RoundRobinRouter(nrOfInstances = nrOfWorkers)), "pi")
//#create-router //#create-router
//#master-receive //#master-receive