deprecate closure-taking Props factories, see #3081

- base Props on Deploy, Class and Seq[Any] (i.e. constructor args)
- remove deprecated Props usage from akka-docs sample code
- rewrite UntypedActorDocTestBase
- rewrite Java/Scala doc section on actor creation
- add migration guide entry
This commit is contained in:
Roland 2013-04-14 22:56:41 +02:00
parent 64f664a706
commit 28aad82b1a
80 changed files with 2268 additions and 1641 deletions

View file

@ -37,11 +37,43 @@ case class Message(s: String)
//#context-actorOf
class FirstActor extends Actor {
val myActor = context.actorOf(Props[MyActor], name = "myactor")
//#context-actorOf
val child = context.actorOf(Props[MyActor], name = "myChild")
//#plus-some-behavior
def receive = {
case x sender ! x
}
//#plus-some-behavior
}
//#context-actorOf
class ActorWithArgs(arg: String) extends Actor {
def receive = { case _ () }
}
class DemoActorWrapper extends Actor {
//#props-factory
object DemoActor {
/**
* Create Props for an actor of this type.
* @param name The name to be passed to this actors constructor.
* @return a Props for creating this actor, which can then be further configured
* (e.g. calling `.withDispatcher()` on it)
*/
def apply(name: String): Props = Props(classOf[DemoActor], name)
}
class DemoActor(name: String) extends Actor {
def receive = {
case x // some behavior
}
}
// ...
context.actorOf(DemoActor("hello"))
//#props-factory
def receive = Actor.emptyBehavior
}
class AnonymousActor extends Actor {
@ -61,11 +93,21 @@ class AnonymousActor extends Actor {
//#anonymous-actor
}
//#system-actorOf
object Main extends App {
val system = ActorSystem("MySystem")
val myActor = system.actorOf(Props[MyActor], name = "myactor")
//#system-actorOf
class Hook extends Actor {
var child: ActorRef = _
//#preStart
override def preStart() {
child = context.actorOf(Props[MyActor], "child")
}
//#preStart
def receive = Actor.emptyBehavior
//#postStop
override def postStop() {
//#clean-up-some-resources
()
//#clean-up-some-resources
}
//#postStop
}
class ReplyException extends Actor {
@ -142,22 +184,23 @@ case class MyMsg(subject: String)
class ActorDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) {
"import context" in {
//#import-context
class FirstActor extends Actor {
import context._
val myActor = actorOf(Props[MyActor], name = "myactor")
def receive = {
case x myActor ! x
new AnyRef {
//#import-context
class FirstActor extends Actor {
import context._
val myActor = actorOf(Props[MyActor], name = "myactor")
def receive = {
case x myActor ! x
}
}
//#import-context
val first = system.actorOf(Props(classOf[FirstActor], this), name = "first")
system.stop(first)
}
//#import-context
val first = system.actorOf(Props(new FirstActor), name = "first")
system.stop(first)
}
"creating actor with AkkaSpec.actorOf" in {
"creating actor with system.actorOf" in {
val myActor = system.actorOf(Props[MyActor])
// testing the actor
@ -183,44 +226,99 @@ class ActorDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) {
}
"creating actor with constructor" in {
class MyActor(arg: String) extends Actor {
def receive = { case _ () }
}
//#creating-constructor
// allows passing in arguments to the MyActor constructor
val myActor = system.actorOf(Props(new MyActor("...")), name = "myactor")
val myActor = system.actorOf(Props[MyActor], name = "myactor")
//#creating-constructor
system.stop(myActor)
}
"creating a Props config" in {
//#creating-props-config
//#creating-props
import akka.actor.Props
val props1 = Props.empty
val props2 = Props[MyActor]
val props3 = Props(new MyActor)
val props1 = Props[MyActor]
val props3 = Props(classOf[ActorWithArgs], "arg")
//#creating-props
//#creating-props-deprecated
// DEPRECATED: encourages to close over enclosing class
val props4 = Props(
creator = { () new MyActor },
dispatcher = "my-dispatcher")
// DEPRECATED: encourages to close over enclosing class
val props5 = props1.withCreator(new MyActor)
val props6 = props5.withDispatcher("my-dispatcher")
//#creating-props-config
// DEPRECATED: encourages to close over enclosing class
val props6 = Props(new MyActor)
// DEPRECATED due to duplicate functionality with Props.apply()
val props7 = props1.withCreator(classOf[MyActor])
//#creating-props-deprecated
}
"creating actor with Props" in {
//#creating-props
import akka.actor.Props
val myActor = system.actorOf(Props[MyActor].withDispatcher("my-dispatcher"),
name = "myactor2")
//#creating-props
//#system-actorOf
import akka.actor.ActorSystem
system.stop(myActor)
// ActorSystem is a heavy object: create only one per application
val system = ActorSystem("mySystem")
val myActor = system.actorOf(Props[MyActor].withDispatcher("my-dispatcher"), "myactor2")
//#system-actorOf
system.shutdown()
}
"creating actor with IndirectActorProducer" in {
class Echo(name: String) extends Actor {
def receive = {
case n: Int sender ! name
case message
val target = testActor
//#forward
target forward message
//#forward
}
}
val a: { def actorRef: ActorRef } = new AnyRef {
val applicationContext = this
//#creating-indirectly
import akka.actor.IndirectActorProducer
class DependencyInjector(applicationContext: AnyRef, beanName: String)
extends IndirectActorProducer {
override def actorClass = classOf[Actor]
override def produce =
//#obtain-fresh-Actor-instance-from-DI-framework
new Echo(beanName)
def this(beanName: String) = this("", beanName)
//#obtain-fresh-Actor-instance-from-DI-framework
}
val actorRef = system.actorOf(
Props(classOf[DependencyInjector], applicationContext, "hello"),
"helloBean")
//#creating-indirectly
}
val actorRef = a.actorRef
val message = 42
implicit val self = testActor
//#tell
actorRef ! message
//#tell
expectMsg("hello")
actorRef ! "huhu"
expectMsg("huhu")
}
"using implicit timeout" in {
val myActor = system.actorOf(Props(new FirstActor))
val myActor = system.actorOf(Props[FirstActor])
//#using-implicit-timeout
import scala.concurrent.duration._
import akka.util.Timeout
@ -233,7 +331,7 @@ class ActorDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) {
}
"using explicit timeout" in {
val myActor = system.actorOf(Props(new FirstActor))
val myActor = system.actorOf(Props[FirstActor])
//#using-explicit-timeout
import scala.concurrent.duration._
import akka.pattern.ask
@ -262,28 +360,28 @@ class ActorDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) {
//#receive-timeout
}
"using hot-swap" in {
//#hot-swap-actor
class HotSwapActor extends Actor {
import context._
def angry: Receive = {
case "foo" sender ! "I am already angry?"
case "bar" become(happy)
}
def happy: Receive = {
case "bar" sender ! "I am already happy :-)"
case "foo" become(angry)
}
def receive = {
case "foo" become(angry)
case "bar" become(happy)
}
//#hot-swap-actor
class HotSwapActor extends Actor {
import context._
def angry: Receive = {
case "foo" sender ! "I am already angry?"
case "bar" become(happy)
}
//#hot-swap-actor
val actor = system.actorOf(Props(new HotSwapActor), name = "hot")
def happy: Receive = {
case "bar" sender ! "I am already happy :-)"
case "foo" become(angry)
}
def receive = {
case "foo" become(angry)
case "bar" become(happy)
}
}
//#hot-swap-actor
"using hot-swap" in {
val actor = system.actorOf(Props(classOf[HotSwapActor], this), name = "hot")
}
"using Stash" in {
@ -307,55 +405,77 @@ class ActorDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) {
}
"using watch" in {
//#watch
import akka.actor.{ Actor, Props, Terminated }
new AnyRef {
//#watch
import akka.actor.{ Actor, Props, Terminated }
class WatchActor extends Actor {
val child = context.actorOf(Props.empty, "child")
context.watch(child) // <-- this is the only call needed for registration
var lastSender = system.deadLetters
class WatchActor extends Actor {
val child = context.actorOf(Props.empty, "child")
context.watch(child) // <-- this is the only call needed for registration
var lastSender = system.deadLetters
def receive = {
case "kill" context.stop(child); lastSender = sender
case Terminated(`child`) lastSender ! "finished"
def receive = {
case "kill"
context.stop(child); lastSender = sender
case Terminated(`child`) lastSender ! "finished"
}
}
//#watch
val a = system.actorOf(Props(classOf[WatchActor], this))
implicit val sender = testActor
a ! "kill"
expectMsg("finished")
}
//#watch
val a = system.actorOf(Props(new WatchActor))
implicit val sender = testActor
a ! "kill"
expectMsg("finished")
}
"demonstrate ActorSelection" in {
val context = system
//#selection-local
// will look up this absolute path
context.actorSelection("/user/serviceA/aggregator")
// will look up sibling beneath same supervisor
context.actorSelection("../joe")
//#selection-local
//#selection-wildcard
// will look all children to serviceB with names starting with worker
context.actorSelection("/user/serviceB/worker*")
// will look up all siblings beneath same supervisor
context.actorSelection("../*")
//#selection-wildcard
//#selection-remote
context.actorSelection("akka.tcp://app@otherhost:1234/user/serviceB")
//#selection-remote
}
"using Identify" in {
//#identify
import akka.actor.{ Actor, Props, Identify, ActorIdentity, Terminated }
new AnyRef {
//#identify
import akka.actor.{ Actor, Props, Identify, ActorIdentity, Terminated }
class Follower extends Actor {
val identifyId = 1
context.actorSelection("/user/another") ! Identify(identifyId)
class Follower extends Actor {
val identifyId = 1
context.actorSelection("/user/another") ! Identify(identifyId)
def receive = {
case ActorIdentity(`identifyId`, Some(ref))
context.watch(ref)
context.become(active(ref))
case ActorIdentity(`identifyId`, None) context.stop(self)
def receive = {
case ActorIdentity(`identifyId`, Some(ref))
context.watch(ref)
context.become(active(ref))
case ActorIdentity(`identifyId`, None) context.stop(self)
}
def active(another: ActorRef): Actor.Receive = {
case Terminated(`another`) context.stop(self)
}
}
//#identify
def active(another: ActorRef): Actor.Receive = {
case Terminated(`another`) context.stop(self)
}
val a = system.actorOf(Props.empty)
val b = system.actorOf(Props(classOf[Follower], this))
watch(b)
system.stop(a)
expectMsgType[akka.actor.Terminated].actor must be === b
}
//#identify
val a = system.actorOf(Props(new Actor {
def receive = Actor.emptyBehavior
}))
val b = system.actorOf(Props(new Follower))
watch(b)
system.stop(a)
expectMsgType[akka.actor.Terminated].actor must be === b
}
"using pattern gracefulStop" in {
@ -397,20 +517,22 @@ class ActorDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) {
//#ask-pipeTo
}
"replying with own or other sender" in {
val actor = system.actorOf(Props(new Actor {
def receive = {
case ref: ActorRef
//#reply-with-sender
sender.tell("reply", context.parent) // replies will go back to parent
sender.!("reply")(context.parent) // alternative syntax (beware of the parens!)
class Replier extends Actor {
def receive = {
case ref: ActorRef
//#reply-with-sender
case x
//#reply-without-sender
sender ! x // replies will go to this actor
sender.tell("reply", context.parent) // replies will go back to parent
sender.!("reply")(context.parent) // alternative syntax (beware of the parens!)
//#reply-with-sender
case x
//#reply-without-sender
}
}))
sender ! x // replies will go to this actor
//#reply-without-sender
}
}
"replying with own or other sender" in {
val actor = system.actorOf(Props(classOf[Replier], this))
implicit val me = testActor
actor ! 42
expectMsg(42)
@ -430,51 +552,51 @@ class ActorDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) {
})
}
"using ComposableActor" in {
//#receive-orElse2
class PartialFunctionBuilder[A, B] {
import scala.collection.immutable.Vector
//#receive-orElse2
class PartialFunctionBuilder[A, B] {
import scala.collection.immutable.Vector
// Abbreviate to make code fit
type PF = PartialFunction[A, B]
// Abbreviate to make code fit
type PF = PartialFunction[A, B]
private var pfsOption: Option[Vector[PF]] = Some(Vector.empty)
private var pfsOption: Option[Vector[PF]] = Some(Vector.empty)
private def mapPfs[C](f: Vector[PF] (Option[Vector[PF]], C)): C = {
pfsOption.fold(throw new IllegalStateException("Already built"))(f) match {
case (newPfsOption, result) {
pfsOption = newPfsOption
result
}
private def mapPfs[C](f: Vector[PF] (Option[Vector[PF]], C)): C = {
pfsOption.fold(throw new IllegalStateException("Already built"))(f) match {
case (newPfsOption, result) {
pfsOption = newPfsOption
result
}
}
def +=(pf: PF): Unit =
mapPfs { case pfs (Some(pfs :+ pf), ()) }
def result(): PF =
mapPfs { case pfs (None, pfs.foldLeft[PF](Map.empty) { _ orElse _ }) }
}
trait ComposableActor extends Actor {
protected lazy val receiveBuilder = new PartialFunctionBuilder[Any, Unit]
final def receive = receiveBuilder.result()
}
def +=(pf: PF): Unit =
mapPfs { case pfs (Some(pfs :+ pf), ()) }
trait TheirComposableActor extends ComposableActor {
receiveBuilder += {
case "foo" sender ! "foo received"
}
}
def result(): PF =
mapPfs { case pfs (None, pfs.foldLeft[PF](Map.empty) { _ orElse _ }) }
}
class MyComposableActor extends TheirComposableActor {
receiveBuilder += {
case "bar" sender ! "bar received"
}
}
//#receive-orElse2
trait ComposableActor extends Actor {
protected lazy val receiveBuilder = new PartialFunctionBuilder[Any, Unit]
final def receive = receiveBuilder.result()
}
val composed = system.actorOf(Props(new MyComposableActor))
trait TheirComposableActor extends ComposableActor {
receiveBuilder += {
case "foo" sender ! "foo received"
}
}
class MyComposableActor extends TheirComposableActor {
receiveBuilder += {
case "bar" sender ! "bar received"
}
}
//#receive-orElse2
"using ComposableActor" in {
val composed = system.actorOf(Props(classOf[MyComposableActor], this))
implicit val me = testActor
composed ! "foo"
expectMsg("foo received")